diff --git a/doc/contributions.txt b/doc/contributions.txt
index d02c88ba47fcea09f80fb11a389b338f76dbdc48..af8b259c7492a1796e2fa263ae632f9f81a0383f 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -238,6 +238,7 @@ Ansariel Hiller
 	SL-15227
 	SL-15398
 	SL-18432
+	SL-19140
 	SL-4126
 Aralara Rajal
 Arare Chantilly
@@ -895,6 +896,7 @@ Kitty Barnett
 	STORM-2149
 	MAINT-7581
 	MAINT-7081
+    SL-18988
 Kolor Fall
 Komiko Okamoto
 Korvel Noh
diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt
index 8af61ebf8726ab7e7ecf734eb351cbf4d47e8491..631ac77d2956c02c06f096598f725b23cf45e00e 100644
--- a/indra/llappearance/CMakeLists.txt
+++ b/indra/llappearance/CMakeLists.txt
@@ -21,7 +21,6 @@ set(llappearance_SOURCE_FILES
     lltexglobalcolor.cpp
     lltexlayer.cpp
     lltexlayerparams.cpp
-    lltexturemanagerbridge.cpp
     llwearable.cpp
     llwearabledata.cpp
     llwearabletype.cpp
@@ -44,7 +43,6 @@ set(llappearance_HEADER_FILES
     lltexglobalcolor.h
     lltexlayer.h
     lltexlayerparams.h
-    lltexturemanagerbridge.h
     llwearable.h
     llwearabledata.h
     llwearabletype.h
diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp
index 6017ab4103137891b05b1c8a5b416bb8dfe22dc6..f6170bed4164a1ce5049e91c8233d6bd626f2af5 100644
--- a/indra/llcommon/llcallbacklist.cpp
+++ b/indra/llcommon/llcallbacklist.cpp
@@ -45,7 +45,7 @@ void LLCallbackList::addFunction( callback_t func, void *data)
 
 	// only add one callback per func/data pair
 	//
-	if (containsFunction(func))
+	if (containsFunction(func, data))
 	{
 		return;
 	}
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index 05a80d456f78afb93c188f97bf8677c16cbd435e..cd8fabea053a4f076ad1115fa90584a464a440aa 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -40,9 +40,12 @@
 ///----------------------------------------------------------------------------
 /// Exported functions
 ///----------------------------------------------------------------------------
+// FIXME D567 - what's the point of these, especially if we don't even use them consistently?
 static const std::string INV_ITEM_ID_LABEL("item_id");
 static const std::string INV_FOLDER_ID_LABEL("cat_id");
 static const std::string INV_PARENT_ID_LABEL("parent_id");
+static const std::string INV_THUMBNAIL_LABEL("thumbnail");
+static const std::string INV_THUMBNAIL_ID_LABEL("thumbnail_id");
 static const std::string INV_ASSET_TYPE_LABEL("type");
 static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type");
 static const std::string INV_INVENTORY_TYPE_LABEL("inv_type");
@@ -95,6 +98,7 @@ void LLInventoryObject::copyObject(const LLInventoryObject* other)
 	mParentUUID = other->mParentUUID;
 	mType = other->mType;
 	mName = other->mName;
+	mThumbnailUUID = other->mThumbnailUUID;
 }
 
 const LLUUID& LLInventoryObject::getUUID() const
@@ -107,6 +111,11 @@ const LLUUID& LLInventoryObject::getParentUUID() const
 	return mParentUUID;
 }
 
+const LLUUID& LLInventoryObject::getThumbnailUUID() const
+{
+	return mThumbnailUUID;
+}
+
 const std::string& LLInventoryObject::getName() const
 {
 	return mName;
@@ -156,6 +165,11 @@ void LLInventoryObject::setParent(const LLUUID& new_parent)
 	mParentUUID = new_parent;
 }
 
+void LLInventoryObject::setThumbnailUUID(const LLUUID& thumbnail_uuid)
+{
+	mThumbnailUUID = thumbnail_uuid;
+}
+
 void LLInventoryObject::setType(LLAssetType::EType type)
 {
 	mType = type;
@@ -197,6 +211,26 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream)
 		{
 			mType = LLAssetType::lookup(valuestr);
 		}
+        else if (0 == strcmp("metadata", keyword))
+        {
+            LLSD metadata(valuestr);
+            if (metadata.has("thumbnail"))
+            {
+                const LLSD& thumbnail = metadata["thumbnail"];
+                if (thumbnail.has("asset_id"))
+                {
+                    setThumbnailUUID(thumbnail["asset_id"].asUUID());
+                }
+                else
+                {
+                    setThumbnailUUID(LLUUID::null);
+                }
+            }
+            else
+            {
+                setThumbnailUUID(LLUUID::null);
+            }
+        }
 		else if(0 == strcmp("name", keyword))
 		{
 			//strcpy(valuestr, buffer + strlen(keyword) + 3);
@@ -328,6 +362,7 @@ void LLInventoryItem::copyItem(const LLInventoryItem* other)
 	copyObject(other);
 	mPermissions = other->mPermissions;
 	mAssetUUID = other->mAssetUUID;
+    mThumbnailUUID = other->mThumbnailUUID;
 	mDescription = other->mDescription;
 	mSaleInfo = other->mSaleInfo;
 	mInventoryType = other->mInventoryType;
@@ -392,6 +427,7 @@ U32 LLInventoryItem::getCRC32() const
 	//LL_DEBUGS() << "8 crc: " << std::hex << crc << std::dec << LL_ENDL;
 	crc += (U32)mCreationDate;
 	//LL_DEBUGS() << "9 crc: " << std::hex << crc << std::dec << LL_ENDL;
+    crc += mThumbnailUUID.getCRC32();
 	return crc;
 }
 
@@ -647,6 +683,26 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream)
 		{
 			mType = LLAssetType::lookup(valuestr);
 		}
+        else if (0 == strcmp("metadata", keyword))
+        {
+            LLSD metadata(valuestr);
+            if (metadata.has("thumbnail"))
+            {
+                const LLSD& thumbnail = metadata["thumbnail"];
+                if (thumbnail.has("asset_id"))
+                {
+                    setThumbnailUUID(thumbnail["asset_id"].asUUID());
+                }
+                else
+                {
+                    setThumbnailUUID(LLUUID::null);
+                }
+            }
+            else
+            {
+                setThumbnailUUID(LLUUID::null);
+            }
+        }
 		else if(0 == strcmp("inv_type", keyword))
 		{
 			mInventoryType = LLInventoryType::lookup(std::string(valuestr));
@@ -736,6 +792,13 @@ BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL inclu
 	output_stream << "\t\tparent_id\t" << uuid_str << "\n";
 	mPermissions.exportLegacyStream(output_stream);
 
+    if (mThumbnailUUID.notNull())
+    {
+        LLSD metadata;
+        metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID);
+        output_stream << "\t\tmetadata\t" << metadata << "|\n";
+    }
+
 	// Check for permissions to see the asset id, and if so write it
 	// out as an asset id. Otherwise, apply our cheesy encryption.
 	if(include_asset_key)
@@ -789,6 +852,11 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const
 	sd[INV_PARENT_ID_LABEL] = mParentUUID;
 	sd[INV_PERMISSIONS_LABEL] = ll_create_sd_from_permissions(mPermissions);
 
+    if (mThumbnailUUID.notNull())
+    {
+        sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
+    }
+
 	U32 mask = mPermissions.getMaskBase();
 	if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
 		|| (mAssetUUID.isNull()))
@@ -840,6 +908,35 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
 	{
 		mParentUUID = sd[w];
 	}
+    mThumbnailUUID.setNull();
+    w = INV_THUMBNAIL_LABEL;
+    if (sd.has(w))
+    {
+        const LLSD &thumbnail_map = sd[w];
+        w = INV_ASSET_ID_LABEL;
+        if (thumbnail_map.has(w))
+        {
+            mThumbnailUUID = thumbnail_map[w];
+        }
+        /* Example:
+            <key> asset_id </key>
+            <uuid> acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7 </uuid>
+            <key> perms </key>
+            <integer> 8 </integer>
+            <key>service</key>
+            <integer> 3 </integer>
+            <key>version</key>
+            <integer> 1 </key>
+        */
+    }
+    else
+    {
+        w = INV_THUMBNAIL_ID_LABEL;
+        if (sd.has(w))
+        {
+            mThumbnailUUID = sd[w].asUUID();
+        }
+    }
 	w = INV_PERMISSIONS_LABEL;
 	if (sd.has(w))
 	{
@@ -964,7 +1061,6 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
 
 }
 
-
 ///----------------------------------------------------------------------------
 /// Class LLInventoryCategory
 ///----------------------------------------------------------------------------
@@ -1010,11 +1106,32 @@ void LLInventoryCategory::setPreferredType(LLFolderType::EType type)
 LLSD LLInventoryCategory::asLLSD() const
 {
     LLSD sd = LLSD();
-    sd["item_id"] = mUUID;
-    sd["parent_id"] = mParentUUID;
+    sd[INV_ITEM_ID_LABEL]   = mUUID;
+    sd[INV_PARENT_ID_LABEL] = mParentUUID;
     S8 type = static_cast<S8>(mPreferredType);
-    sd["type"]      = type;
-    sd["name"] = mName;
+    sd[INV_ASSET_TYPE_LABEL] = type;
+    sd[INV_NAME_LABEL] = mName;
+
+    if (mThumbnailUUID.notNull())
+    {
+        sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
+    }
+
+    return sd;
+}
+
+LLSD LLInventoryCategory::asAISCreateCatLLSD() const
+{
+    LLSD sd                 = LLSD();
+    sd[INV_FOLDER_ID_LABEL_WS]  = mUUID;
+    sd[INV_PARENT_ID_LABEL] = mParentUUID;
+    S8 type                 = static_cast<S8>(mPreferredType);
+    sd[INV_ASSET_TYPE_LABEL_WS] = type;
+    sd[INV_NAME_LABEL] = mName;
+    if (mThumbnailUUID.notNull())
+    {
+        sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
+    }
 
     return sd;
 }
@@ -1048,6 +1165,25 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd)
     {
         mParentUUID = sd[w];
     }
+    mThumbnailUUID.setNull();
+    w = INV_THUMBNAIL_LABEL;
+    if (sd.has(w))
+    {
+        const LLSD &thumbnail_map = sd[w];
+        w = INV_ASSET_ID_LABEL;
+        if (thumbnail_map.has(w))
+        {
+            mThumbnailUUID = thumbnail_map[w];
+        }
+    }
+    else
+    {
+        w = INV_THUMBNAIL_ID_LABEL;
+        if (sd.has(w))
+        {
+            mThumbnailUUID = sd[w];
+        }
+    }
     w = INV_ASSET_TYPE_LABEL;
     if (sd.has(w))
     {
@@ -1139,6 +1275,26 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream)
 			LLStringUtil::replaceNonstandardASCII(mName, ' ');
 			LLStringUtil::replaceChar(mName, '|', ' ');
 		}
+        else if (0 == strcmp("metadata", keyword))
+        {
+            LLSD metadata(valuestr);
+            if (metadata.has("thumbnail"))
+            {
+                const LLSD& thumbnail = metadata["thumbnail"];
+                if (thumbnail.has("asset_id"))
+                {
+                    setThumbnailUUID(thumbnail["asset_id"].asUUID());
+                }
+                else
+                {
+                    setThumbnailUUID(LLUUID::null);
+                }
+            }
+            else
+            {
+                setThumbnailUUID(LLUUID::null);
+            }
+        }
 		else
 		{
 			LL_WARNS() << "unknown keyword '" << keyword
@@ -1159,6 +1315,12 @@ BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL)
 	output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
 	output_stream << "\t\tpref_type\t" << LLFolderType::lookup(mPreferredType) << "\n";
 	output_stream << "\t\tname\t" << mName.c_str() << "|\n";
+    if (mThumbnailUUID.notNull())
+    {
+        LLSD metadata;
+        metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID);
+        output_stream << "\t\tmetadata\t" << metadata << "|\n";
+    }
 	output_stream << "\t}\n";
 	return TRUE;
 }
@@ -1172,6 +1334,11 @@ LLSD LLInventoryCategory::exportLLSD() const
 	cat_data[INV_PREFERRED_TYPE_LABEL] = LLFolderType::lookup(mPreferredType);
 	cat_data[INV_NAME_LABEL] = mName;
 
+    if (mThumbnailUUID.notNull())
+    {
+        cat_data[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
+    }
+
 	return cat_data;
 }
 
@@ -1193,6 +1360,16 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data)
 	{
 		setPreferredType(LLFolderType::lookup(cat_data[INV_PREFERRED_TYPE_LABEL].asString()));
 	}
+    if (cat_data.has(INV_THUMBNAIL_LABEL))
+    {
+        LLUUID thumbnail_uuid;
+        const LLSD &thumbnail_data = cat_data[INV_THUMBNAIL_LABEL];
+        if (thumbnail_data.has(INV_ASSET_ID_LABEL))
+        {
+            thumbnail_uuid = thumbnail_data[INV_ASSET_ID_LABEL].asUUID();
+        }
+        setThumbnailUUID(thumbnail_uuid);
+    }
 	if (cat_data.has(INV_NAME_LABEL))
 	{
 		mName = cat_data[INV_NAME_LABEL].asString();
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
index 6392ca3ed8a6eab543eb33e011ef58083da67aa9..848ed588b31216e3a9307a6dba7b06c3be19b212 100644
--- a/indra/llinventory/llinventory.h
+++ b/indra/llinventory/llinventory.h
@@ -70,6 +70,7 @@ class LLInventoryObject : public LLRefCount
 	virtual const LLUUID& getUUID() const; // inventoryID that this item points to
 	virtual const LLUUID& getLinkedUUID() const; // inventoryID that this item points to, else this item's inventoryID
 	const LLUUID& getParentUUID() const;
+	virtual const LLUUID& getThumbnailUUID() const;
 	virtual const std::string& getName() const;
 	virtual LLAssetType::EType getType() const;
 	LLAssetType::EType getActualType() const; // bypasses indirection for linked items
@@ -84,6 +85,7 @@ class LLInventoryObject : public LLRefCount
 	void setUUID(const LLUUID& new_uuid);
 	virtual void rename(const std::string& new_name);
 	void setParent(const LLUUID& new_parent);
+	virtual void setThumbnailUUID(const LLUUID& thumbnail_uuid);
 	void setType(LLAssetType::EType type);
 	virtual void setCreationDate(time_t creation_date_utc); // only stored for items
 
@@ -108,6 +110,7 @@ class LLInventoryObject : public LLRefCount
 protected:
 	LLUUID mUUID;
 	LLUUID mParentUUID; // Parent category.  Root categories have LLUUID::NULL.
+	LLUUID mThumbnailUUID;
 	LLAssetType::EType mType;
 	std::string mName;
 	time_t mCreationDate; // seconds from 1/1/1970, UTC
@@ -250,6 +253,7 @@ class LLInventoryCategory : public LLInventoryObject
 	LLFolderType::EType getPreferredType() const;
 	void setPreferredType(LLFolderType::EType type);
 	LLSD asLLSD() const;
+    LLSD asAISCreateCatLLSD() const;
 	bool fromLLSD(const LLSD& sd);
 	bool isPreferredTypeRoot() const;
 
diff --git a/indra/llinventory/tests/inventorymisc_test.cpp b/indra/llinventory/tests/inventorymisc_test.cpp
index 6f73f73894fff6ee26c3964044cc9bb4b216b2d1..c7730be7b2fecbe390f0891c120395c31c86567e 100644
--- a/indra/llinventory/tests/inventorymisc_test.cpp
+++ b/indra/llinventory/tests/inventorymisc_test.cpp
@@ -401,15 +401,7 @@ namespace tut
 		// Deleted LLInventoryItem::exportFileXML() and LLInventoryItem::importXML()
 		// because I can't find any non-test code references to it. 2009-05-04 JC
 	}
-		
-	template<> template<>
-	void inventory_object::test<10>()
-	{
-		// Deleted LLInventoryItem::packBinaryBucket() and LLInventoryItem::unpackBinaryBucket()
-		// because I can't find any non-test code references to it.
-	
-	}
-	
+
 	template<> template<>
 	void inventory_object::test<11>()
 	{
diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp
index c544678040182109bb1f9acd97bec18ef73d0e0b..074f0f8726a45ddc6fad7111dd4251479ed774f0 100644
--- a/indra/llmessage/llcoproceduremanager.cpp
+++ b/indra/llmessage/llcoproceduremanager.cpp
@@ -354,7 +354,26 @@ LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoproced
 {
     LLUUID id(LLUUID::generateNewID());
 
-    LL_INFOS("CoProcMgr") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName << "\" at " << mPending << LL_ENDL;
+    if (mPoolName == "AIS")
+    {
+        // Fetch is going to be spammy.
+        LL_DEBUGS("CoProcMgr", "Inventory") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName
+                                   << "\" at "
+                              << mPending << LL_ENDL;
+
+        if (mPending >= (LLCoprocedureManager::DEFAULT_QUEUE_SIZE - 1))
+        {
+            // If it's all used up (not supposed to happen,
+            // fetched should cap it), we are going to crash
+            LL_WARNS("CoProcMgr", "Inventory") << "About to run out of queue space for Coprocedure(" << name
+                                               << ") enqueuing with id=" << id.asString() << " Already pending:" << mPending << LL_ENDL;
+        }
+    }
+    else
+    {
+        LL_INFOS("CoProcMgr") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName << "\" at "
+                              << mPending << LL_ENDL;
+    }
     auto pushed = mPendingCoprocs->try_push(std::make_shared<QueuedCoproc>(name, id, proc));
     if (pushed == boost::fibers::channel_op_status::success)
     {
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index d9de6f1253b0f35b41063c61b6011becc9438d4d..04e526bc18e32ea4fc345720141625a5677e357f 100644
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -3474,6 +3474,7 @@ typedef std::map<const char*, LLMessageBuilder*> BuilderMap;
 
 void LLMessageSystem::newMessageFast(const char *name)
 {
+	//LL_DEBUGS("Messaging") << "creating new message: " << name << LL_ENDL;
 	LLMessageConfig::Flavor message_flavor =
 		LLMessageConfig::getMessageFlavor(name);
 	LLMessageConfig::Flavor server_flavor =
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt
index f47a0127da8cc26bdc254d30957a5a34ee9b88e2..d2949b284cd66c25a00e4692f324942f83e7d063 100644
--- a/indra/llrender/CMakeLists.txt
+++ b/indra/llrender/CMakeLists.txt
@@ -28,6 +28,7 @@ set(llrender_SOURCE_FILES
     llrendertarget.cpp
     llshadermgr.cpp
     lltexture.cpp
+    lltexturemanagerbridge.cpp
     lluiimage.cpp
     llvertexbuffer.cpp
     llglcommonfunc.cpp
@@ -55,6 +56,7 @@ set(llrender_HEADER_FILES
     llrendersphere.h
     llshadermgr.h
     lltexture.h
+    lltexturemanagerbridge.h
     lluiimage.h
     lluiimage.inl
     llvertexbuffer.h
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index d7e9ed10dd0e56f7eaa82541239799e05bbfe4bf..fe360f88135936580030a91770a4a531b7ef5134 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -1024,6 +1024,20 @@ LLFontGL* LLFontGL::getFontSansSerifSmall()
 	return fontp;
 }
 
+//static
+LLFontGL* LLFontGL::getFontSansSerifSmallBold()
+{
+    static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",BOLD));
+    return fontp;
+}
+
+//static
+LLFontGL* LLFontGL::getFontSansSerifSmallItalic()
+{
+    static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",ITALIC));
+    return fontp;
+}
+
 //static
 LLFontGL* LLFontGL::getFontSansSerif()
 {
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index 7d815bf9b56510b891838dd6fe1c6e90236c1d31..2fed29ff3daf7f1b5508169023069e1aad38406b 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -189,6 +189,8 @@ class LLFontGL
 		
 	static LLFontGL* getFontMonospace();
 	static LLFontGL* getFontSansSerifSmall();
+    static LLFontGL* getFontSansSerifSmallBold();
+    static LLFontGL* getFontSansSerifSmallItalic();
 	static LLFontGL* getFontSansSerif();
 	static LLFontGL* getFontSansSerifBig();
 	static LLFontGL* getFontSansSerifHuge();
diff --git a/indra/llappearance/lltexturemanagerbridge.cpp b/indra/llrender/lltexturemanagerbridge.cpp
similarity index 100%
rename from indra/llappearance/lltexturemanagerbridge.cpp
rename to indra/llrender/lltexturemanagerbridge.cpp
diff --git a/indra/llappearance/lltexturemanagerbridge.h b/indra/llrender/lltexturemanagerbridge.h
similarity index 97%
rename from indra/llappearance/lltexturemanagerbridge.h
rename to indra/llrender/lltexturemanagerbridge.h
index db55e9e34e0600dac44f89b4534a026dcfb2d535..a83c8625d50a476b98b7c55b6b8475354c1a48aa 100644
--- a/indra/llappearance/lltexturemanagerbridge.h
+++ b/indra/llrender/lltexturemanagerbridge.h
@@ -27,7 +27,6 @@
 #ifndef LL_TEXTUREMANAGERBRIDGE_H
 #define LL_TEXTUREMANAGERBRIDGE_H
 
-#include "llavatarappearancedefines.h"
 #include "llpointer.h"
 #include "llgltexture.h"
 
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index d47bc31808cd9261a4b1a55899e07f12c36dcac3..22eced12bf1487c195c854cad2fd6f0e1847e2e9 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -204,7 +204,8 @@ LLButton::LLButton(const LLButton::Params& p)
 	}
 
 	// Hack to make sure there is space for at least one character
-	if (getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" ")))
+	if (getRect().mRight >= 0 && getRect().getWidth() > 0 &&
+		getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" ")))
 	{
 		// Use old defaults
 		mLeftHPad = llbutton_orig_h_pad;
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index 463ee4e20d3fa2c570dcd8eb9724aa16435fc576..77956e7b330e78346f45c72b322dfda0d5869fe2 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -191,7 +191,9 @@ LLFolderView::LLFolderView(const Params& p)
 	mStatusTextBox(NULL),
 	mShowItemLinkOverlays(p.show_item_link_overlays),
 	mViewModel(p.view_model),
-    mGroupedItemModel(p.grouped_item_model)
+    mGroupedItemModel(p.grouped_item_model),
+    mForceArrange(false),
+    mSingleFolderMode(false)
 {
     LLPanel* panel = p.parent_panel;
     mParentPanel = panel->getHandle();
@@ -618,6 +620,7 @@ void LLFolderView::clearSelection()
 	}
 
 	mSelectedItems.clear();
+    mNeedsScroll = false;
 }
 
 std::set<LLFolderViewItem*> LLFolderView::getSelectionList() const
@@ -674,7 +677,7 @@ void LLFolderView::draw()
 	}
 	else if (mShowEmptyMessage)
 	{
-		mStatusTextBox->setValue(getFolderViewModel()->getStatusText());
+		mStatusTextBox->setValue(getFolderViewModel()->getStatusText(mItems.empty() && mFolders.empty()));
 		mStatusTextBox->setVisible( TRUE );
 		
 		// firstly reshape message textbox with current size. This is necessary to
@@ -702,12 +705,16 @@ void LLFolderView::draw()
 		}
 	}
 
-	if (mRenameItem && mRenamer && mRenamer->getVisible() && !getVisibleRect().overlaps(mRenamer->getRect()))
-	{
-		// renamer is not connected to the item we are renaming in any form so manage it manually
-		// TODO: consider stopping on any scroll action instead of when out of visible area
-		finishRenamingItem();
-	}
+    if (mRenameItem
+        && mRenamer
+        && mRenamer->getVisible()
+        && !getVisibleRect().overlaps(mRenamer->getRect()))
+    {
+        // renamer is not connected to the item we are renaming in any form so manage it manually
+        // TODO: consider stopping on any scroll action instead of when out of visible area
+        LL_DEBUGS("Inventory") << "Renamer out of bounds, hiding" << LL_ENDL;
+        finishRenamingItem();
+    }
 
 	// skip over LLFolderViewFolder::draw since we don't want the folder icon, label, 
 	// and arrow for the root folder
@@ -840,9 +847,12 @@ void LLFolderView::autoOpenItem( LLFolderViewFolder* item )
 	mAutoOpenItems.push(item);
 	
 	item->setOpen(TRUE);
+    if(!item->isSingleFolderMode())
+    {
 	LLRect content_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect());
 	LLRect constraint_rect(0,content_rect.getHeight(), content_rect.getWidth(), 0);
 	scrollToShowItem(item, constraint_rect);
+    }
 }
 
 void LLFolderView::closeAutoOpenedFolders()
@@ -1053,6 +1063,8 @@ void LLFolderView::paste()
 // public rename functionality - can only start the process
 void LLFolderView::startRenamingSelectedItem( void )
 {
+    LL_DEBUGS("Inventory") << "Starting inventory renamer" << LL_ENDL;
+
 	// make sure selection is visible
 	scrollToShowSelection();
 
@@ -1288,6 +1300,11 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask )
 		if(mSelectedItems.size())
 		{
 			LLFolderViewItem* last_selected = getCurSelectedItem();
+            if(last_selected && last_selected->isSingleFolderMode())
+            {
+                handled = FALSE;
+                break;
+            }
 			LLFolderViewItem* parent_folder = last_selected->getParentFolder();
 			if (!last_selected->isOpen() && parent_folder && parent_folder->getParentFolder())
 			{
@@ -1475,9 +1492,19 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )
 			mCallbackRegistrar->popScope();
 		}
 	}
+
+    BOOL item_clicked = FALSE;
+    for (selected_items_t::iterator item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
+    {
+        item_clicked |= (*item_it)->getRect().pointInRect(x, y);
+    }
+    if(!item_clicked && mSingleFolderMode)
+    {
+        clearSelection();
+    }
 	bool hide_folder_menu = mSuppressFolderMenu && isFolderSelected();
-	if (menu && (handled
-		&& ( count > 0 && (hasVisibleChildren()) )) && // show menu only if selected items are visible
+	if (menu && (mSingleFolderMode || (handled
+		&& ( count > 0 && (hasVisibleChildren()) ))) && // show menu only if selected items are visible
 		!hide_folder_menu)
 	{
 		if (mCallbackRegistrar)
@@ -1549,6 +1576,22 @@ BOOL LLFolderView::handleHover( S32 x, S32 y, MASK mask )
 	return LLView::handleHover( x, y, mask );
 }
 
+LLFolderViewItem* LLFolderView::getHoveredItem() const
+{
+	return dynamic_cast<LLFolderViewItem*>(mHoveredItem.get());
+}
+
+void LLFolderView::setHoveredItem(LLFolderViewItem* itemp)
+{
+	if (mHoveredItem.get() != itemp)
+	{
+		if (itemp)
+			mHoveredItem = itemp->getHandle();
+		else
+			mHoveredItem.markDead();
+	}
+}
+
 BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 									 EDragAndDropType cargo_type,
 									 void* cargo_data, 
@@ -1731,7 +1774,7 @@ void LLFolderView::update()
 		mNeedsAutoSelect = FALSE;
 	}
 
-  BOOL is_visible = isInVisibleChain();
+  BOOL is_visible = isInVisibleChain() || mForceArrange;
 
   //Puts folders/items in proper positions
   // arrange() takes the model filter flag into account and call sort() if necessary (CHUI-849)
@@ -1832,13 +1875,28 @@ void LLFolderView::update()
         }
 	}
 
-	if (mSignalSelectCallback)
-	{
-		//RN: we use keyboard focus as a proxy for user-explicit actions
-		BOOL take_keyboard_focus = (mSignalSelectCallback == SIGNAL_KEYBOARD_FOCUS);
-		mSelectSignal(mSelectedItems, take_keyboard_focus);
-	}
-	mSignalSelectCallback = FALSE;
+    if (mSelectedItems.size())
+    {
+        LLFolderViewItem* item = mSelectedItems.back();
+        // If the goal is to show renamer, don't callback untill
+        // item is visible or is no longer being scrolled to.
+        // Otherwise renamer will be instantly closed
+        // Todo: consider moving renamer out of selection callback
+        if (!mNeedsAutoRename || !mNeedsScroll || item->getVisible())
+        {
+            if (mSignalSelectCallback)
+            {
+                //RN: we use keyboard focus as a proxy for user-explicit actions
+                BOOL take_keyboard_focus = (mSignalSelectCallback == SIGNAL_KEYBOARD_FOCUS);
+                mSelectSignal(mSelectedItems, take_keyboard_focus);
+            }
+            mSignalSelectCallback = FALSE;
+        }
+    }
+    else
+    {
+        mSignalSelectCallback = FALSE;
+    }
 }
 
 void LLFolderView::dumpSelectionInformation()
@@ -1901,6 +1959,11 @@ void LLFolderView::updateMenuOptions(LLMenuGL* menu)
 		flags = multi_select_flag;
 	}
 
+    if(mSingleFolderMode && (mSelectedItems.size() == 0))
+    {
+        buildContextMenu(*menu, flags);
+    }
+
 	// This adds a check for restrictions based on the entire
 	// selection set - for example, any one wearable may not push you
 	// over the limit, but all wearables together still might.
@@ -2049,7 +2112,7 @@ LLFolderViewItem* LLFolderView::getNextUnselectedItem()
 	return new_selection;
 }
 
-S32 LLFolderView::getItemHeight()
+S32 LLFolderView::getItemHeight() const
 {
 	if(!hasVisibleChildren())
 {
diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h
index 6e9a681de73c996f0297cbff65e7bf602c192f79..26e9e8b66588b451736ccc48ea64c90a19184c5c 100644
--- a/indra/llui/llfolderview.h
+++ b/indra/llui/llfolderview.h
@@ -127,6 +127,9 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 	bool getAllowMultiSelect() { return mAllowMultiSelect; }
 	bool getAllowDrag() { return mAllowDrag; }
 
+    void setSingleFolderMode(bool is_single_mode) { mSingleFolderMode = is_single_mode; }
+    bool isSingleFolderMode() { return mSingleFolderMode; }
+
 	// Close all folders in the view
 	void openAllFolders();
 	void closeAllFolders();
@@ -137,7 +140,7 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 	// Find width and height of this object and its children. Also
 	// makes sure that this view and its children are the right size.
 	virtual S32 arrange( S32* width, S32* height );
-	virtual S32 getItemHeight();
+	virtual S32 getItemHeight() const;
 
 	void arrangeAll() { mArrangeGeneration++; }
 	S32 getArrangeGeneration() { return mArrangeGeneration; }
@@ -145,6 +148,10 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 	// applies filters to control visibility of items
 	virtual void filter( LLFolderViewFilter& filter);
 
+	void              clearHoveredItem() { setHoveredItem(nullptr); }
+	LLFolderViewItem* getHoveredItem() const;
+	void              setHoveredItem(LLFolderViewItem* itemp);
+
 	// Get the last selected item
 	virtual LLFolderViewItem* getCurSelectedItem( void );
     selected_items_t& getSelectedItems( void );
@@ -238,11 +245,15 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 	void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; }
 	void setEnableRegistrar(LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* registrar) { mEnableRegistrar = registrar; }
 
+    void setForceArrange(bool force) { mForceArrange = force; }
+
 	LLPanel* getParentPanel() { return mParentPanel.get(); }
 	// DEBUG only
 	void dumpSelectionInformation();
 
 	virtual S32	notify(const LLSD& info) ;
+
+	void setShowEmptyMessage(bool show_msg) { mShowEmptyMessage = show_msg; }
 	
 	bool useLabelSuffix() { return mUseLabelSuffix; }
 	virtual void updateMenu();
@@ -276,6 +287,7 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 	LLHandle<LLView>					mPopupMenuHandle;
 	std::string						mMenuFileName;
 	
+	LLHandle<LLView>				mHoveredItem;
 	selected_items_t				mSelectedItems;
 	bool							mKeyboardSelection,
 									mAllowMultiSelect,
@@ -292,7 +304,8 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 									mShowItemLinkOverlays,
 									mShowSelectionContext,
 									mShowSingleSelection,
-									mSuppressFolderMenu;
+									mSuppressFolderMenu,
+                                    mSingleFolderMode;
 
 	// Renaming variables and methods
 	LLFolderViewItem*				mRenameItem;  // The item currently being renamed
@@ -331,6 +344,8 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 
 	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar;
 	LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar;
+
+    bool mForceArrange;
 	
 public:
 	static F32 sAutoOpenTime;
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index a21f5f3bab0f419913b583e385c6f86caf6c9e8b..beef2b6b02c6890b3daaf36b1a11d514bc55f5ee 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -31,6 +31,7 @@
 #include "llfolderview.h"
 #include "llfolderviewmodel.h"
 #include "llpanel.h"
+#include "llcallbacklist.h"
 #include "llcriticaldamp.h"
 #include "llclipboard.h"
 #include "llfocusmgr.h"		// gFocusMgr
@@ -114,6 +115,8 @@ LLFolderViewItem::Params::Params()
     icon_width("icon_width", 0),
     text_pad("text_pad", 0),
     text_pad_right("text_pad_right", 0),
+    single_folder_mode("single_folder_mode", false),
+    double_click_override("double_click_override", false),
     arrow_size("arrow_size", 0),
     max_folder_item_overlap("max_folder_item_overlap", 0)
 { }
@@ -152,7 +155,9 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
     mTextPad(p.text_pad),
     mTextPadRight(p.text_pad_right),
     mArrowSize(p.arrow_size),
-    mMaxFolderItemOverlap(p.max_folder_item_overlap)
+    mSingleFolderMode(p.single_folder_mode),
+    mMaxFolderItemOverlap(p.max_folder_item_overlap),
+    mDoubleClickOverride(p.double_click_override)
 {
 	if (!sColorSetInitialized)
 	{
@@ -163,7 +168,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
 		sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
 		sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
 		sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
-		sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
+		sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
 		sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
 		sColorSetInitialized = true;
 	}
@@ -397,7 +402,7 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height )
             // it is purely visual, so it is fine to do at our laisure
             refreshSuffix();
         }
-		mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel.c_str()) + getLabelFontForStyle(mLabelStyle)->getWidth(mLabelSuffix.c_str()) + mLabelPaddingRight; 
+		mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel.c_str()) + getLabelFontForStyle(LLFontGL::NORMAL)->getWidth(mLabelSuffix.c_str()) + mLabelPaddingRight;
 		mLabelWidthDirty = false;
 	}
 
@@ -414,7 +419,7 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height )
 	return *height;
 }
 
-S32 LLFolderViewItem::getItemHeight()
+S32 LLFolderViewItem::getItemHeight() const
 {
 	return mItemHeight;
 }
@@ -625,11 +630,14 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
 			getWindow()->setCursor(UI_CURSOR_NOLOCKED);
 		}
 
+		root->clearHoveredItem();
 		return TRUE;
 	}
 	else
 	{
-		getRoot()->setShowSelectionContext(FALSE);
+		LLFolderView* pRoot = getRoot();
+		pRoot->setHoveredItem(this);
+		pRoot->setShowSelectionContext(FALSE);
 		getWindow()->setCursor(UI_CURSOR_ARROW);
 		// let parent handle this then...
 		return FALSE;
@@ -684,6 +692,13 @@ BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask )
 void LLFolderViewItem::onMouseLeave(S32 x, S32 y, MASK mask)
 {
 	mIsMouseOverTitle = false;
+
+	// NOTE: LLViewerWindow::updateUI() calls "enter" before "leave"; if the mouse moved to another item, we can't just outright clear it
+	LLFolderView* pRoot = getRoot();
+	if (this == pRoot->getHoveredItem())
+	{
+		pRoot->clearHoveredItem();
+	}
 }
 
 BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
@@ -890,7 +905,10 @@ void LLFolderViewItem::draw()
 
     getViewModelItem()->update();
 
-    drawOpenFolderArrow(default_params, sFgColor);
+    if(!mSingleFolderMode)
+    {
+        drawOpenFolderArrow(default_params, sFgColor);
+    }
 
     drawHighlight(show_context, filled, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
 
@@ -938,16 +956,43 @@ void LLFolderViewItem::draw()
 	F32 text_left = (F32)getLabelXPos();
 	LLWString combined_string = mLabel + mLabelSuffix;
 
+    const LLFontGL* suffix_font = getLabelFontForStyle(LLFontGL::NORMAL);
+    S32 filter_offset = mViewModelItem->getFilterStringOffset();
 	if (filter_string_length > 0)
 	{
+        S32 bottom = llfloor(getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD);
+        S32 top = getRect().getHeight() - TOP_PAD;
+        if(mLabelSuffix.empty() || (font == suffix_font))
+        {
 		S32 left = ll_round(text_left) + font->getWidth(combined_string.c_str(), 0, mViewModelItem->getFilterStringOffset()) - 2;
 		S32 right = left + font->getWidth(combined_string.c_str(), mViewModelItem->getFilterStringOffset(), filter_string_length) + 2;
-		S32 bottom = llfloor(getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD);
-		S32 top = getRect().getHeight() - TOP_PAD;
 
 		LLUIImage* box_image = default_params.selection_image;
 		LLRect box_rect(left, top, right, bottom);
 		box_image->draw(box_rect, sFilterBGColor);
+        }
+        else
+        {
+            S32 label_filter_length = llmin((S32)mLabel.size() - filter_offset, (S32)filter_string_length);
+            if(label_filter_length > 0)
+            {
+                S32 left = ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, llmin(filter_offset, (S32)mLabel.size())) - 2;
+                S32 right = left + font->getWidthF32(mLabel.c_str(), filter_offset, label_filter_length) + 2;
+                LLUIImage* box_image = default_params.selection_image;
+                LLRect box_rect(left, top, right, bottom);
+                box_image->draw(box_rect, sFilterBGColor);
+            }
+            S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length;
+            if(suffix_filter_length > 0)
+            {
+                S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size());
+                S32 left = ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, mLabel.size()) + suffix_font->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset) - 2;
+                S32 right = left + suffix_font->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length) + 2;
+                LLUIImage* box_image = default_params.selection_image;
+                LLRect box_rect(left, top, right, bottom);
+                box_image->draw(box_rect, sFilterBGColor);
+            }
+        }
     }
 
     LLColor4 color = (mIsSelected && filled) ? mFontHighlightColor : mFontColor;
@@ -967,7 +1012,7 @@ void LLFolderViewItem::draw()
 	//
 	if (!mLabelSuffix.empty())
 	{
-		font->render( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor,
+        suffix_font->render( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor,
 						  LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
 						  S32_MAX, S32_MAX, &right_x, FALSE );
 	}
@@ -977,12 +1022,35 @@ void LLFolderViewItem::draw()
 	//
     if (filter_string_length > 0)
     {
-        S32 filter_offset = mViewModelItem->getFilterStringOffset();
-        F32 match_string_left = text_left + font->getWidthF32(combined_string.c_str(), 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string.c_str(), filter_offset, filter_string_length);
-        F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
-        font->render( combined_string, filter_offset, match_string_left, yy,
+        if(mLabelSuffix.empty() || (font == suffix_font))
+        {
+            F32 match_string_left = text_left + font->getWidthF32(combined_string.c_str(), 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string.c_str(), filter_offset, filter_string_length);
+            F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
+            font->render( combined_string, filter_offset, match_string_left, yy,
             sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
             filter_string_length, S32_MAX, &right_x, FALSE );
+        }
+        else
+        {
+            S32 label_filter_length = llmin((S32)mLabel.size() - filter_offset, (S32)filter_string_length);
+            if(label_filter_length > 0)
+            {
+                F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, filter_offset + label_filter_length) - font->getWidthF32(mLabel.c_str(), filter_offset, label_filter_length);
+                F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
+                font->render( mLabel, filter_offset, match_string_left, yy,
+ sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, label_filter_length, S32_MAX, &right_x, FALSE );
+            }
+            
+            S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length;
+            if(suffix_filter_length > 0)
+            {
+                S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size());
+                F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, mLabel.size()) + suffix_font->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset + suffix_filter_length) - suffix_font->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length);
+                F32 yy = (F32)getRect().getHeight() - suffix_font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
+                suffix_font->render( mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, suffix_filter_length, S32_MAX, &right_x, FALSE );
+            }
+        }
+
     }
 
     //Gilbert Linden 9-20-2012: Although this should be legal, removing it because it causes the mLabelSuffix rendering to
@@ -1280,7 +1348,7 @@ BOOL LLFolderViewFolder::setSelection(LLFolderViewItem* selection, BOOL openitem
 			child_selected = TRUE;
 		}
 	}
-	if(openitem && child_selected)
+	if(openitem && child_selected && !mSingleFolderMode)
 	{
 		setOpenArrangeRecursively(TRUE);
 	}
@@ -1687,6 +1755,11 @@ BOOL LLFolderViewFolder::isRemovable()
 	return TRUE;
 }
 
+void LLFolderViewFolder::destroyRoot()
+{
+    delete this;
+}
+
 // this is an internal method used for adding items to folders. 
 void LLFolderViewFolder::addItem(LLFolderViewItem* item)
 {
@@ -1755,7 +1828,19 @@ void LLFolderViewFolder::toggleOpen()
 // Force a folder open or closed
 void LLFolderViewFolder::setOpen(BOOL openitem)
 {
-	setOpenArrangeRecursively(openitem);
+    if(mSingleFolderMode)
+    {
+        // navigateToFolder can destroy this view
+        // delay it in case setOpen was called from click or key processing
+        doOnIdleOneTime([this]()
+                        {
+                            getViewModelItem()->navigateToFolder();
+                        });
+    }
+    else
+    {
+        setOpenArrangeRecursively(openitem);
+    }
 }
 
 void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse)
@@ -1950,7 +2035,8 @@ BOOL LLFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask )
 	}
 	if( !handled )
 	{
-		if(mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad)
+		if((mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad)
+           && !mSingleFolderMode)
 		{
 			toggleOpen();
 			handled = TRUE;
@@ -1968,12 +2054,45 @@ BOOL LLFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask )
 BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask )
 {
 	BOOL handled = FALSE;
+    if(mSingleFolderMode)
+    {
+        static LLUICachedControl<bool> double_click_new_window("SingleModeDoubleClickOpenWindow", false);
+        if (double_click_new_window)
+        {
+            getViewModelItem()->navigateToFolder(true);
+        }
+        else
+        {
+            // navigating is going to destroy views and change children
+            // delay it untill handleDoubleClick processing is complete
+            doOnIdleOneTime([this]()
+                            {
+                                getViewModelItem()->navigateToFolder(false);
+                            });
+        }
+        return TRUE;
+    }
+
 	if( isOpen() )
 	{
 		handled = childrenHandleDoubleClick( x, y, mask ) != NULL;
 	}
 	if( !handled )
 	{
+        if(mDoubleClickOverride)
+        {
+            static LLUICachedControl<U32> double_click_action("MultiModeDoubleClickFolder", false);
+            if (double_click_action == 1)
+            {
+                getViewModelItem()->navigateToFolder(true);
+                return TRUE;
+            }
+            if (double_click_action == 2)
+            {
+                getViewModelItem()->navigateToFolder(false, true);
+                return TRUE;
+            }
+        }
 		if(mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad)
 		{
 			// don't select when user double-clicks plus sign
diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h
index c72eca6965ce38b841e4147e1f6dde8598ab9297..10a3ca1413b8c0f9a3ed36a625f42b3b661b1cd0 100644
--- a/indra/llui/llfolderviewitem.h
+++ b/indra/llui/llfolderviewitem.h
@@ -72,6 +72,8 @@ class LLFolderViewItem : public LLView
                                                     text_pad_right,
                                                     arrow_size,
                                                     max_folder_item_overlap;
+        Optional<bool>                              single_folder_mode,
+                                                    double_click_override;
 		Params();
 	};
 
@@ -121,6 +123,8 @@ class LLFolderViewItem : public LLView
 								mIsMouseOverTitle,
 								mAllowWear,
                                 mAllowDrop,
+                                mSingleFolderMode,
+                                mDoubleClickOverride,
 								mSelectPending,
 								mIsItemCut;
 
@@ -174,7 +178,7 @@ class LLFolderViewItem : public LLView
 	// Finds width and height of this object and it's children.  Also
 	// makes sure that this view and it's children are the right size.
 	virtual S32 arrange( S32* width, S32* height );
-	virtual S32 getItemHeight();
+	virtual S32 getItemHeight() const;
     virtual S32 getLabelXPos();
     S32 getIconPad();
     S32 getTextPad();
@@ -213,9 +217,9 @@ class LLFolderViewItem : public LLView
 
 	void setIsCurSelection(BOOL select) { mIsCurSelection = select; }
 
-	BOOL getIsCurSelection() { return mIsCurSelection; }
+	BOOL getIsCurSelection() const { return mIsCurSelection; }
 
-	BOOL hasVisibleChildren() { return mHasVisibleChildren; }
+	BOOL hasVisibleChildren() const { return mHasVisibleChildren; }
 
 	// true if object can't have children
 	virtual bool isFolderComplete() { return true; }
@@ -264,7 +268,7 @@ class LLFolderViewItem : public LLView
 	virtual LLFolderView*	getRoot();
 	virtual const LLFolderView*	getRoot() const;
 	BOOL			isDescendantOf( const LLFolderViewFolder* potential_ancestor );
-	S32				getIndentation() { return mIndentation; }
+	S32				getIndentation() const { return mIndentation; }
 
 	virtual BOOL	passedFilter(S32 filter_generation = -1);
 	virtual BOOL	isPotentiallyVisible(S32 filter_generation = -1);
@@ -277,6 +281,8 @@ class LLFolderViewItem : public LLView
     // Does not need filter update
 	virtual void refreshSuffix();
 
+    bool isSingleFolderMode() { return mSingleFolderMode; }
+
 	// LLView functionality
 	virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
 	virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );
@@ -387,6 +393,7 @@ class LLFolderViewFolder : public LLFolderViewItem
 
 	// destroys this folder, and all children
 	virtual void destroyView();
+    void destroyRoot();
 
     // whether known children are fully loaded (arrange sets to true)
     virtual bool isFolderComplete() { return mIsFolderComplete; }
diff --git a/indra/llui/llfolderviewmodel.cpp b/indra/llui/llfolderviewmodel.cpp
index 5fa3468f38e78e1a8dd0d03faacc716171bf58ca..22e767bf78beb90869b12b13e0e7cd7421b0c85d 100644
--- a/indra/llui/llfolderviewmodel.cpp
+++ b/indra/llui/llfolderviewmodel.cpp
@@ -34,7 +34,7 @@ bool LLFolderViewModelCommon::needsSort(LLFolderViewModelItem* item)
 	return item->getSortVersion() < mTargetSortVersion;
 }
 
-std::string LLFolderViewModelCommon::getStatusText()
+std::string LLFolderViewModelCommon::getStatusText(bool is_empty_folder)
 {
 	if (!contentsReady() || mFolderView->getViewModelItem()->getLastFilterGeneration() < getFilter().getCurrentGeneration())
 	{
@@ -43,7 +43,7 @@ std::string LLFolderViewModelCommon::getStatusText()
 	}
 	else
 	{
-		return getFilter().getEmptyLookupMessage();
+		return getFilter().getEmptyLookupMessage(is_empty_folder);
 	}
 }
 
diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h
index f7952fa06dffa49e760ba0bcb4ef4238d83c38ac..e0852199bc84555c937b4aa62885b993cfa11150 100644
--- a/indra/llui/llfolderviewmodel.h
+++ b/indra/llui/llfolderviewmodel.h
@@ -70,7 +70,7 @@ class LLFolderViewFilter
 	virtual bool				checkFolder(const LLFolderViewModelItem* folder) const = 0;
 
 	virtual void 				setEmptyLookupMessage(const std::string& message) = 0;
-	virtual std::string			getEmptyLookupMessage() const = 0;
+    virtual std::string			getEmptyLookupMessage(bool is_empty_folder = false) const = 0;
 
 	virtual bool				showAllResults() const = 0;
 
@@ -126,7 +126,7 @@ class LLFolderViewModelInterface
 	virtual void setFolderView(LLFolderView* folder_view) = 0;
 	virtual LLFolderViewFilter& getFilter() = 0;
 	virtual const LLFolderViewFilter& getFilter() const = 0;
-	virtual std::string getStatusText() = 0;
+	virtual std::string getStatusText(bool is_empty_folder = false) = 0;
 
 	virtual bool startDrag(std::vector<LLFolderViewModelItem*>& items) = 0;
 };
@@ -160,6 +160,8 @@ class LLFolderViewModelItem : public LLRefCount
 	virtual void openItem( void ) = 0;
 	virtual void closeItem( void ) = 0;
 	virtual void selectItem(void) = 0;
+
+    virtual void navigateToFolder(bool new_window = false, bool change_mode = false) = 0;
     
     virtual BOOL isItemWearable() const { return FALSE; }
 
@@ -398,7 +400,7 @@ class LLFolderViewModelCommon : public LLFolderViewModelInterface
 		// sort everything
 		mTargetSortVersion++;
 	}
-	virtual std::string getStatusText();
+	virtual std::string getStatusText(bool is_empty_folder = false);
 	virtual void filter();
 
 	void setFolderView(LLFolderView* folder_view) { mFolderView = folder_view;}
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index a05849a9f198dc841eee65dc5b44e92770b09dac..490827d282139176d735b942f6fa0229214fd1ba 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -39,7 +39,9 @@ class LLUICtrlFactory;
 // Classes
 //
 
-// 
+// Class for diplaying named UI textures
+// Do not use for displaying textures from network,
+// UI textures are stored permanently!
 class LLIconCtrl
 : public LLUICtrl
 {
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 601018af2becfa12fa8c65fd1f74ee1298728ec0..bf548c11dda2faed270c6f3b9271947ae16c532c 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -217,7 +217,8 @@ LLLayoutStack::Params::Params()
 	drag_handle_first_indent("drag_handle_first_indent", 0),
 	drag_handle_second_indent("drag_handle_second_indent", 0),
 	drag_handle_thickness("drag_handle_thickness", 5),
-	drag_handle_shift("drag_handle_shift", 2)
+	drag_handle_shift("drag_handle_shift", 2),
+    drag_handle_color("drag_handle_color", LLUIColorTable::instance().getColor("ResizebarBody"))
 {
 	addSynonym(border_size, "drag_handle_gap");
 }
@@ -237,7 +238,8 @@ LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p)
 	mDragHandleFirstIndent(p.drag_handle_first_indent),
 	mDragHandleSecondIndent(p.drag_handle_second_indent),
 	mDragHandleThickness(p.drag_handle_thickness),
-	mDragHandleShift(p.drag_handle_shift)
+	mDragHandleShift(p.drag_handle_shift),
+    mDragHandleColor(p.drag_handle_color())
 {
 }
 
@@ -525,6 +527,15 @@ void LLLayoutStack::updateLayout()
 	mNeedsLayout = continue_animating;
 } // end LLLayoutStack::updateLayout
 
+void LLLayoutStack::setPanelSpacing(S32 val)
+{
+    if (mPanelSpacing != val)
+    {
+        mPanelSpacing = val;
+        mNeedsLayout = true;
+    }
+}
+
 LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
 {
 	if (!panelp) return NULL;
@@ -578,7 +589,7 @@ void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp)
 				resize_bar_bg_panel_p.follows.flags = FOLLOWS_ALL;
 				resize_bar_bg_panel_p.tab_stop = false;
 				resize_bar_bg_panel_p.background_visible = true;
-				resize_bar_bg_panel_p.bg_alpha_color = LLUIColorTable::instance().getColor("ResizebarBody");
+				resize_bar_bg_panel_p.bg_alpha_color = mDragHandleColor;
 				resize_bar_bg_panel_p.has_border = true;
 				resize_bar_bg_panel_p.border.border_thickness = 1;
 				resize_bar_bg_panel_p.border.highlight_light_color = LLUIColorTable::instance().getColor("ResizebarBorderLight");
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index b0b06059e1ad0d1df88886c91583b8b36e964238..09b10c75279a8c437a3d11e8bfa285342a152caa 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -59,6 +59,8 @@ class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack>
 		Optional<S32>			drag_handle_thickness;
 		Optional<S32>			drag_handle_shift;
 
+        Optional<LLUIColor>     drag_handle_color;
+
 		Params();
 	};
 
@@ -89,6 +91,7 @@ class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack>
 	void updateLayout();
 
 	S32 getPanelSpacing() const { return mPanelSpacing; }
+    void setPanelSpacing(S32 val);
 	
 	static void updateClass();
 
@@ -128,6 +131,7 @@ class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack>
 	S32  mDragHandleSecondIndent;
 	S32  mDragHandleThickness;
 	S32  mDragHandleShift;
+    LLUIColor mDragHandleColor;
 }; // end class LLLayoutStack
 
 
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 13452d2d2f65abe061f0817578e6ade9b36cbba0..7a2ac3228c95181c8ea2b12da10348726f963a62 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -577,30 +577,10 @@ void LLMenuItemGL::onVisibilityChange(BOOL new_visibility)
 LLMenuItemSeparatorGL::LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p) :
 	LLMenuItemGL( p )
 {
-}
-
-void LLMenuItemSeparatorGL::initFromParams(const Params& p)
-{
-	if (p.on_visible.isProvided())
-	{
-		mVisibleSignal.connect(initEnableCallback(p.on_visible));
-	}
-	LLUICtrl::initFromParams(p);
-}
-
-void LLMenuItemSeparatorGL::updateVisible()
-{
-	if (mVisibleSignal.num_slots() > 0)
-	{
-		bool visible = mVisibleSignal(this, LLSD());
-		setVisible(visible);
-	}
-}
-
-void LLMenuItemSeparatorGL::buildDrawLabel()
-{
-	updateVisible();
-	LLMenuItemGL::buildDrawLabel();
+    if (p.on_visible.isProvided())
+    {
+        mVisibleSignal.connect(initEnableCallback(p.on_visible));
+    }
 }
 
 //virtual
@@ -617,6 +597,15 @@ void LLMenuItemSeparatorGL::draw( void )
 	gl_line_2d( PAD, y, getRect().getWidth() - PAD, y );
 }
 
+void LLMenuItemSeparatorGL::buildDrawLabel( void )
+{
+    if (mVisibleSignal.num_slots() > 0)
+    {
+        bool visible = mVisibleSignal(this, LLSD());
+        setVisible(visible);
+    }
+}
+
 BOOL LLMenuItemSeparatorGL::handleMouseDown(S32 x, S32 y, MASK mask)
 {
 	LLMenuGL* parent_menu = getMenu();
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 2a81bacd31846a8f9748dff5a7327fa182d8fb30..521494f1e4002183110bd7944bf599cbd9650325 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -234,10 +234,9 @@ class LLMenuItemSeparatorGL : public LLMenuItemGL
 public:
 	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
 	{
-		Optional<EnableCallbackParam > on_visible;
-		Params()
-			: on_visible("on_visible")
-		{}
+        Optional<EnableCallbackParam > on_visible;
+        Params() : on_visible("on_visible")
+        {}
 	};
 	LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p = LLMenuItemSeparatorGL::Params());
 
@@ -246,13 +245,12 @@ class LLMenuItemSeparatorGL : public LLMenuItemGL
 	/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
 	/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
 
+    virtual void buildDrawLabel();
+
 	/*virtual*/ U32 getNominalHeight( void ) const;
-	void updateVisible(void);
-	void initFromParams(const Params& p);
-	// called to rebuild the draw label
-	/*virtual*/ void buildDrawLabel(void);
+
 private:
-	enable_signal_t mVisibleSignal;
+    enable_signal_t mVisibleSignal;
 };
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp
index 42c628adab5b7ba975bf48e2107a94124eb8b2dc..ddfca5a04d12061479f4c7a3c41fe70061f894a0 100644
--- a/indra/llui/llscrollbar.cpp
+++ b/indra/llui/llscrollbar.cpp
@@ -190,12 +190,12 @@ void LLScrollbar::setPageSize( S32 page_size )
 	}
 }
 
-BOOL LLScrollbar::isAtBeginning()
+bool LLScrollbar::isAtBeginning() const
 {
 	return mDocPos == 0;
 }
 
-BOOL LLScrollbar::isAtEnd()
+bool LLScrollbar::isAtEnd() const
 {
 	return mDocPos == getDocPosMax();
 }
@@ -595,7 +595,12 @@ void LLScrollbar::setValue(const LLSD& value)
 
 BOOL LLScrollbar::handleKeyHere(KEY key, MASK mask)
 {
-	BOOL handled = FALSE;
+    if (getDocPosMax() == 0 && !getVisible())
+    {
+        return FALSE;
+    }
+
+    BOOL handled = FALSE;
 
 	switch( key )
 	{
diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h
index 38db475a3527400ca37309ca6890697673136369..95ff77f86ee50674cdc006d84ec31a8e34675eaf 100644
--- a/indra/llui/llscrollbar.h
+++ b/indra/llui/llscrollbar.h
@@ -105,8 +105,8 @@ class LLScrollbar
 	bool				setDocPos( S32 pos, BOOL update_thumb = TRUE );
 	S32					getDocPos() const		{ return mDocPos; }
 
-	BOOL				isAtBeginning();
-	BOOL				isAtEnd();
+	bool				isAtBeginning() const;
+	bool				isAtEnd() const;
 
 	// Setting both at once.
 	void				setDocParams( S32 size, S32 pos );
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index ef5d71a93f5f9f39c3773e57aa0a047afa552c76..4165cf084c16940ae17d792b29469b27ab146a42 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -105,8 +105,8 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
 	mBorder = LLUICtrlFactory::create<LLViewBorder> (params);
 	LLView::addChild( mBorder );
 
-	mInnerRect.set( 0, getRect().getHeight(), getRect().getWidth(), 0 );
-	mInnerRect.stretch( -getBorderWidth()  );
+	mInnerRect = getLocalRect();
+	mInnerRect.stretch( -getBorderWidth() );
 
 	LLRect vertical_scroll_rect = mInnerRect;
 	vertical_scroll_rect.mLeft = vertical_scroll_rect.mRight - scrollbar_size;
@@ -124,8 +124,9 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
 	mScrollbar[VERTICAL] = LLUICtrlFactory::create<LLScrollbar> (sbparams);
 	LLView::addChild( mScrollbar[VERTICAL] );
 	
-	LLRect horizontal_scroll_rect = mInnerRect;
-	horizontal_scroll_rect.mTop = horizontal_scroll_rect.mBottom + scrollbar_size;
+	LLRect horizontal_scroll_rect;
+	horizontal_scroll_rect.mTop = scrollbar_size;
+	horizontal_scroll_rect.mRight = mInnerRect.getWidth();
 	sbparams.name("scrollable horizontal");
 	sbparams.rect(horizontal_scroll_rect);
 	sbparams.orientation(LLScrollbar::HORIZONTAL);
@@ -134,7 +135,7 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
 	sbparams.page_size(mInnerRect.getWidth());
 	sbparams.step_size(VERTICAL_MULTIPLE);
 	sbparams.visible(false);
-	sbparams.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT);
+	sbparams.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
 	sbparams.change_callback(p.scroll_callback);
 	mScrollbar[HORIZONTAL] = LLUICtrlFactory::create<LLScrollbar> (sbparams);
 	LLView::addChild( mScrollbar[HORIZONTAL] );
diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h
index c14099dbd5361f409905827eb5269396f72d37e2..dacea2a987c51e0a3b618d331314cc31b2f08ad1 100644
--- a/indra/llui/llscrollcontainer.h
+++ b/indra/llui/llscrollcontainer.h
@@ -98,8 +98,10 @@ class LLScrollContainer : public LLUICtrl
 	void			pageDown(S32 overlap = 0);
 	void			goToTop();
 	void			goToBottom();
-	bool			isAtTop() { return mScrollbar[VERTICAL]->isAtBeginning(); }
-	bool			isAtBottom() { return mScrollbar[VERTICAL]->isAtEnd(); }
+	bool			isAtTop() const { return mScrollbar[VERTICAL]->isAtBeginning(); }
+	bool			isAtBottom() const { return mScrollbar[VERTICAL]->isAtEnd(); }
+    S32             getDocPosVertical() const { return mScrollbar[VERTICAL]->getDocPos(); }
+    S32             getDocPosHorizontal() const { return mScrollbar[HORIZONTAL]->getDocPos(); }
 	S32				getBorderWidth() const;
 
 	// LLView functionality
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index cd31b0f73a79bb14e3d96d745dd5b6c10a3f042e..44ae56597f8dfb534f8218f1c6954cc740b74184 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -604,6 +604,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
 			LLButton* tab_button = getTab(index)->mButton;
 			gFocusMgr.setMouseCapture(this);
 			tab_button->setFocus(TRUE);
+            mMouseDownTimer.start();
 		}
 	}
 
@@ -655,7 +656,11 @@ BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask )
 		handled = LLPanel::handleHover(x, y, mask);
 	}
 
-	commitHoveredButton(x, y);
+    F32 drag_delay = 0.25f; // filter out clicks from dragging
+    if (mMouseDownTimer.getElapsedTimeF32() > drag_delay)
+    {
+        commitHoveredButton(x, y);
+    }
 	return handled;
 }
 
@@ -701,6 +706,7 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
 	}
 
 	commitHoveredButton(x, y);
+    mMouseDownTimer.stop();
 	LLPanel* cur_panel = getCurrentPanel();
 	if (hasMouseCapture())
 	{
@@ -1007,7 +1013,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
 	}
 	else
 	{
-		//Scip tab button space if they are invisible(EXT - 576)
+		// Skip tab button space if tabs are invisible (EXT-576)
 		tab_panel_top = getRect().getHeight();
 		tab_panel_bottom = LLPANEL_BORDER_WIDTH;
 	}
@@ -1022,9 +1028,9 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
 	}
 	else
 	{
-		tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH, 
+		tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH * 3,
 								tab_panel_top,
-								getRect().getWidth()-LLPANEL_BORDER_WIDTH,
+								getRect().getWidth() - LLPANEL_BORDER_WIDTH * 2,
 								tab_panel_bottom );
 	}
 	child->setFollowsAll();
@@ -1111,7 +1117,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
 		  p.follows.flags = p.follows.flags() | FOLLOWS_TOP;
 		}
 		else
-		  { 
+		{ 
 		    p.name("htab_"+std::string(child->getName()));
 		    p.visible(false);
 		    p.image_unselected(tab_img);
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index ba72a528fec9aff7d29442fc508970769e270fbe..765b70401a326a3c8eb7068a7c131fdf639ef90c 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -320,6 +320,7 @@ class LLTabContainer : public LLPanel
 	LLUIColor						mTabsFlashingColor;
 	S32								mTabIconCtrlPad;
 	bool							mUseTabEllipses;
+    LLFrameTimer					mMouseDownTimer;
 };
 
 #endif  // LL_TABCONTAINER_H
diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp
index 19fdca684626f9abdce722ca311541030bf55493..a009b5c57d3449e9dd6e3b411d08ce15b636a6a5 100644
--- a/indra/llui/lltooltip.cpp
+++ b/indra/llui/lltooltip.cpp
@@ -168,6 +168,7 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p)
 :	LLPanel(p),
 	mHasClickCallback(p.click_callback.isProvided()),
 	mPadding(p.padding),
+	mMaxWidth(p.max_width),
 	mTextBox(NULL),
 	mInfoButton(NULL),
 	mPlayMediaButton(NULL),
@@ -277,7 +278,7 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)
 
 	// do this *after* we've had our size set in LLPanel::initFromParams();
 	const S32 REALLY_LARGE_HEIGHT = 10000;
-	mTextBox->reshape(p.max_width, REALLY_LARGE_HEIGHT);
+	mTextBox->reshape(mMaxWidth, REALLY_LARGE_HEIGHT);
 
 	if (p.styled_message.isProvided())
 	{
@@ -293,16 +294,19 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)
 		mTextBox->setText(p.message());
 	}
 
-	S32 text_width = llmin(p.max_width(), mTextBox->getTextPixelWidth() + 1);
+	updateTextBox();
+	snapToChildren();
+}
+
+void LLToolTip::updateTextBox()
+{
+	S32 text_width = llmin(mMaxWidth, mTextBox->getTextPixelWidth() + 1);
 	S32 text_height = mTextBox->getTextPixelHeight();
 	mTextBox->reshape(text_width, text_height);
-	if (mInfoButton)
-	{
-		LLRect text_rect = mTextBox->getRect();
-		LLRect icon_rect = mInfoButton->getRect();
-		mTextBox->translate(0, icon_rect.getCenterY() - text_rect.getCenterY());
-	}
-
+}
+ 
+void LLToolTip::snapToChildren()
+{
 	// reshape tooltip panel to fit text box
 	LLRect tooltip_rect = calcBoundingRect();
 	tooltip_rect.mTop += mPadding;
@@ -310,7 +314,14 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)
 	tooltip_rect.mBottom = 0;
 	tooltip_rect.mLeft = 0;
 
-	mTextBox->reshape(mTextBox->getRect().getWidth(), llmax(mTextBox->getRect().getHeight(), tooltip_rect.getHeight() - 2 * mPadding));
+	if (mInfoButton)
+	{
+		mTextBox->reshape(mTextBox->getRect().getWidth(), llmax(mTextBox->getRect().getHeight(), tooltip_rect.getHeight() - 2 * mPadding));
+
+		LLRect text_rect = mTextBox->getRect();
+		LLRect icon_rect = mInfoButton->getRect();
+		mInfoButton->translate(0, text_rect.getCenterY() - icon_rect.getCenterY());
+	}
 
 	setShape(tooltip_rect);
 }
@@ -433,7 +444,10 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params)
 	}
 	tooltip_params.rect = LLRect (0, 1, 1, 0);
 
-	mToolTip = LLUICtrlFactory::create<LLToolTip> (tooltip_params);
+	if (tooltip_params.create_callback.isProvided())
+		mToolTip = tooltip_params.create_callback()(tooltip_params);
+	else
+		mToolTip = LLUICtrlFactory::create<LLToolTip> (tooltip_params);
 
 	gToolTipView->addChild(mToolTip);
 
diff --git a/indra/llui/lltooltip.h b/indra/llui/lltooltip.h
index cff582fcfb9e87e621370317c63a3b9a412eefc2..6bb9be8e2eb01c631afd7c28ede23488fc48a5af 100644
--- a/indra/llui/lltooltip.h
+++ b/indra/llui/lltooltip.h
@@ -68,6 +68,7 @@ class LLToolTip : public LLPanel
 	struct Params : public LLInitParam::Block<Params, LLPanel::Params> 
 	{
 		typedef boost::function<void(void)> click_callback_t;
+		typedef boost::function<LLToolTip*(LLToolTip::Params)> create_callback_t;
 
 		Optional<std::string>		message;
 		Multiple<StyledText>		styled_message;
@@ -84,6 +85,8 @@ class LLToolTip : public LLPanel
 		Optional<bool>				time_based_media,
 									web_based_media,
 									media_playing;
+		Optional<create_callback_t>	create_callback;
+		Optional<LLSD>				create_params;
 		Optional<click_callback_t>	click_callback,
 									click_playmedia_callback,
 									click_homepage_callback;
@@ -103,11 +106,15 @@ class LLToolTip : public LLPanel
 	bool hasClickCallback();
 
 	LLToolTip(const Params& p);
-	void initFromParams(const LLToolTip::Params& params);
+	virtual void initFromParams(const LLToolTip::Params& params);
 
 	void getToolTipMessage(std::string & message);
 
-private:
+protected:
+	void updateTextBox();
+	void snapToChildren();
+
+protected:
 	class LLTextBox*	mTextBox;
 	class LLButton*     mInfoButton;
 	class LLButton*     mPlayMediaButton;
@@ -117,6 +124,7 @@ class LLToolTip : public LLPanel
 	LLFrameTimer	mVisibleTimer;
 	bool			mHasClickCallback;
 	S32				mPadding;	// pixels
+	S32				mMaxWidth;
 };
 
 // used for the inspector tooltips which need different background images etc.
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 268d9dd4079cf5a28daa5656ba127ca1c2784d59..49572b5783395869ac20bfbc523addcaec73912e 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -545,6 +545,15 @@ void LLUICtrl::setControlVariable(LLControlVariable* control)
 	}
 }
 
+void LLUICtrl::removeControlVariable()
+{
+    if (mControlVariable)
+    {
+        mControlConnection.disconnect();
+        mControlVariable = NULL;
+    }
+}
+
 //virtual
 void LLUICtrl::setControlName(std::string_view control_name, LLView *context)
 {
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index ebd80463ca4fc44f2a6f853e9594d9c0bea0a44e..61e48b8987082dc066151fa7df7c13710338689e 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -175,6 +175,7 @@ class LLUICtrl
 	bool setControlValue(const LLSD& value);
 	void setControlVariable(LLControlVariable* control);
     virtual void setControlName(std::string_view control, LLView* context = NULL);
+    void removeControlVariable();
 	
 	LLControlVariable* getControlVariable() { return mControlVariable; } 
 	
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 7bb6432153883c331a6aacb87a5409d1826e846b..426d4e9d45dde98260228fe6fb693ba37e59e300 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -311,7 +311,13 @@ bool LLView::addChild(LLView* child, S32 tab_group)
 	}
 
 	child->mParentView = this;
-	updateBoundingRect();
+    if (getVisible() && child->getVisible())
+    {
+        // if child isn't visible it won't affect bounding rect
+        // if current view is not visible it will be recalculated
+        // on visibility change
+        updateBoundingRect();
+    }
 	mLastTabGroup = tab_group;
 	return true;
 }
@@ -581,6 +587,7 @@ void LLView::deleteAllChildren()
         delete viewp;
         mChildList.pop_front();
 	}
+    updateBoundingRect();
 }
 
 void LLView::setAllChildrenEnabled(BOOL b)
@@ -892,6 +899,17 @@ LLView*	LLView::childFromPoint(S32 x, S32 y, bool recur)
 	return 0;
 }
 
+F32 LLView::getTooltipTimeout()
+{
+    static LLCachedControl<F32> tooltip_fast_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipFastDelay", 0.1f);
+    static LLCachedControl<F32> tooltip_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipDelay", 0.7f);
+    // allow "scrubbing" over ui by showing next tooltip immediately
+    // if previous one was still visible
+    return (F32)(LLToolTipMgr::instance().toolTipVisible()
+    ? tooltip_fast_delay
+    : tooltip_delay);
+}
+
 BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
 {
 	BOOL handled = FALSE;
@@ -901,14 +919,7 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
 	std::string tooltip = getToolTip();
 	if (!tooltip.empty())
 	{
-        static LLUICachedControl<F32> tooltip_fast_delay("ToolTipFastDelay", 0.1f);
-        static LLUICachedControl<F32> tooltip_delay("ToolTipDelay", 0.7f);
-        static LLUICachedControl<bool> allow_ui_tooltips("BasicUITooltips", true);
-		// allow "scrubbing" over ui by showing next tooltip immediately
-		// if previous one was still visible
-		F32 timeout = LLToolTipMgr::instance().toolTipVisible() 
-		              ? tooltip_fast_delay
-		              : tooltip_delay;
+        static LLCachedControl<bool> allow_ui_tooltips(*LLUI::getInstance()->mSettingGroups["config"], "BasicUITooltips", true);
 
 		// Even if we don't show tooltips, consume the event, nothing below should show tooltip
 		if (allow_ui_tooltips)
@@ -916,7 +927,7 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
 			LLToolTipMgr::instance().show(LLToolTip::Params()
 			                              .message(tooltip)
 			                              .sticky_rect(calcScreenRect())
-			                              .delay_time(timeout));
+			                              .delay_time(getTooltipTimeout()));
 		}
 		handled = TRUE;
 	}
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 3a05d262fe14e419dfab8757521ad1c93b7dc824..a8732be5f73002ac25dc4914de04092525df32f3 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -248,6 +248,7 @@ class LLView
 
 	ECursorType	getHoverCursor() { return mHoverCursor; }
 
+    static F32 getTooltipTimeout();
 	virtual const std::string getToolTip() const			{ return mToolTipMsg.getString(); }
 
 	void		sendChildToFront(LLView* child);
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 89325f65a3de4f96d3c924c9636f696d189bbf46..0d4b8e1f30d3fbe9032adfe35892bc60dd3a6532 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -239,6 +239,7 @@ set(viewer_SOURCE_FILES
     llfloaterbuyland.cpp
     llfloatercamera.cpp
     llfloatercamerapresets.cpp
+    llfloaterchangeitemthumbnail.cpp
     llfloaterchatalerts.cpp
     llfloaterchatvoicevolume.cpp
     llfloaterclassified.cpp
@@ -279,6 +280,7 @@ set(viewer_SOURCE_FILES
     llfloaterimsession.cpp
     llfloaterimcontainer.cpp
     llfloaterinspect.cpp
+    llfloaterinventorysettings.cpp
     llfloaterjoystick.cpp
     llfloaterlagmeter.cpp
     llfloaterland.cpp
@@ -301,10 +303,9 @@ set(viewer_SOURCE_FILES
     llfloaternewlocalinventory.cpp
     llfloaternotificationsconsole.cpp
     llfloaternotificationstabbed.cpp
-    llfloateroutfitphotopreview.cpp 
     llfloaterobjectweights.cpp
     llfloateropenobject.cpp
-    llfloatersimpleoutfitsnapshot.cpp
+    llfloatersimplesnapshot.cpp
     llfloaterpathfindingcharacters.cpp
     llfloaterpathfindingconsole.cpp
     llfloaterpathfindinglinksets.cpp
@@ -320,7 +321,6 @@ set(viewer_SOURCE_FILES
     llfloaterpreviewtrash.cpp
     llfloaterprofiletexture.cpp
     llfloaterprogressview.cpp
-    llfloaterproperties.cpp
     llfloaterpublishclassified.cpp
     llfloaterregiondebugconsole.cpp
     llfloaterregioninfo.cpp
@@ -398,10 +398,13 @@ set(viewer_SOURCE_FILES
     llinspectgroup.cpp
     llinspectobject.cpp
     llinspectremoteobject.cpp
+    llinspecttexture.cpp
     llinspecttoast.cpp
     llinventorybridge.cpp
     llinventoryfilter.cpp
     llinventoryfunctions.cpp
+    llinventorygallery.cpp
+    llinventorygallerymenu.cpp
     llinventoryicon.cpp
     llinventoryitemslist.cpp
     llinventorylistitem.cpp
@@ -646,6 +649,7 @@ set(viewer_SOURCE_FILES
     lltextureinfodetails.cpp
     lltexturestats.cpp
     lltextureview.cpp
+    llthumbnailctrl.cpp
     lltinygltfhelper.cpp
     lltoast.cpp
     lltoastalertpanel.cpp
@@ -959,6 +963,7 @@ set(viewer_HEADER_FILES
     llfloaterbuycurrencyhtml.h
     llfloaterbuyland.h
     llfloatercamerapresets.h
+    llfloaterchangeitemthumbnail.h
     llfloatercamera.h
     llfloaterchatalerts.h
     llfloaterchatvoicevolume.h
@@ -1003,6 +1008,7 @@ set(viewer_HEADER_FILES
     llfloaterimsession.h
     llfloaterimcontainer.h
     llfloaterinspect.h
+    llfloaterinventorysettings.h
     llfloaterjoystick.h
     llfloaterlagmeter.h
     llfloaterland.h
@@ -1025,10 +1031,9 @@ set(viewer_HEADER_FILES
     llfloaternewlocalinventory.h
     llfloaternotificationsconsole.h
     llfloaternotificationstabbed.h
-    llfloateroutfitphotopreview.h
     llfloaterobjectweights.h
     llfloateropenobject.h
-    llfloatersimpleoutfitsnapshot.h
+    llfloatersimplesnapshot.h
     llfloaterpathfindingcharacters.h
     llfloaterpathfindingconsole.h
     llfloaterpathfindinglinksets.h
@@ -1044,7 +1049,6 @@ set(viewer_HEADER_FILES
     llfloaterpreviewtrash.h
     llfloaterprofiletexture.h
     llfloaterprogressview.h
-    llfloaterproperties.h
     llfloaterpublishclassified.h
     llfloaterregiondebugconsole.h
     llfloaterregioninfo.h
@@ -1120,10 +1124,13 @@ set(viewer_HEADER_FILES
     llinspectgroup.h
     llinspectobject.h
     llinspectremoteobject.h
+    llinspecttexture.h
     llinspecttoast.h
     llinventorybridge.h
     llinventoryfilter.h
     llinventoryfunctions.h
+    llinventorygallery.h
+    llinventorygallerymenu.h
     llinventoryicon.h
     llinventoryitemslist.h
     llinventorylistitem.h
@@ -1359,6 +1366,7 @@ set(viewer_HEADER_FILES
     lltextureinfodetails.h
     lltexturestats.h
     lltextureview.h
+    llthumbnailctrl.h
     lltinygltfhelper.h
     lltoast.h
     lltoastalertpanel.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 44ab07bd62a910ebe186fcee2300d7224d9e054d..d8b4f0a7be016c5ebac999ac6912cd03198c63eb 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -5412,17 +5412,6 @@
         <string>Boolean</string>
         <key>Value</key>
         <integer>0</integer>
-    </map>
-    <key>InventoryInboxToggleState</key>
-    <map>
-        <key>Comment</key>
-        <string>Stores the open/closed state of inventory Received items panel</string>
-        <key>Persist</key>
-        <integer>1</integer>
-        <key>Type</key>
-        <string>Boolean</string>
-        <key>Value</key>
-        <integer>0</integer>
     </map>
 	<key>InventoryLinking</key>
 	<map>
@@ -16146,6 +16135,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>BatchSizeAIS3</key>
+    <map>
+        <key>Comment</key>
+        <string>Amount of folder ais packs into category subset request</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+        <string>S32</string>
+        <key>Value</key>
+        <integer>20</integer>
+    </map>
     <key>PoolSizeAIS</key>
         <map>
         <key>Comment</key>
@@ -16153,7 +16153,7 @@
         <key>Type</key>
             <string>U32</string>
         <key>Value</key>
-            <integer>1</integer>
+            <integer>20</integer>
         </map>
     <key>PoolSizeUpload</key>
         <map>
@@ -17969,6 +17969,17 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
+  <key>FindOriginalOpenWindow</key>
+  <map>
+    <key>Comment</key>
+    <string>Sets the action for 'Find original' and 'Show in Inventory' (0 - shows item in main Inventory, 1 - opens a new single-folder window)</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
   <key>StatsReportMaxDuration</key>
   <map>
     <key>Comment</key>
@@ -18002,5 +18013,27 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
+<key>MultiModeDoubleClickFolder</key>
+<map>
+  <key>Comment</key>
+  <string>Sets the action for Double-click on folder in multi-folder view (0 - expands and collapses folder, 1 - opens a new window, 2 – stays in current floater but switches to SFV)</string>
+  <key>Persist</key>
+  <integer>1</integer>
+  <key>Type</key>
+  <string>U32</string>
+  <key>Value</key>
+  <integer>0</integer>
+</map>
+<key>SingleModeDoubleClickOpenWindow</key>
+<map>
+  <key>Comment</key>
+  <string>Sets the action for Double-click on folder in single-folder view (0 - stays in current window, 1 - opens a new window)</string>
+  <key>Persist</key>
+  <integer>1</integer>
+  <key>Type</key>
+  <string>Boolean</string>
+  <key>Value</key>
+  <integer>0</integer>
+</map>
 </map>
 </llsd>
diff --git a/indra/newview/app_settings/settings_alchemy.xml b/indra/newview/app_settings/settings_alchemy.xml
index 1949442391a9bfc35cd7e5e5f7afa9958dc45443..daf25605b64eb5db16a02b71c27fa96b68312f26 100644
--- a/indra/newview/app_settings/settings_alchemy.xml
+++ b/indra/newview/app_settings/settings_alchemy.xml
@@ -1344,17 +1344,6 @@
       <key>Value</key>
       <boolean>1</boolean>
     </map>
-    <key>ShowPropertiesFloaters</key>
-    <map>
-      <key>Comment</key>
-      <string>Shows item properties in a floater rather than the sidebar</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <boolean>1</boolean>
-    </map>
     <key>ShowStatusBarFPS</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 53c7f933c8e8533b1afd1b15401914f48ea30d7c..86f08b8e1c757ed843279de4c2fa1f6dc81d91fb 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -130,8 +130,7 @@ const F32 MAX_FIDGET_TIME = 20.f; // seconds
 
 const S32 UI_FEATURE_VERSION = 1;
 // For version 1: 1 - inventory, 2 - gltf
-// Will need to change to 3 once either inventory or gltf releases and cause a conflict
-const S32 UI_FEATURE_FLAGS = 2;
+const S32 UI_FEATURE_FLAGS = 3;
 
 // The agent instance.
 LLAgent gAgent;
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index c8821f7ff582e727f190a0ab41399319a44a014f..ea70bf7d007877163ae65ce9dc0634a83a705fa5 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -2010,7 +2010,7 @@ bool LLAgentWearables::moveWearable(const LLViewerInventoryItem* item, bool clos
 }
 
 // static
-void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, const LLUUID& parent_id)
+void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, const LLUUID& parent_id, std::function<void(const LLUUID&)> created_cb)
 {
 	if (type == LLWearableType::WT_INVALID || type == LLWearableType::WT_NONE) return;
 
@@ -2022,7 +2022,7 @@ void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, con
 
 	LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);
 	LLAssetType::EType asset_type = wearable->getAssetType();
-	LLPointer<LLInventoryCallback> cb;
+	LLPointer<LLBoostFuncInventoryCallback> cb;
 	if(wear)
 	{
 		cb = new LLBoostFuncInventoryCallback(wear_and_edit_cb);
@@ -2031,6 +2031,10 @@ void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, con
 	{
 		cb = new LLBoostFuncInventoryCallback(wear_cb);
 	}
+    if (created_cb != NULL)
+    {
+        cb->addOnFireFunc(created_cb);
+    }
 
 	LLUUID folder_id;
 
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index 317fd669b50d0d57b4de930044c9ca06b66f5d6a..20de8895c72217a56bafa9b9a0799376c52b7d01 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -144,7 +144,7 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable
 	//--------------------------------------------------------------------
 
 public:
-	static void		createWearable(LLWearableType::EType type, bool wear = false, const LLUUID& parent_id = LLUUID::null);
+	static void		createWearable(LLWearableType::EType type, bool wear = false, const LLUUID& parent_id = LLUUID::null, std::function<void(const LLUUID&)> created_cb = NULL);
 	static void		editWearable(const LLUUID& item_id);
 	bool			moveWearable(const LLViewerInventoryItem* item, bool closer_to_body);
 
diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp
index 5ad1da776f55029d5b81ede15f43dbb04d21d009..97356fd00921571cc005cd748de7ad4b07e00b65 100644
--- a/indra/newview/llaisapi.cpp
+++ b/indra/newview/llaisapi.cpp
@@ -29,11 +29,15 @@
 #include "llaisapi.h"
 
 #include "llagent.h"
+#include "llappviewer.h"
 #include "llcallbacklist.h"
 #include "llinventorymodel.h"
+#include "llinventoryobserver.h"
+#include "llnotificationsutil.h"
 #include "llsdutil.h"
 #include "llviewerregion.h"
-#include "llinventoryobserver.h"
+#include "llvoavatar.h"
+#include "llvoavatarself.h"
 #include "llviewercontrol.h"
 
 ///----------------------------------------------------------------------------
@@ -43,11 +47,16 @@
 //=========================================================================
 const std::string AISAPI::INVENTORY_CAP_NAME("InventoryAPIv3");
 const std::string AISAPI::LIBRARY_CAP_NAME("LibraryAPIv3");
+const S32 AISAPI::HTTP_TIMEOUT = 180;
 
 std::list<AISAPI::ais_query_item_t> AISAPI::sPostponedQuery;
 
 const S32 MAX_SIMULTANEOUS_COROUTINES = 2048;
 
+// AIS3 allows '*' requests, but in reality those will be cut at some point
+// Specify own depth to be able to anticipate it and mark folders as incomplete
+const S32 MAX_FOLDER_DEPTH_REQUEST = 50;
+
 //-------------------------------------------------------------------------
 /*static*/
 bool AISAPI::isAvailable()
@@ -93,6 +102,10 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c
     if (cap.empty())
     {
         LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
         return;
     }
 
@@ -100,7 +113,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c
     tid.generate();
 
     std::string url = cap + std::string("/category/") + parentId.asString() + "?tid=" + tid.asString();
-    LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+    LL_DEBUGS("Inventory") << "url: " << url << " parentID " << parentId << " newInventory " << newInventory << LL_ENDL;
 
     // I may be suffering from golden hammer here, but the first part of this bind 
     // is actually a static cast for &HttpCoroutineAdapter::postAndSuspend so that 
@@ -124,7 +137,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c
         (&LLCoreHttpUtil::HttpCoroutineAdapter::postAndSuspend), _1, _2, _3, _4, _5, _6);
 
     LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
-        _1, postFn, url, parentId, newInventory, callback, COPYINVENTORY));
+        _1, postFn, url, parentId, newInventory, callback, CREATEINVENTORY));
     EnqueueAISCommand("CreateInventory", proc);
 }
 
@@ -135,6 +148,10 @@ void AISAPI::SlamFolder(const LLUUID& folderId, const LLSD& newInventory, comple
     if (cap.empty())
     {
         LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
         return;
     }
 
@@ -170,6 +187,10 @@ void AISAPI::RemoveCategory(const LLUUID &categoryId, completion_t callback)
     if (cap.empty())
     {
         LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
         return;
     }
 
@@ -203,6 +224,10 @@ void AISAPI::RemoveItem(const LLUUID &itemId, completion_t callback)
     if (cap.empty())
     {
         LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
         return;
     }
 
@@ -235,6 +260,10 @@ void AISAPI::CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, b
     if (cap.empty())
     {
         LL_WARNS("Inventory") << "Library cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
         return;
     }
 
@@ -279,6 +308,10 @@ void AISAPI::PurgeDescendents(const LLUUID &categoryId, completion_t callback)
     if (cap.empty())
     {
         LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
         return;
     }
 
@@ -313,6 +346,10 @@ void AISAPI::UpdateCategory(const LLUUID &categoryId, const LLSD &updates, compl
     if (cap.empty())
     {
         LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
         return;
     }
     std::string url = cap + std::string("/category/") + categoryId.asString();
@@ -345,6 +382,10 @@ void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t
     if (cap.empty())
     {
         LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
         return;
     }
     std::string url = cap + std::string("/item/") + itemId.asString();
@@ -367,6 +408,380 @@ void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t
     EnqueueAISCommand("UpdateItem", proc);
 }
 
+/*static*/
+void AISAPI::FetchItem(const LLUUID &itemId, ITEM_TYPE type, completion_t callback)
+{
+	std::string cap;
+
+	cap = (type == INVENTORY) ? getInvCap() : getLibCap();
+	if (cap.empty())
+	{
+		LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
+		return;
+	}
+	std::string url = cap + std::string("/item/") + itemId.asString();
+
+	invokationFn_t getFn = boost::bind(
+		// Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+		static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+		//----
+		// _1 -> httpAdapter
+		// _2 -> httpRequest
+		// _3 -> url
+		// _4 -> body 
+		// _5 -> httpOptions
+		// _6 -> httpHeaders
+		(&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+	LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+		_1, getFn, url, itemId, LLSD(), callback, FETCHITEM));
+
+	EnqueueAISCommand("FetchItem", proc);
+}
+
+/*static*/
+void AISAPI::FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type, bool recursive, completion_t callback, S32 depth)
+{
+    std::string cap;
+
+    cap = (type == INVENTORY) ? getInvCap() : getLibCap();
+    if (cap.empty())
+    {
+        LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
+        return;
+    }
+    std::string url = cap + std::string("/category/") + catId.asString() + "/children";
+
+    if (recursive)
+    {
+        // can specify depth=*, but server side is going to cap requests
+        // and reject everything 'over the top',.
+        depth = MAX_FOLDER_DEPTH_REQUEST;
+    }
+    else
+    {
+        depth = llmin(depth, MAX_FOLDER_DEPTH_REQUEST);
+    }
+
+    url += "?depth=" + std::to_string(depth);
+
+    invokationFn_t getFn = boost::bind(
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+        static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+        //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
+        (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+    // get doesn't use body, can pass additional data
+    LLSD body;
+    body["depth"] = depth;
+    LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+        _1, getFn, url, catId, body, callback, FETCHCATEGORYCHILDREN));
+
+    EnqueueAISCommand("FetchCategoryChildren", proc);
+}
+
+// some folders can be requested by name, like
+// animatn | bodypart | clothing | current | favorite | gesture | inbox | landmark | lsltext
+// lstndfnd | my_otfts | notecard | object | outbox | root | snapshot | sound | texture | trash
+void AISAPI::FetchCategoryChildren(const std::string &identifier, bool recursive, completion_t callback, S32 depth)
+{
+    std::string cap;
+
+    cap = getInvCap();
+    if (cap.empty())
+    {
+        LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
+        return;
+    }
+    std::string url = cap + std::string("/category/") + identifier + "/children";
+
+    if (recursive)
+    {
+        // can specify depth=*, but server side is going to cap requests
+        // and reject everything 'over the top',.
+        depth = MAX_FOLDER_DEPTH_REQUEST;
+    }
+    else
+    {
+        depth = llmin(depth, MAX_FOLDER_DEPTH_REQUEST);
+    }
+
+    url += "?depth=" + std::to_string(depth);
+
+    invokationFn_t getFn = boost::bind(
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+        static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+        //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
+        (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+    // get doesn't use body, can pass additional data
+    LLSD body;
+    body["depth"] = depth;
+    LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+        _1, getFn, url, LLUUID::null, body, callback, FETCHCATEGORYCHILDREN));
+
+    EnqueueAISCommand("FetchCategoryChildren", proc);
+}
+
+/*static*/
+void AISAPI::FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type, bool recursive, completion_t callback, S32 depth)
+{
+    std::string cap;
+
+    cap = (type == INVENTORY) ? getInvCap() : getLibCap();
+    if (cap.empty())
+    {
+        LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
+        return;
+    }
+    std::string url = cap + std::string("/category/") + catId.asString() + "/categories";
+
+    if (recursive)
+    {
+        // can specify depth=*, but server side is going to cap requests
+        // and reject everything 'over the top',.
+        depth = MAX_FOLDER_DEPTH_REQUEST;
+    }
+    else
+    {
+        depth = llmin(depth, MAX_FOLDER_DEPTH_REQUEST);
+    }
+
+    url += "?depth=" + std::to_string(depth);
+
+    invokationFn_t getFn = boost::bind(
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+        static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+        //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
+        (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+    // get doesn't use body, can pass additional data
+    LLSD body;
+    body["depth"] = depth;
+    LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+        _1, getFn, url, catId, body, callback, FETCHCATEGORYCATEGORIES));
+
+    EnqueueAISCommand("FetchCategoryCategories", proc);
+}
+
+void AISAPI::FetchCategorySubset(const LLUUID& catId,
+                                   const uuid_vec_t specificChildren,
+                                   ITEM_TYPE type,
+                                   bool recursive,
+                                   completion_t callback,
+                                   S32 depth)
+{
+    std::string cap = (type == INVENTORY) ? getInvCap() : getLibCap();
+    if (cap.empty())
+    {
+        LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
+        return;
+    }
+    if (specificChildren.empty())
+    {
+        LL_WARNS("Inventory") << "Empty request!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
+        return;
+    }
+    // category/any_folder_id/children?depth=*&children=child_id1,child_id2,child_id3
+    std::string url = cap + std::string("/category/") + catId.asString() + "/children";
+
+    if (recursive)
+    {
+        depth = MAX_FOLDER_DEPTH_REQUEST;
+    }
+    else
+    {
+        depth = llmin(depth, MAX_FOLDER_DEPTH_REQUEST);
+    }
+
+    uuid_vec_t::const_iterator iter = specificChildren.begin();
+    uuid_vec_t::const_iterator end = specificChildren.end();
+
+    url += "?depth=" + std::to_string(depth) + "&children=" + iter->asString();
+    iter++;
+
+    while (iter != end)
+    {
+        url += "," + iter->asString();
+        iter++;
+    }
+
+    const S32 MAX_URL_LENGH = 2000; // RFC documentation specifies a maximum length of 2048
+    if (url.length() > MAX_URL_LENGH)
+    {
+        LL_WARNS("Inventory") << "Request url is too long, url: " << url << LL_ENDL;
+    }
+
+    invokationFn_t getFn = boost::bind(
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+        static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string&, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+        //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
+        (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+    // get doesn't use body, can pass additional data
+    LLSD body;
+    body["depth"] = depth;
+    LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+                                                         _1, getFn, url, catId, body, callback, FETCHCATEGORYSUBSET));
+
+    EnqueueAISCommand("FetchCategorySubset", proc);
+}
+
+/*static*/
+// Will get COF folder, links in it and items those links point to
+void AISAPI::FetchCOF(completion_t callback)
+{
+    std::string cap = getInvCap();
+    if (cap.empty())
+    {
+        LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
+        return;
+    }
+    std::string url = cap + std::string("/category/current/links");
+
+    invokationFn_t getFn = boost::bind(
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+        static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string&, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+        //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
+        (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+    LLSD body;
+    // Only cof folder will be full, but cof can contain an outfit
+    // link with embedded outfit folder for request to parse
+    body["depth"] = 0;
+    LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+                                                         _1, getFn, url, LLUUID::null, body, callback, FETCHCOF));
+
+    EnqueueAISCommand("FetchCOF", proc);
+}
+
+void AISAPI::FetchCategoryLinks(const LLUUID &catId, completion_t callback)
+{
+    std::string cap = getInvCap();
+    if (cap.empty())
+    {
+        LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
+        return;
+    }
+    std::string url = cap + std::string("/category/") + catId.asString() + "/links";
+
+    invokationFn_t getFn = boost::bind(
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+        static_cast<LLSD (LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &,
+                                                                   LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+        //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
+        (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend),
+        _1, _2, _3, _5, _6);
+
+    LLSD body;
+    body["depth"] = 0;
+    LLCoprocedureManager::CoProcedure_t proc(
+        boost::bind(&AISAPI::InvokeAISCommandCoro, _1, getFn, url, LLUUID::null, body, callback, FETCHCATEGORYLINKS));
+
+    EnqueueAISCommand("FetchCategoryLinks", proc);
+}
+
+/*static*/
+void AISAPI::FetchOrphans(completion_t callback)
+{
+    std::string cap = getInvCap();
+    if (cap.empty())
+    {
+        LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
+        return;
+    }
+    std::string url = cap + std::string("/orphans");
+
+    invokationFn_t getFn = boost::bind(
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+        static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t , const std::string& , LLCore::HttpOptions::ptr_t , LLCore::HttpHeaders::ptr_t)>
+        //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
+        (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend) , _1 , _2 , _3 , _5 , _6);
+
+    LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro ,
+                                                         _1 , getFn , url , LLUUID::null , LLSD() , callback , FETCHORPHANS));
+
+    EnqueueAISCommand("FetchOrphans" , proc);
+}
+
 /*static*/
 void AISAPI::EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc)
 {
@@ -417,22 +832,50 @@ void AISAPI::onIdle(void *userdata)
     }
 }
 
+/*static*/
+void AISAPI::onUpdateReceived(const LLSD& update, COMMAND_TYPE type, const LLSD& request_body)
+{
+    LLTimer timer;
+    if ( (type == UPDATECATEGORY || type == UPDATEITEM)
+        && gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+    {
+        dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
+    }
+
+    AISUpdate ais_update(update, type, request_body);
+    ais_update.doUpdate(); // execute the updates in the appropriate order.
+    LL_DEBUGS("Inventory", "AIS3") << "Elapsed processing: " << timer.getElapsedTimeF32() << LL_ENDL;
+}
+
 /*static*/
 void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter, 
         invokationFn_t invoke, std::string url, 
         LLUUID targetId, LLSD body, completion_t callback, COMMAND_TYPE type)
 {
+    if (gDisconnected)
+    {
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
+        return;
+    }
+
     LLCore::HttpOptions::ptr_t httpOptions(std::make_shared<LLCore::HttpOptions>());
     LLCore::HttpRequest::ptr_t httpRequest(std::make_shared<LLCore::HttpRequest>());
     LLCore::HttpHeaders::ptr_t httpHeaders;
 
-    httpOptions->setTimeout(LLCoreHttpUtil::HTTP_REQUEST_EXPIRY_SECS);
+    httpOptions->setTimeout(HTTP_TIMEOUT);
 
-    LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+    LL_DEBUGS("Inventory") << "Request url: " << url << LL_ENDL;
+
+    LLSD result;
+    LLSD httpResults;
+    LLCore::HttpStatus status;
 
-    LLSD result = invoke(httpAdapter, httpRequest, url, body, httpOptions, httpHeaders);
-    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
-    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+    result = invoke(httpAdapter , httpRequest , url , body , httpOptions , httpHeaders);
+    httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+    status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
 
     if (!status || !result.isMap())
     {
@@ -474,14 +917,43 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
                 }
             }
         }
+        else if (status == LLCore::HttpStatus(HTTP_FORBIDDEN) /*403*/)
+        {
+            if (type == FETCHCATEGORYCHILDREN)
+            {
+                if (body.has("depth") && body["depth"].asInteger() == 0)
+                {
+                    // Can't fetch a single folder with depth 0, folder is too big.
+                    static bool first_call = true;
+                    if (first_call)
+                    {
+                        first_call = false;
+                        LLNotificationsUtil::add("InventoryLimitReachedAISAlert");
+                    }
+                    else
+                    {
+                        LLNotificationsUtil::add("InventoryLimitReachedAIS");
+                    }
+                    LL_WARNS("Inventory") << "Fetch failed, content is over limit, url: " << url << LL_ENDL;
+                }
+                else
+                {
+                    // Result was too big, but situation is recoverable by requesting with lower depth
+                    LL_DEBUGS("Inventory") << "Fetch failed, content is over limit, url: " << url << LL_ENDL;
+                }
+            }
+        }
         LL_WARNS("Inventory") << "Inventory error: " << status.toString() << LL_ENDL;
         LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL;
     }
 
-    gInventory.onAISUpdateReceived("AISCommand", result);
+	LL_DEBUGS("Inventory", "AIS3") << "Result: " << result << LL_ENDL;
+    onUpdateReceived(result, type, body);
 
     if (callback && !callback.empty())
     {   
+// ALCHMERGE
+#if 0
 // [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7
 		uuid_list_t ids;
 		switch (type)
@@ -520,13 +992,94 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
 //	    }
 //
 //        callback(id);
+#else
+        bool needs_callback = true;
+        LLUUID id(LLUUID::null);
+
+        switch (type)
+        {
+        case COPYLIBRARYCATEGORY:
+        case FETCHCATEGORYCATEGORIES:
+        case FETCHCATEGORYCHILDREN:
+        case FETCHCATEGORYSUBSET:
+        case FETCHCATEGORYLINKS:
+        case FETCHCOF:
+            if (result.has("category_id"))
+            {
+                id = result["category_id"];
+            }
+            break;
+        case FETCHITEM:
+            if (result.has("item_id"))
+            {
+                // Error message might contain an item_id!!!
+                id = result["item_id"];
+            }
+            if (result.has("linked_id"))
+            {
+                id = result["linked_id"];
+            }
+            break;
+        case CREATEINVENTORY:
+            // CREATEINVENTORY can have multiple callbacks
+            if (result.has("_created_categories"))
+            {
+                LLSD& cats = result["_created_categories"];
+                LLSD::array_const_iterator cat_iter;
+                for (cat_iter = cats.beginArray(); cat_iter != cats.endArray(); ++cat_iter)
+                {
+                    LLUUID cat_id = *cat_iter;
+                    callback(cat_id);
+                    needs_callback = false;
+                }
+            }
+            if (result.has("_created_items"))
+            {
+                LLSD& items = result["_created_items"];
+                LLSD::array_const_iterator item_iter;
+                for (item_iter = items.beginArray(); item_iter != items.endArray(); ++item_iter)
+                {
+                    LLUUID item_id = *item_iter;
+                    callback(item_id);
+                    needs_callback = false;
+                }
+            }
+            break;
+        default:
+            break;
+        }
+
+        if (needs_callback)
+        {
+            // Call callback at least once regardless of failure.
+            // UPDATEITEM doesn't expect an id
+            callback(id);
+        }
+#endif
     }
 
 }
 
 //-------------------------------------------------------------------------
-AISUpdate::AISUpdate(const LLSD& update)
+AISUpdate::AISUpdate(const LLSD& update, AISAPI::COMMAND_TYPE type, const LLSD& request_body)
+: mType(type)
 {
+    mFetch = (type == AISAPI::FETCHITEM)
+        || (type == AISAPI::FETCHCATEGORYCHILDREN)
+        || (type == AISAPI::FETCHCATEGORYCATEGORIES)
+        || (type == AISAPI::FETCHCATEGORYSUBSET)
+        || (type == AISAPI::FETCHCOF)
+        || (type == AISAPI::FETCHCATEGORYLINKS)
+        || (type == AISAPI::FETCHORPHANS);
+    // parse update llsd into stuff to do or parse received items.
+    mFetchDepth = MAX_FOLDER_DEPTH_REQUEST;
+    if (mFetch && request_body.has("depth"))
+    {
+        mFetchDepth = request_body["depth"].asInteger();
+    }
+
+    mTimer.setTimerExpirySec(AIS_EXPIRY_SECONDS);
+    mTimer.start();
 	parseUpdate(update);
 }
 
@@ -536,6 +1089,7 @@ void AISUpdate::clearParseResults()
 	mCatDescendentsKnown.clear();
 	mCatVersionsUpdated.clear();
 	mItemsCreated.clear();
+    mItemsLost.clear();
 	mItemsUpdated.clear();
 	mCategoriesCreated.clear();
 	mCategoriesUpdated.clear();
@@ -544,6 +1098,16 @@ void AISUpdate::clearParseResults()
 	mCategoryIds.clear();
 }
 
+void AISUpdate::checkTimeout()
+{
+    if (mTimer.hasExpired())
+    {
+        llcoro::suspend();
+        LLCoros::checkStop();
+        mTimer.setTimerExpirySec(AIS_EXPIRY_SECONDS);
+    }
+}
+
 void AISUpdate::parseUpdate(const LLSD& update)
 {
 	clearParseResults();
@@ -631,24 +1195,37 @@ void AISUpdate::parseMeta(const LLSD& update)
 
 void AISUpdate::parseContent(const LLSD& update)
 {
-	if (update.has("linked_id"))
+    // Errors from a fetch request might contain id without
+    // full item or folder.
+    // Todo: Depending on error we might want to do something,
+    // like removing a 404 item or refetching parent folder
+	if (update.has("linked_id") && update.has("parent_id"))
 	{
-		parseLink(update);
+		parseLink(update, mFetchDepth);
 	}
-	else if (update.has("item_id"))
+	else if (update.has("item_id") && update.has("parent_id"))
 	{
 		parseItem(update);
 	}
 
-	if (update.has("category_id"))
-	{
-		parseCategory(update);
-	}
+    if (mType == AISAPI::FETCHCATEGORYSUBSET)
+    {
+        // initial category is incomplete, don't process it,
+        // go for content instead
+        if (update.has("_embedded"))
+        {
+            parseEmbedded(update["_embedded"], mFetchDepth - 1);
+        }
+    }
+    else if (update.has("category_id") && update.has("parent_id"))
+    {
+        parseCategory(update, mFetchDepth);
+    }
 	else
 	{
 		if (update.has("_embedded"))
 		{
-			parseEmbedded(update["_embedded"]);
+			parseEmbedded(update["_embedded"], mFetchDepth);
 		}
 	}
 }
@@ -666,7 +1243,17 @@ void AISUpdate::parseItem(const LLSD& item_map)
 	BOOL rv = new_item->unpackMessage(item_map);
 	if (rv)
 	{
-		if (curr_item)
+        if (mFetch)
+        {
+            mItemsCreated[item_id] = new_item;
+            new_item->setComplete(true);
+
+            if (new_item->getParentUUID().isNull())
+            {
+                mItemsLost[item_id] = new_item;
+            }
+        }
+        else if (curr_item)
 		{
 			mItemsUpdated[item_id] = new_item;
 			// This statement is here to cause a new entry with 0
@@ -678,6 +1265,7 @@ void AISUpdate::parseItem(const LLSD& item_map)
 		{
 			mItemsCreated[item_id] = new_item;
 			mCatDescendentDeltas[new_item->getParentUUID()]++;
+            new_item->setComplete(true);
 		}
 	}
 	else
@@ -687,7 +1275,7 @@ void AISUpdate::parseItem(const LLSD& item_map)
 	}
 }
 
-void AISUpdate::parseLink(const LLSD& link_map)
+void AISUpdate::parseLink(const LLSD& link_map, S32 depth)
 {
 	LLUUID item_id = link_map["item_id"].asUUID();
 	LLPointer<LLViewerInventoryItem> new_link(new LLViewerInventoryItem);
@@ -701,7 +1289,24 @@ void AISUpdate::parseLink(const LLSD& link_map)
 	if (rv)
 	{
 		const LLUUID& parent_id = new_link->getParentUUID();
-		if (curr_link)
+        if (mFetch)
+        {
+            LLPermissions default_perms;
+            default_perms.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
+            default_perms.initMasks(PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE);
+            new_link->setPermissions(default_perms);
+            LLSaleInfo default_sale_info;
+            new_link->setSaleInfo(default_sale_info);
+            //LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL;
+            mItemsCreated[item_id] = new_link;
+            new_link->setComplete(true);
+
+            if (new_link->getParentUUID().isNull())
+            {
+                mItemsLost[item_id] = new_link;
+            }
+        }
+		else if (curr_link)
 		{
 			mItemsUpdated[item_id] = new_link;
 			// This statement is here to cause a new entry with 0
@@ -720,7 +1325,13 @@ void AISUpdate::parseLink(const LLSD& link_map)
 			//LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL;
 			mItemsCreated[item_id] = new_link;
 			mCatDescendentDeltas[parent_id]++;
+            new_link->setComplete(true);
 		}
+
+        if (link_map.has("_embedded"))
+        {
+            parseEmbedded(link_map["_embedded"], depth);
+        }
 	}
 	else
 	{
@@ -730,19 +1341,30 @@ void AISUpdate::parseLink(const LLSD& link_map)
 }
 
 
-void AISUpdate::parseCategory(const LLSD& category_map)
+void AISUpdate::parseCategory(const LLSD& category_map, S32 depth)
 {
-	LLUUID category_id = category_map["category_id"].asUUID();
+    LLUUID category_id = category_map["category_id"].asUUID();
+    S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN;
 
-	// Check descendent count first, as it may be needed
-	// to populate newly created categories
-	if (category_map.has("_embedded"))
-	{
-		parseDescendentCount(category_id, category_map["_embedded"]);
-	}
+    if (category_map.has("version"))
+    {
+        version = category_map["version"].asInteger();
+    }
+
+    LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id);
+
+    if (curr_cat
+        && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN
+        && curr_cat->getDescendentCount() != LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN
+        && version > LLViewerInventoryCategory::VERSION_UNKNOWN
+        && version < curr_cat->getVersion())
+    {
+        LL_WARNS() << "Got stale folder, known: " << curr_cat->getVersion()
+            << ", received: " << version << LL_ENDL;
+        return;
+    }
 
 	LLPointer<LLViewerInventoryCategory> new_cat;
-	LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id);
 	if (curr_cat)
 	{
 		// Default to current values where not provided.
@@ -762,13 +1384,58 @@ void AISUpdate::parseCategory(const LLSD& category_map)
     }
 	BOOL rv = new_cat->unpackMessage(category_map);
 	// *NOTE: unpackMessage does not unpack version or descendent count.
-	//if (category_map.has("version"))
-	//{
-	//	mCatVersionsUpdated[category_id] = category_map["version"].asInteger();
-	//}
 	if (rv)
 	{
-		if (curr_cat)
+        // Check descendent count first, as it may be needed
+        // to populate newly created categories
+        if (category_map.has("_embedded"))
+        {
+            parseDescendentCount(category_id, new_cat->getPreferredType(), category_map["_embedded"]);
+        }
+
+        if (mFetch)
+        {
+            uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id);
+            if (mCatDescendentsKnown.end() != lookup_it)
+            {
+                S32 descendent_count = lookup_it->second;
+                LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count
+                    << " for category " << category_id << LL_ENDL;
+                new_cat->setDescendentCount(descendent_count);
+
+                // set version only if we are sure this update has full data and embeded items
+                // since viewer uses version to decide if folder and content still need fetching
+                if (version > LLViewerInventoryCategory::VERSION_UNKNOWN
+                    && depth >= 0)
+                {
+                    if (curr_cat && curr_cat->getVersion() > version)
+                    {
+                        LL_WARNS("Inventory") << "Version was " << curr_cat->getVersion()
+                            << ", but fetch returned version " << version
+                            << " for category " << category_id << LL_ENDL;
+                    }
+                    else
+                    {
+                        LL_DEBUGS("Inventory") << "Setting version to " << version
+                            << " for category " << category_id << LL_ENDL;
+                    }
+
+                    new_cat->setVersion(version);
+                }
+            }
+            else if (curr_cat
+                     && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN
+                     && version > curr_cat->getVersion())
+            {
+                // Potentially should new_cat->setVersion(unknown) here,
+                // but might be waiting for a callback that would increment
+                LL_DEBUGS("Inventory") << "Category " << category_id
+                    << " is stale. Known version: " << curr_cat->getVersion()
+                    << " server version: " << version << LL_ENDL;
+            }
+            mCategoriesCreated[category_id] = new_cat;
+        }
+		else if (curr_cat)
 		{
 			mCategoriesUpdated[category_id] = new_cat;
 			// This statement is here to cause a new entry with 0
@@ -781,20 +1448,22 @@ void AISUpdate::parseCategory(const LLSD& category_map)
 		else
 		{
 			// Set version/descendents for newly created categories.
-			if (category_map.has("version"))
-			{
-				S32 version = category_map["version"].asInteger();
-				LL_DEBUGS("Inventory") << "Setting version to " << version
-									   << " for new category " << category_id << LL_ENDL;
-				new_cat->setVersion(version);
-			}
-			uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id);
-			if (mCatDescendentsKnown.end() != lookup_it)
-			{
-				S32 descendent_count = lookup_it->second;
-				LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count 
-									   << " for new category " << category_id << LL_ENDL;
-				new_cat->setDescendentCount(descendent_count);
+            uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id);
+            if (mCatDescendentsKnown.end() != lookup_it)
+            {
+                S32 descendent_count = lookup_it->second;
+                LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count
+                    << " for new category " << category_id << LL_ENDL;
+                new_cat->setDescendentCount(descendent_count);
+
+                // Don't set version unles correct children count is present
+                if (category_map.has("version"))
+                {
+                    S32 version = category_map["version"].asInteger();
+                    LL_DEBUGS("Inventory") << "Setting version to " << version
+                        << " for new category " << category_id << LL_ENDL;
+                    new_cat->setVersion(version);
+                }
 			}
 			mCategoriesCreated[category_id] = new_cat;
 			mCatDescendentDeltas[new_cat->getParentUUID()]++;
@@ -809,28 +1478,35 @@ void AISUpdate::parseCategory(const LLSD& category_map)
 	// Check for more embedded content.
 	if (category_map.has("_embedded"))
 	{
-		parseEmbedded(category_map["_embedded"]);
+		parseEmbedded(category_map["_embedded"], depth - 1);
 	}
 }
 
-void AISUpdate::parseDescendentCount(const LLUUID& category_id, const LLSD& embedded)
+void AISUpdate::parseDescendentCount(const LLUUID& category_id, LLFolderType::EType type, const LLSD& embedded)
 {
-	// We can only determine true descendent count if this contains all descendent types.
-	if (embedded.has("categories") &&
-		embedded.has("links") &&
-		embedded.has("items"))
-	{
-		mCatDescendentsKnown[category_id]  = embedded["categories"].size();
-		mCatDescendentsKnown[category_id] += embedded["links"].size();
-		mCatDescendentsKnown[category_id] += embedded["items"].size();
-	}
+    // We can only determine true descendent count if this contains all descendent types.
+    if (embedded.has("categories") &&
+        embedded.has("links") &&
+        embedded.has("items"))
+    {
+        mCatDescendentsKnown[category_id] = embedded["categories"].size();
+        mCatDescendentsKnown[category_id] += embedded["links"].size();
+        mCatDescendentsKnown[category_id] += embedded["items"].size();
+    }
+    else if (mFetch && embedded.has("links") && (type == LLFolderType::FT_CURRENT_OUTFIT || type == LLFolderType::FT_OUTFIT))
+    {
+        // COF and outfits contain links only
+        mCatDescendentsKnown[category_id] = embedded["links"].size();
+    }
 }
 
-void AISUpdate::parseEmbedded(const LLSD& embedded)
+void AISUpdate::parseEmbedded(const LLSD& embedded, S32 depth)
 {
+    checkTimeout();
+
 	if (embedded.has("links")) // _embedded in a category
 	{
-		parseEmbeddedLinks(embedded["links"]);
+		parseEmbeddedLinks(embedded["links"], depth);
 	}
 	if (embedded.has("items")) // _embedded in a category
 	{
@@ -842,11 +1518,11 @@ void AISUpdate::parseEmbedded(const LLSD& embedded)
 	}
 	if (embedded.has("categories")) // _embedded in a category
 	{
-		parseEmbeddedCategories(embedded["categories"]);
+		parseEmbeddedCategories(embedded["categories"], depth);
 	}
 	if (embedded.has("category")) // _embedded in a link
 	{
-		parseEmbeddedCategory(embedded["category"]);
+		parseEmbeddedCategory(embedded["category"], depth);
 	}
 }
 
@@ -863,7 +1539,7 @@ void AISUpdate::parseUUIDArray(const LLSD& content, const std::string& name, uui
 	}
 }
 
-void AISUpdate::parseEmbeddedLinks(const LLSD& links)
+void AISUpdate::parseEmbeddedLinks(const LLSD& links, S32 depth)
 {
 	for(LLSD::map_const_iterator linkit = links.beginMap(),
 			linkend = links.endMap();
@@ -871,13 +1547,13 @@ void AISUpdate::parseEmbeddedLinks(const LLSD& links)
 	{
 		const LLUUID link_id((*linkit).first);
 		const LLSD& link_map = (*linkit).second;
-		if (mItemIds.end() == mItemIds.find(link_id))
+		if (!mFetch && mItemIds.end() == mItemIds.find(link_id))
 		{
 			LL_DEBUGS("Inventory") << "Ignoring link not in items list " << link_id << LL_ENDL;
 		}
 		else
 		{
-			parseLink(link_map);
+			parseLink(link_map, depth);
 		}
 	}
 }
@@ -887,7 +1563,7 @@ void AISUpdate::parseEmbeddedItem(const LLSD& item)
 	// a single item (_embedded in a link)
 	if (item.has("item_id"))
 	{
-		if (mItemIds.end() != mItemIds.find(item["item_id"].asUUID()))
+		if (mFetch || mItemIds.end() != mItemIds.find(item["item_id"].asUUID()))
 		{
 			parseItem(item);
 		}
@@ -903,7 +1579,7 @@ void AISUpdate::parseEmbeddedItems(const LLSD& items)
 	{
 		const LLUUID item_id((*itemit).first);
 		const LLSD& item_map = (*itemit).second;
-		if (mItemIds.end() == mItemIds.find(item_id))
+		if (!mFetch && mItemIds.end() == mItemIds.find(item_id))
 		{
 			LL_DEBUGS("Inventory") << "Ignoring item not in items list " << item_id << LL_ENDL;
 		}
@@ -914,19 +1590,19 @@ void AISUpdate::parseEmbeddedItems(const LLSD& items)
 	}
 }
 
-void AISUpdate::parseEmbeddedCategory(const LLSD& category)
+void AISUpdate::parseEmbeddedCategory(const LLSD& category, S32 depth)
 {
 	// a single category (_embedded in a link)
 	if (category.has("category_id"))
 	{
-		if (mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID()))
+		if (mFetch || mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID()))
 		{
-			parseCategory(category);
+			parseCategory(category, depth);
 		}
 	}
 }
 
-void AISUpdate::parseEmbeddedCategories(const LLSD& categories)
+void AISUpdate::parseEmbeddedCategories(const LLSD& categories, S32 depth)
 {
 	// a map of categories (_embedded in a category)
 	for(LLSD::map_const_iterator categoryit = categories.beginMap(),
@@ -935,19 +1611,21 @@ void AISUpdate::parseEmbeddedCategories(const LLSD& categories)
 	{
 		const LLUUID category_id((*categoryit).first);
 		const LLSD& category_map = (*categoryit).second;
-		if (mCategoryIds.end() == mCategoryIds.find(category_id))
+		if (!mFetch && mCategoryIds.end() == mCategoryIds.find(category_id))
 		{
 			LL_DEBUGS("Inventory") << "Ignoring category not in categories list " << category_id << LL_ENDL;
 		}
 		else
 		{
-			parseCategory(category_map);
+			parseCategory(category_map, depth);
 		}
 	}
 }
 
 void AISUpdate::doUpdate()
 {
+    checkTimeout();
+
 	// Do version/descendant accounting.
 	for (auto catit = mCatDescendentDeltas.begin();
 		 catit != mCatDescendentDeltas.end(); ++catit)
@@ -991,6 +1669,7 @@ void AISUpdate::doUpdate()
 	}
 
 	// CREATE CATEGORIES
+    const S32 MAX_UPDATE_BACKLOG = 50; // stall prevention
 	for (deferred_category_map_t::const_iterator create_it = mCategoriesCreated.begin();
 		 create_it != mCategoriesCreated.end(); ++create_it)
 	{
@@ -999,6 +1678,13 @@ void AISUpdate::doUpdate()
 
 		gInventory.updateCategory(new_category, LLInventoryObserver::CREATE);
 		LL_DEBUGS("Inventory") << "created category " << category_id << LL_ENDL;
+
+        // fetching can receive massive amount of items and folders
+        if (gInventory.getChangedIDs().size() > MAX_UPDATE_BACKLOG)
+        {
+            gInventory.notifyObservers();
+            checkTimeout();
+        }
 	}
 
 	// UPDATE CATEGORIES
@@ -1023,6 +1709,24 @@ void AISUpdate::doUpdate()
 		}
 	}
 
+    // LOST ITEMS
+    if (!mItemsLost.empty())
+    {
+        LL_INFOS("Inventory") << "Received " << (S32)mItemsLost.size() << " items without a parent" << LL_ENDL;
+        const LLUUID lost_uuid(gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND));
+        if (lost_uuid.notNull())
+        {
+            for (deferred_item_map_t::const_iterator lost_it = mItemsLost.begin();
+                 lost_it != mItemsLost.end(); ++lost_it)
+            {
+                LLPointer<LLViewerInventoryItem> new_item = lost_it->second;
+
+                new_item->setParent(lost_uuid);
+                new_item->updateParentOnServer(FALSE);
+            }
+        }
+    }
+
 	// CREATE ITEMS
 	for (deferred_item_map_t::const_iterator create_it = mItemsCreated.begin();
 		 create_it != mItemsCreated.end(); ++create_it)
@@ -1035,6 +1739,13 @@ void AISUpdate::doUpdate()
 		// case this is create.
 		LL_DEBUGS("Inventory") << "created item " << item_id << LL_ENDL;
 		gInventory.updateItem(new_item, LLInventoryObserver::CREATE);
+
+        // fetching can receive massive amount of items and folders
+        if (gInventory.getChangedIDs().size() > MAX_UPDATE_BACKLOG)
+        {
+            gInventory.notifyObservers();
+            checkTimeout();
+        }
 	}
 	
 	// UPDATE ITEMS
@@ -1095,6 +1806,8 @@ void AISUpdate::doUpdate()
 		}
 	}
 
+    checkTimeout();
+
 	gInventory.notifyObservers();
 }
 
diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h
index 0bfa3d3c41a17f936deec11972609861abc1b13d..f254f21e42a5ae939b966197b3fa57d9d251fcc2 100644
--- a/indra/newview/llaisapi.h
+++ b/indra/newview/llaisapi.h
@@ -38,6 +38,12 @@
 class AISAPI
 {
 public:
+    static const S32 HTTP_TIMEOUT;
+    typedef enum {
+        INVENTORY,
+        LIBRARY
+    } ITEM_TYPE;
+
     typedef boost::function<void(const LLUUID &invItem)>    completion_t;
 
     static bool isAvailable();
@@ -50,9 +56,16 @@ class AISAPI
     static void PurgeDescendents(const LLUUID &categoryId, completion_t callback = completion_t());
     static void UpdateCategory(const LLUUID &categoryId, const LLSD &updates, completion_t callback = completion_t());
     static void UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t callback = completion_t());
+    static void FetchItem(const LLUUID &itemId, ITEM_TYPE type, completion_t callback = completion_t());
+    static void FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
+    static void FetchCategoryChildren(const std::string &identifier, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
+    static void FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
+    static void FetchCategorySubset(const LLUUID& catId, const uuid_vec_t specificChildren, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
+    static void FetchCOF(completion_t callback = completion_t());
+    static void FetchCategoryLinks(const LLUUID &catId, completion_t callback = completion_t());
+    static void FetchOrphans(completion_t callback = completion_t() );
     static void CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback = completion_t());
 
-private:
     typedef enum {
         COPYINVENTORY,
         SLAMFOLDER,
@@ -61,9 +74,18 @@ class AISAPI
         PURGEDESCENDENTS,
         UPDATECATEGORY,
         UPDATEITEM,
-        COPYLIBRARYCATEGORY
+        COPYLIBRARYCATEGORY,
+        CREATEINVENTORY,
+        FETCHITEM,
+        FETCHCATEGORYCHILDREN,
+        FETCHCATEGORYCATEGORIES,
+        FETCHCATEGORYSUBSET,
+        FETCHCOF,
+        FETCHORPHANS,
+        FETCHCATEGORYLINKS
     } COMMAND_TYPE;
 
+private:
     static const std::string INVENTORY_CAP_NAME;
     static const std::string LIBRARY_CAP_NAME;
 
@@ -72,6 +94,7 @@ class AISAPI
 
     static void EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc);
     static void onIdle(void *userdata); // launches postponed AIS commands
+    static void onUpdateReceived(const LLSD& update, COMMAND_TYPE type, const LLSD& request_body);
 
     static std::string getInvCap();
     static std::string getLibCap();
@@ -87,37 +110,40 @@ class AISAPI
 class AISUpdate
 {
 public:
-	AISUpdate(const LLSD& update);
+	AISUpdate(const LLSD& update, AISAPI::COMMAND_TYPE type, const LLSD& request_body);
 	void parseUpdate(const LLSD& update);
 	void parseMeta(const LLSD& update);
 	void parseContent(const LLSD& update);
-// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7
-	static void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
-// [/SL:KB]
-//	void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
-	void parseLink(const LLSD& link_map);
+	void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
+	void parseLink(const LLSD& link_map, S32 depth);
 	void parseItem(const LLSD& link_map);
-	void parseCategory(const LLSD& link_map);
-	void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded);
-	void parseEmbedded(const LLSD& embedded);
-	void parseEmbeddedLinks(const LLSD& links);
+	void parseCategory(const LLSD& link_map, S32 depth);
+	void parseDescendentCount(const LLUUID& category_id, LLFolderType::EType type, const LLSD& embedded);
+	void parseEmbedded(const LLSD& embedded, S32 depth);
+	void parseEmbeddedLinks(const LLSD& links, S32 depth);
 	void parseEmbeddedItems(const LLSD& items);
-	void parseEmbeddedCategories(const LLSD& categories);
+	void parseEmbeddedCategories(const LLSD& categories, S32 depth);
 	void parseEmbeddedItem(const LLSD& item);
-	void parseEmbeddedCategory(const LLSD& category);
+	void parseEmbeddedCategory(const LLSD& category, S32 depth);
 	void doUpdate();
 private:
 	void clearParseResults();
+    void checkTimeout();
+
+    // Fetch can return large packets of data, throttle it to not cause lags
+    // Todo: make throttle work over all fetch requests isntead of per-request
+    const F32 AIS_EXPIRY_SECONDS = 0.008f;
 
-	typedef boost::unordered_map<LLUUID,S32> uuid_int_map_t;
+	typedef std::map<LLUUID,S32> uuid_int_map_t;
 	uuid_int_map_t mCatDescendentDeltas;
 	uuid_int_map_t mCatDescendentsKnown;
 	uuid_int_map_t mCatVersionsUpdated;
 
-	typedef boost::unordered_map<LLUUID,LLPointer<LLViewerInventoryItem> > deferred_item_map_t;
+	typedef std::map<LLUUID,LLPointer<LLViewerInventoryItem> > deferred_item_map_t;
 	deferred_item_map_t mItemsCreated;
+    deferred_item_map_t mItemsLost;
 	deferred_item_map_t mItemsUpdated;
-	typedef boost::unordered_map<LLUUID,LLPointer<LLViewerInventoryCategory> > deferred_category_map_t;
+	typedef std::map<LLUUID,LLPointer<LLViewerInventoryCategory> > deferred_category_map_t;
 	deferred_category_map_t mCategoriesCreated;
 	deferred_category_map_t mCategoriesUpdated;
 
@@ -126,6 +152,10 @@ class AISUpdate
 	uuid_list_t mObjectsDeletedIds;
 	uuid_list_t mItemIds;
 	uuid_list_t mCategoryIds;
+    bool mFetch;
+    S32 mFetchDepth;
+    LLTimer mTimer;
+    AISAPI::COMMAND_TYPE mType;
 };
 
 #endif
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 2f48b7e6ef0359ad6f43e057e49da4b68f02310f..1c8e43f4ec95f1badda5513d788daae279a5ec1c 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -38,6 +38,7 @@
 #include "llgesturemgr.h"
 #include "llinventorybridge.h"
 #include "llinventoryfunctions.h"
+#include "llinventorymodelbackgroundfetch.h"
 #include "llinventoryobserver.h"
 #include "llmd5.h"
 #include "llnotificationsutil.h"
@@ -588,6 +589,71 @@ LLUpdateAppearanceAndEditWearableOnDestroy::~LLUpdateAppearanceAndEditWearableOn
 	}
 }
 
+class LLBrokenLinkObserver : public LLInventoryObserver
+{
+public:
+    LLUUID mUUID;
+    bool mEnforceItemRestrictions;
+    bool mEnforceOrdering;
+    nullary_func_t mPostUpdateFunc;
+
+    LLBrokenLinkObserver(const LLUUID& uuid,
+                          bool enforce_item_restrictions ,
+                          bool enforce_ordering ,
+                          nullary_func_t post_update_func) :
+        mUUID(uuid),
+        mEnforceItemRestrictions(enforce_item_restrictions),
+        mEnforceOrdering(enforce_ordering),
+        mPostUpdateFunc(post_update_func)
+    {
+    }
+    /* virtual */ void changed(U32 mask);
+    void postProcess();
+};
+
+void LLBrokenLinkObserver::changed(U32 mask)
+{
+    if (mask & LLInventoryObserver::REBUILD)
+    {
+        // This observer should be executed after LLInventoryPanel::itemChanged(),
+        // but if it isn't, consider calling updateAppearanceFromCOF with a delay
+        const uuid_set_t& changed_item_ids = gInventory.getChangedIDs();
+        for (uuid_set_t::const_iterator it = changed_item_ids.begin(); it != changed_item_ids.end(); ++it)
+        {
+            const LLUUID& id = *it;
+            if (id == mUUID)
+            {
+                // Might not be processed yet and it is not a
+                // good idea to update appearane here, postpone.
+                doOnIdleOneTime([this]()
+                                {
+                                    postProcess();
+                                });
+
+                gInventory.removeObserver(this);
+                return;
+            }
+        }
+    }
+}
+
+void LLBrokenLinkObserver::postProcess()
+{
+    LLViewerInventoryItem* item = gInventory.getItem(mUUID);
+    llassert(item && !item->getIsBrokenLink()); // the whole point was to get a correct link
+    if (item && item->getIsBrokenLink())
+    {
+        LL_INFOS_ONCE("Avatar") << "Outfit link broken despite being regenerated" << LL_ENDL;
+        LL_DEBUGS("Avatar", "Inventory") << "Outfit link " << mUUID << " \"" << item->getName() << "\" is broken despite being regenerated" << LL_ENDL;
+    }
+
+    LLAppearanceMgr::instance().updateAppearanceFromCOF(
+        mEnforceItemRestrictions ,
+        mEnforceOrdering ,
+        mPostUpdateFunc);
+    delete this;
+}
+
 
 struct LLFoundData
 {
@@ -1765,12 +1831,18 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds
 	{
 		parent_id = gInventory.getRootFolderID();
 	}
-	LLUUID subfolder_id = gInventory.createNewCategory( parent_id,
-														LLFolderType::FT_NONE,
-														src_cat->getName());
-	shallowCopyCategoryContents(src_id, subfolder_id, cb);
+	gInventory.createNewCategory(
+        parent_id,
+        LLFolderType::FT_NONE,
+        src_cat->getName(),
+        [src_id, cb](const LLUUID &new_id)
+    {
+        LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_id, new_id, cb);
 
-	gInventory.notifyObservers();
+        gInventory.notifyObservers();
+    },
+        src_cat->getThumbnailUUID()
+    );
 }
 
 void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id,
@@ -2637,6 +2709,39 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
 
 	LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL;
 
+    if (gInventory.hasPosiblyBrockenLinks())
+    {
+        // Inventory has either broken links or links that
+        // haven't loaded yet.
+        // Check if LLAppearanceMgr needs to wait.
+        LLUUID current_outfit_id = getCOF();
+        LLInventoryModel::item_array_t cof_items;
+        LLInventoryModel::cat_array_t cof_cats;
+        LLFindBrokenLinks is_brocken_link;
+        gInventory.collectDescendentsIf(current_outfit_id,
+            cof_cats,
+            cof_items,
+            LLInventoryModel::EXCLUDE_TRASH,
+            is_brocken_link);
+
+        if (cof_items.size() > 0)
+        {
+            // Some links haven't loaded yet, but fetch isn't complete so
+            // links are likely fine and we will have to wait for them to
+            // load
+            if (LLInventoryModelBackgroundFetch::getInstance()->folderFetchActive())
+            {
+
+                LLBrokenLinkObserver* observer = new LLBrokenLinkObserver(cof_items.front()->getUUID(),
+                                                                            enforce_item_restrictions,
+                                                                            enforce_ordering,
+                                                                            post_update_func);
+                gInventory.addObserver(observer);
+                return;
+            }
+        }
+    }
+
 	if (enforce_item_restrictions)
 	{
 		// The point here is just to call
@@ -3052,22 +3157,29 @@ void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool ap
 		{
 			pid = gInventory.getRootFolderID();
 		}
-		
-		LLUUID new_cat_id = gInventory.createNewCategory(
+
+		gInventory.createNewCategory(
 			pid,
 			LLFolderType::FT_NONE,
-			name);
-
-		// Create a CopyMgr that will copy items, manage its own destruction
-		new LLCallAfterInventoryCopyMgr(
-			*items, new_cat_id, std::string("wear_inventory_category_callback"),
-			boost::bind(&LLAppearanceMgr::wearInventoryCategoryOnAvatar,
-						LLAppearanceMgr::getInstance(),
-						gInventory.getCategory(new_cat_id),
-						append));
-
-		// BAP fixes a lag in display of created dir.
-		gInventory.notifyObservers();
+            name,
+            [cat_id, append](const LLUUID& new_cat_id)
+        {
+            LLInventoryModel::cat_array_t* cats;
+            LLInventoryModel::item_array_t* items;
+            gInventory.getDirectDescendentsOf(cat_id, cats, items);
+            // Create a CopyMgr that will copy items, manage its own destruction
+            new LLCallAfterInventoryCopyMgr(
+                *items, new_cat_id, std::string("wear_inventory_category_callback"),
+                boost::bind(&LLAppearanceMgr::wearInventoryCategoryOnAvatar,
+                    LLAppearanceMgr::getInstance(),
+                    gInventory.getCategory(new_cat_id),
+                    append));
+
+            // BAP fixes a lag in display of created dir.
+            gInventory.notifyObservers();
+        },
+            cat->getThumbnailUUID()
+        );
 	}
 	else
 	{
@@ -3545,7 +3657,7 @@ void LLAppearanceMgr::copyLibraryGestures()
 
 	// Copy gestures
 	LLUUID lib_gesture_cat_id =
-		gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE,false);
+		gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE);
 	if (lib_gesture_cat_id.isNull())
 	{
 		LL_WARNS() << "Unable to copy gestures, source category not found" << LL_ENDL;
@@ -4056,7 +4168,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd
 
         if (cofVersion == LLViewerInventoryCategory::VERSION_UNKNOWN)
         {
-            LL_WARNS("AVatar") << "COF version is unknown... not requesting until COF version is known." << LL_ENDL;
+            LL_INFOS("AVatar") << "COF version is unknown... not requesting until COF version is known." << LL_ENDL;
             return;
         }
         else
@@ -4425,26 +4537,15 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo
 
 	// First, make a folder in the My Outfits directory.
 	const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
-    if (AISAPI::isAvailable())
-	{
-		// cap-based category creation was buggy until recently. use
-		// existence of AIS as an indicator the fix is present. Does
-		// not actually use AIS to create the category.
-		inventory_func_type func = boost::bind(&LLAppearanceMgr::onOutfitFolderCreated,this,_1,show_panel);
-		gInventory.createNewCategory(
-			parent_id,
-			LLFolderType::FT_OUTFIT,
-			new_folder_name,
-			func);
-	}
-	else
-	{		
-		LLUUID folder_id = gInventory.createNewCategory(
-			parent_id,
-			LLFolderType::FT_OUTFIT,
-			new_folder_name);
-		onOutfitFolderCreated(folder_id, show_panel);
-	}
+
+    gInventory.createNewCategory(
+        parent_id,
+        LLFolderType::FT_OUTFIT,
+        new_folder_name,
+        [show_panel](const LLUUID &new_cat_id)
+        {
+            LLAppearanceMgr::getInstance()->onOutfitFolderCreated(new_cat_id, show_panel);
+        });
 }
 
 void LLAppearanceMgr::wearBaseOutfit()
@@ -4814,6 +4915,73 @@ class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver
 	~CallAfterCategoryFetchStage1()
 	{
 	}
+    /*virtual*/ void startFetch()
+    {
+        bool ais3 = AISAPI::isAvailable();
+        for (uuid_vec_t::const_iterator it = mIDs.begin(); it != mIDs.end(); ++it)
+        {
+            LLViewerInventoryCategory* cat = gInventory.getCategory(*it);
+            if (!cat) continue;
+            if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
+            {
+                // CHECK IT: isCategoryComplete() checks both version and descendant count but
+                // fetch() only works for Unknown version and doesn't care about descentants,
+                // as result fetch won't start and folder will potentially get stuck as
+                // incomplete in observer.
+                // Likely either both should use only version or both should check descendants.
+                cat->fetch();		//blindly fetch it without seeing if anything else is fetching it.
+                mIncomplete.push_back(*it);	//Add to list of things being downloaded for this observer.
+            }
+            else if (!isCategoryComplete(cat))
+            {
+                LL_DEBUGS("Inventory") << "Categoty " << *it << " incomplete despite having version" << LL_ENDL;
+                LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch(*it, true);
+                mIncomplete.push_back(*it);
+            }
+            else if (ais3)
+            {
+                LLInventoryModel::cat_array_t* cats;
+                LLInventoryModel::item_array_t* items;
+                gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items);
+
+                if (items)
+                {
+                    S32 complete_count = 0;
+                    S32 incomplete_count = 0;
+                    for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); it < items->end(); ++it)
+                    {
+                        if (!(*it)->isFinished())
+                        {
+                            incomplete_count++;
+                        }
+                        else
+                        {
+                            complete_count++;
+                        }
+                    }
+                    // AIS can fetch couple items, but if there
+                    // is more than a dozen it will be very slow
+                    // it's faster to get whole folder in such case
+                    if (incomplete_count > LLInventoryFetchItemsObserver::MAX_INDIVIDUAL_ITEM_REQUESTS
+                        || (incomplete_count > 1 && complete_count == 0))
+                    {
+                        LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch(*it, true);
+                        mIncomplete.push_back(*it);
+                    }
+                    else
+                    {
+                        // let stage2 handle incomplete ones
+                        mComplete.push_back(*it);
+                    }
+                }
+                // else should have been handled by isCategoryComplete
+            }
+            else
+            {
+                mComplete.push_back(*it);
+            }
+        }
+    }
 	virtual void done()
 	{
         if (mComplete.empty())
@@ -4831,13 +4999,11 @@ class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver
 		// What we do here is get the complete information on the
 		// items in the requested category, 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(mComplete.front(),
-									  cat_array,
-									  item_array,
-									  LLInventoryModel::EXCLUDE_TRASH);
-		S32 count = item_array.size();
+        LLInventoryModel::cat_array_t* cats;
+        LLInventoryModel::item_array_t* items;
+        gInventory.getDirectDescendentsOf(mComplete.front(), cats, items);
+
+		S32 count = items->size();
 		if(!count)
 		{
 			LL_WARNS() << "Nothing fetched in category " << mComplete.front()
@@ -4849,11 +5015,13 @@ class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver
 			return;
 		}
 
-		LL_INFOS() << "stage1 got " << item_array.size() << " items, passing to stage2 " << LL_ENDL;
+        LLViewerInventoryCategory* cat = gInventory.getCategory(mComplete.front());
+        S32 version = cat ? cat->getVersion() : -2;
+		LL_INFOS() << "stage1, category " << mComplete.front() << " got " << count << " items, version " << version << " passing to stage2 " << LL_ENDL;
 		uuid_vec_t ids;
 		for(S32 i = 0; i < count; ++i)
 		{
-			ids.push_back(item_array.at(i)->getUUID());
+			ids.push_back(items->at(i)->getUUID());
 		}
 		
 		gInventory.removeObserver(this);
@@ -4878,18 +5046,78 @@ class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver
 	nullary_func_t mCallable;
 };
 
+void callAfterCOFFetch(nullary_func_t cb)
+{
+    LLUUID cat_id = LLAppearanceMgr::instance().getCOF();
+    LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+
+    if (AISAPI::isAvailable())
+    {
+        // Mark cof (update timer) so that background fetch won't request it
+        cat->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE);
+        // For reliability assume that we have no relevant cache, so
+        // fetch cof along with items cof's links point to.
+        AISAPI::FetchCOF([cb](const LLUUID& id)
+                         {
+                             cb();
+                             LLUUID cat_id = LLAppearanceMgr::instance().getCOF();
+                             LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+                             if (cat)
+                             {
+                                 cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+                             }
+                         });
+    }
+    else
+    {
+        LL_INFOS() << "AIS API v3 not available, using callAfterCategoryFetch" << LL_ENDL;
+        // startup should have marked folder as fetching, remove that
+        cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+        callAfterCategoryFetch(cat_id, cb);
+    }
+}
+
 void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb)
 {
-	CallAfterCategoryFetchStage1 *stage1 = new CallAfterCategoryFetchStage1(cat_id, cb);
-	stage1->startFetch();
-	if (stage1->isFinished())
-	{
-		stage1->done();
-	}
-	else
-	{
-		gInventory.addObserver(stage1);
-	}
+    CallAfterCategoryFetchStage1* stage1 = new CallAfterCategoryFetchStage1(cat_id, cb);
+    stage1->startFetch();
+    if (stage1->isFinished())
+    {
+        stage1->done();
+    }
+    else
+    {
+        gInventory.addObserver(stage1);
+    }
+}
+
+void callAfterCategoryLinksFetch(const LLUUID &cat_id, nullary_func_t cb)
+{
+    LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
+    if (AISAPI::isAvailable())
+    {
+        // Mark folder (update timer) so that background fetch won't request it
+        cat->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE);
+        // Assume that we have no relevant cache. Fetch folder, and items folder's links point to.
+        AISAPI::FetchCategoryLinks(cat_id,
+            [cb, cat_id](const LLUUID &id)
+            {
+                cb();
+                LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
+                if (cat)
+                {
+                    cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+                }
+            });
+        }
+        else
+        {
+            LL_WARNS() << "AIS API v3 not available, can't use AISAPI::FetchCOF" << LL_ENDL;
+            // startup should have marked folder as fetching, remove that
+            cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+            callAfterCategoryFetch(cat_id, cb);
+        }
+    
 }
 
 void add_wearable_type_counts(const uuid_vec_t& ids,
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 8721a695ccb56c238bdc2db6b5eac3103587e8bd..d7bb1c1dbe6ac1fedf830078c6dbbc7f547a0e24 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -364,7 +364,9 @@ class LLRequestServerAppearanceUpdateOnDestroy: public LLInventoryCallback
 LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name);
 
 // Invoke a given callable after category contents are fully fetched.
+void callAfterCOFFetch(nullary_func_t cb);
 void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb);
+void callAfterCategoryLinksFetch(const LLUUID &cat_id, nullary_func_t cb);
 
 // Wear all items in a uuid vector.
 void wear_multiple(const uuid_vec_t& ids, bool replace);
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 5d5ae15901ba7bca89f9fc77480f42c017f47846..d9a153cd2501f719aa21f1a259c3962fbcd2ab11 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -227,7 +227,7 @@
 #include "llcommandlineparser.h"
 #include "llfloatermemleak.h"
 #include "llfloaterreg.h"
-#include "llfloatersimpleoutfitsnapshot.h"
+#include "llfloatersimplesnapshot.h"
 #include "llfloatersnapshot.h"
 #include "llsidepanelinventory.h"
 
@@ -1472,7 +1472,7 @@ bool LLAppViewer::doFrame()
                     pingMainloopTimeout("Main:Snapshot");
                     gPipeline.mReflectionMapManager.update();
                     LLFloaterSnapshot::update(); // take snapshots
-                    LLFloaterSimpleOutfitSnapshot::update();
+                    LLFloaterSimpleSnapshot::update();
                     gGLActive = FALSE;
                 }
 
diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp
index 27d4c459a6904d1d62a1811ad8c0d1797469108a..13fae3787337ef54d48bcc85df73f3b0fe76481c 100644
--- a/indra/newview/llattachmentsmgr.cpp
+++ b/indra/newview/llattachmentsmgr.cpp
@@ -301,6 +301,13 @@ void LLAttachmentsMgr::linkRecentlyArrivedAttachments()
             return;
         }
 
+        if (LLAppearanceMgr::instance().getCOFVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
+        {
+            // Wait for cof to load
+            LL_DEBUGS_ONCE("Avatar") << "Received atachments, but cof isn't loaded yet, postponing processing" << LL_ENDL;
+            return;
+        }
+
         LL_DEBUGS("Avatar") << "ATT checking COF linkability for " << mRecentlyArrivedAttachments.size()
                             << " recently arrived items" << LL_ENDL;
 
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 5dab1cc4d0c7b1faf691400c0c08136afa0a9b73..68f65768446e80a2295fba720a2e1348904aab86 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -899,39 +899,55 @@ namespace action_give_inventory
 	/**
 	 * Checks My Inventory visibility.
 	 */
+    static bool is_give_inventory_acceptable_ids(const std::set<LLUUID> inventory_selected_uuids)
+    {
+        if (inventory_selected_uuids.empty()) return false; // nothing selected
+
+        bool acceptable = false;
+        std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
+        const std::set<LLUUID>::const_iterator it_end = inventory_selected_uuids.end();
+        for (; it != it_end; ++it)
+        {
+            LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
+            // any category can be offered.
+            if (inv_cat)
+            {
+                acceptable = true;
+                continue;
+            }
+
+            LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
+            // check if inventory item can be given
+            if (LLGiveInventory::isInventoryGiveAcceptable(inv_item))
+            {
+                acceptable = true;
+                continue;
+            }
+
+            // there are neither item nor category in inventory
+            acceptable = false;
+            break;
+        }
+    return acceptable;
+    }
 
 	static bool is_give_inventory_acceptable(LLInventoryPanel* panel = NULL)
 	{
 		// check selection in the panel
-		const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
-		if (inventory_selected_uuids.empty()) return false; // nothing selected
-
-		bool acceptable = false;
-		std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
-		const std::set<LLUUID>::const_iterator it_end = inventory_selected_uuids.end();
-		for (; it != it_end; ++it)
-		{
-			LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
-			// any category can be offered.
-			if (inv_cat)
-			{
-				acceptable = true;
-				continue;
-			}
-
-			LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
-			// check if inventory item can be given
-			if (LLGiveInventory::isInventoryGiveAcceptable(inv_item))
-			{
-				acceptable = true;
-				continue;
-			}
+        std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
+		if (inventory_selected_uuids.empty())
+        {
+            if(panel && panel->getRootFolder() && panel->getRootFolder()->isSingleFolderMode())
+            {
+                inventory_selected_uuids.insert(panel->getRootFolderID());
+            }
+            else
+            {
+                return false; // nothing selected
+            }
+        }
 
-			// there are neither item nor category in inventory
-			acceptable = false;
-			break;
-		}
-		return acceptable;
+        return is_give_inventory_acceptable_ids(inventory_selected_uuids);
 	}
 
 	static void build_items_string(const std::set<LLUUID>& inventory_selected_uuids , std::string& items_string)
@@ -1059,12 +1075,13 @@ namespace action_give_inventory
 	 * @param avatar_names - avatar names request to be sent.
 	 * @param avatar_uuids - avatar names request to be sent.
 	 */
-//	static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, LLInventoryPanel* panel = NULL)
+
+//    static void give_inventory_ids(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, const uuid_set_t inventory_selected_uuids)
 // [RLVa:KB] - @share
-	static void give_inventory(uuid_vec_t avatar_uuids, std::vector<LLAvatarName> avatar_names, LLInventoryPanel* panel = NULL)
+	static void give_inventory_ids(uuid_vec_t avatar_uuids, std::vector<LLAvatarName> avatar_names, const uuid_set_t inventory_selected_uuids)
 // [/RLVa:KB]
-	{
-		llassert(avatar_names.size() == avatar_uuids.size());
+    {
+        llassert(avatar_names.size() == avatar_uuids.size());
 
 // [RLVa:KB] - @share
 		if ( (RlvActions::isRlvEnabled()) && (RlvActions::hasBehaviour(RLV_BHVR_SHARE)) )
@@ -1087,42 +1104,60 @@ namespace action_give_inventory
 		}
 // [/RLVa:KB]
 
-		const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
-		if (inventory_selected_uuids.empty())
-		{
-			return;
-		}
+        if (inventory_selected_uuids.empty())
+        {
+            return;
+        }
 
-		std::string residents;
-		LLAvatarActions::buildResidentsString(avatar_names, residents, true);
+        std::string residents;
+        LLAvatarActions::buildResidentsString(avatar_names, residents, true);
 
-		std::string items;
-		build_items_string(inventory_selected_uuids, items);
+        std::string items;
+        build_items_string(inventory_selected_uuids, items);
 
-		int folders_count = 0;
-		std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
+        int folders_count = 0;
+        std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
 
-		//traverse through selected inventory items and count folders among them
-		for ( ; it != inventory_selected_uuids.end() && folders_count <=1 ; ++it)
-		{
-			LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
-			if (NULL != inv_cat)
-			{
-				folders_count++;
-			}
-		}
+        //traverse through selected inventory items and count folders among them
+        for ( ; it != inventory_selected_uuids.end() && folders_count <=1 ; ++it)
+        {
+            LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
+            if (NULL != inv_cat)
+            {
+                folders_count++;
+            }
+        }
 
-		// EXP-1599
-		// In case of sharing multiple folders, make the confirmation
-		// dialog contain a warning that only one folder can be shared at a time.
-		std::string notification = (folders_count > 1) ? "ShareFolderConfirmation" : "ShareItemsConfirmation";
-		LLSD substitutions;
-		substitutions["RESIDENTS"] = residents;
-		substitutions["ITEMS"] = items;
-		LLShareInfo::instance().mAvatarNames = avatar_names;
-		LLShareInfo::instance().mAvatarUuids = avatar_uuids;
-		LLNotificationsUtil::add(notification, substitutions, LLSD(), boost::bind(&give_inventory_cb, _1, _2, inventory_selected_uuids));
-	}
+        // EXP-1599
+        // In case of sharing multiple folders, make the confirmation
+        // dialog contain a warning that only one folder can be shared at a time.
+        std::string notification = (folders_count > 1) ? "ShareFolderConfirmation" : "ShareItemsConfirmation";
+        LLSD substitutions;
+        substitutions["RESIDENTS"] = residents;
+        substitutions["ITEMS"] = items;
+        LLShareInfo::instance().mAvatarNames = avatar_names;
+        LLShareInfo::instance().mAvatarUuids = avatar_uuids;
+        LLNotificationsUtil::add(notification, substitutions, LLSD(), boost::bind(&give_inventory_cb, _1, _2, inventory_selected_uuids));
+    }
+
+    static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, LLInventoryPanel* panel = NULL)
+    {
+        llassert(avatar_names.size() == avatar_uuids.size());
+        std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);;
+
+        if (inventory_selected_uuids.empty())
+        {
+            if(panel && panel->getRootFolder() && panel->getRootFolder()->isSingleFolderMode())
+            {
+                inventory_selected_uuids.insert(panel->getRootFolderID());
+            }
+            else
+            {
+                return;
+            }
+        }
+        give_inventory_ids(avatar_uuids, avatar_names, inventory_selected_uuids);
+    }
 }
 
 // static
@@ -1238,6 +1273,28 @@ void LLAvatarActions::shareWithAvatars(LLView * panel)
 	LLNotificationsUtil::add("ShareNotification");
 }
 
+//static
+void LLAvatarActions::shareWithAvatars(const uuid_set_t inventory_selected_uuids, LLFloater* root_floater)
+{
+    using namespace action_give_inventory;
+
+    LLFloaterAvatarPicker* picker =
+        LLFloaterAvatarPicker::show(boost::bind(give_inventory_ids, _1, _2, inventory_selected_uuids), TRUE, FALSE, FALSE, root_floater->getName());
+    if (!picker)
+    {
+        return;
+    }
+
+    picker->setOkBtnEnableCb(boost::bind(is_give_inventory_acceptable_ids, inventory_selected_uuids));
+    picker->openFriendsTab();
+    
+    if (root_floater)
+    {
+        root_floater->addDependentFloater(picker);
+    }
+    LLNotificationsUtil::add("ShareNotification");
+}
+
 // static
 bool LLAvatarActions::canShareSelectedItems(LLInventoryPanel* inv_panel /* = NULL*/)
 {
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index b3ade560842c5ac8769d17f17cfada66fd787dd6..92effba14d9369792db35d0e2669673d323c6fde 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -136,6 +136,7 @@ class LLAvatarActions
 	 * Share items with the picked avatars.
 	 */
 	static void shareWithAvatars(LLView * panel);
+    static void shareWithAvatars(const uuid_set_t inventory_selected_uuids, LLFloater* root_floater);
 
 	/**
 	 * Block/unblock the avatar by id.
diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h
index 68f594383d00b4b7c81eabb9f409c9f13bb90dfc..72572ec3bce6a861088c83d893d6a1ee96df3fdd 100644
--- a/indra/newview/llconversationmodel.h
+++ b/indra/newview/llconversationmodel.h
@@ -114,6 +114,7 @@ class LLConversationItem : public LLFolderViewModelItemCommon
 	virtual void previewItem( void );
 	virtual void selectItem(void) { } 
 	virtual void showProperties(void);
+    virtual void navigateToFolder(bool new_window = false, bool change_mode = false) {}
 
 	// Methods used in sorting (see LLConversationSort::operator())
 	EConversationType const getType() const { return mConvType; }
@@ -252,7 +253,7 @@ class LLConversationFilter : public LLFolderViewFilter
 	bool 				check(const LLFolderViewModelItem* item) { return true; }
 	bool				checkFolder(const LLFolderViewModelItem* folder) const { return true; }
 	void 				setEmptyLookupMessage(const std::string& message) { }
-	std::string			getEmptyLookupMessage() const { return mEmpty; }
+	std::string			getEmptyLookupMessage(bool is_empty_folder = false) const { return mEmpty; }
 	bool				showAllResults() const { return true; }
 	std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const { return std::string::npos; }
 	std::string::size_type getFilterStringSize() const { return 0; }
diff --git a/indra/newview/llfloaterchangeitemthumbnail.cpp b/indra/newview/llfloaterchangeitemthumbnail.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..eb73310a6ed94e21ee693854226a403e5e0341da
--- /dev/null
+++ b/indra/newview/llfloaterchangeitemthumbnail.cpp
@@ -0,0 +1,957 @@
+/** 
+ * @file llfloaterchangeitemthumbnail.cpp
+ * @brief LLFloaterChangeItemThumbnail class implementation
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterchangeitemthumbnail.h"
+
+#include "llbutton.h"
+#include "llclipboard.h"
+#include "lliconctrl.h"
+#include "llinventoryfunctions.h"
+#include "llinventoryicon.h"
+#include "llinventorymodel.h"
+#include "llinventoryobserver.h"
+#include "llfloaterreg.h"
+#include "llfloatersimplesnapshot.h"
+#include "llfloatertexturepicker.h"
+#include "lllineeditor.h"
+#include "llnotificationsutil.h"
+#include "lltextbox.h"
+#include "lltexturectrl.h"
+#include "llthumbnailctrl.h"
+#include "llviewerfoldertype.h"
+#include "llviewermenufile.h"
+#include "llviewerobjectlist.h"
+#include "llviewertexturelist.h"
+#include "llwindow.h"
+
+
+class LLThumbnailImagePicker : public LLFilePickerThread
+{
+public:
+    LLThumbnailImagePicker(const LLUUID &item_id);
+    LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id);
+    ~LLThumbnailImagePicker();
+    void notify(const std::vector<std::string>& filenames) override;
+
+private:
+    LLUUID mInventoryId;
+    LLUUID mTaskId;
+};
+
+LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id)
+    : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE)
+    , mInventoryId(item_id)
+{
+}
+
+LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id)
+    : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE)
+    , mInventoryId(item_id)
+    , mTaskId(task_id)
+{
+}
+
+LLThumbnailImagePicker::~LLThumbnailImagePicker()
+{
+}
+
+void LLThumbnailImagePicker::notify(const std::vector<std::string>& filenames)
+{
+    if (filenames.empty())
+    {
+        return;
+    }
+    std::string file_path = filenames[0];
+    if (file_path.empty())
+    {
+        return;
+    }
+    
+    LLFloaterSimpleSnapshot::uploadThumbnail(file_path, mInventoryId, mTaskId);
+}
+
+LLFloaterChangeItemThumbnail::LLFloaterChangeItemThumbnail(const LLSD& key)
+    : LLFloater(key)
+    , mObserverInitialized(false)
+    , mTooltipState(TOOLTIP_NONE)
+{
+}
+
+LLFloaterChangeItemThumbnail::~LLFloaterChangeItemThumbnail()
+{
+    gInventory.removeObserver(this);
+    removeVOInventoryListener();
+}
+
+BOOL LLFloaterChangeItemThumbnail::postBuild()
+{
+    mItemNameText = getChild<LLUICtrl>("item_name");
+    mItemTypeIcon = getChild<LLIconCtrl>("item_type_icon");
+    mThumbnailCtrl = getChild<LLThumbnailCtrl>("item_thumbnail");
+    mToolTipTextBox = getChild<LLTextBox>("tooltip_text");
+
+    LLSD tooltip_text;
+    mToolTipTextBox->setValue(tooltip_text);
+
+    LLButton *upload_local = getChild<LLButton>("upload_local");
+    upload_local->setClickedCallback(onUploadLocal, (void*)this);
+    upload_local->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_UPLOAD_LOCAL));
+    upload_local->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_UPLOAD_LOCAL));
+
+    LLButton *upload_snapshot = getChild<LLButton>("upload_snapshot");
+    upload_snapshot->setClickedCallback(onUploadSnapshot, (void*)this);
+    upload_snapshot->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_UPLOAD_SNAPSHOT));
+    upload_snapshot->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_UPLOAD_SNAPSHOT));
+
+    LLButton *use_texture = getChild<LLButton>("use_texture");
+    use_texture->setClickedCallback(onUseTexture, (void*)this);
+    use_texture->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_USE_TEXTURE));
+    use_texture->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_USE_TEXTURE));
+
+    mCopyToClipboardBtn = getChild<LLButton>("copy_to_clipboard");
+    mCopyToClipboardBtn->setClickedCallback(onCopyToClipboard, (void*)this);
+    mCopyToClipboardBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_COPY_TO_CLIPBOARD));
+    mCopyToClipboardBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_COPY_TO_CLIPBOARD));
+
+    mPasteFromClipboardBtn = getChild<LLButton>("paste_from_clipboard");
+    mPasteFromClipboardBtn->setClickedCallback(onPasteFromClipboard, (void*)this);
+    mPasteFromClipboardBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_COPY_FROM_CLIPBOARD));
+    mPasteFromClipboardBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_COPY_FROM_CLIPBOARD));
+
+    mRemoveImageBtn = getChild<LLButton>("remove_image");
+    mRemoveImageBtn->setClickedCallback(onRemove, (void*)this);
+    mRemoveImageBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_REMOVE));
+    mRemoveImageBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_REMOVE));
+
+    return LLFloater::postBuild();
+}
+
+void LLFloaterChangeItemThumbnail::onOpen(const LLSD& key)
+{
+    if (!key.has("item_id") && !key.isUUID())
+    {
+        closeFloater();
+    }
+
+    if (key.isUUID())
+    {
+        mItemId = key.asUUID();
+    }
+    else
+    {
+        mItemId = key["item_id"].asUUID();
+        mTaskId = key["task_id"].asUUID();
+    }
+
+    refreshFromInventory();
+}
+
+void LLFloaterChangeItemThumbnail::onFocusReceived()
+{
+    mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
+}
+
+void LLFloaterChangeItemThumbnail::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+    mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
+}
+
+BOOL LLFloaterChangeItemThumbnail::handleDragAndDrop(
+    S32 x,
+    S32 y,
+    MASK mask,
+    BOOL drop,
+    EDragAndDropType cargo_type,
+    void *cargo_data,
+    EAcceptance *accept,
+    std::string& tooltip_msg)
+{
+    if (cargo_type == DAD_TEXTURE)
+    {
+        LLInventoryItem *item = (LLInventoryItem *)cargo_data;
+        if (item->getAssetUUID().notNull())
+        {
+            if (drop)
+            {
+                assignAndValidateAsset(item->getAssetUUID());
+            }
+
+            *accept = ACCEPT_YES_SINGLE;
+        }
+        else
+        {
+            *accept = ACCEPT_NO;
+        }
+    }
+    else
+    {
+        *accept = ACCEPT_NO;
+    }
+
+    LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFloaterChangeItemThumbnail " << getKey() << LL_ENDL;
+
+    return TRUE;
+}
+
+void LLFloaterChangeItemThumbnail::changed(U32 mask)
+{
+    //LLInventoryObserver
+
+    if (mTaskId.notNull() || mItemId.isNull())
+    {
+        // Task inventory or not set up yet
+        return;
+    }
+
+    const std::set<LLUUID>& mChangedItemIDs = gInventory.getChangedIDs();
+    std::set<LLUUID>::const_iterator it;
+
+    for (it = mChangedItemIDs.begin(); it != mChangedItemIDs.end(); it++)
+    {
+        // set dirty for 'item profile panel' only if changed item is the item for which 'item profile panel' is shown (STORM-288)
+        if (*it == mItemId)
+        {
+            // if there's a change we're interested in.
+            if ((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
+            {
+                refreshFromInventory();
+            }
+        }
+    }
+}
+
+void LLFloaterChangeItemThumbnail::inventoryChanged(LLViewerObject* object,
+    LLInventoryObject::object_list_t* inventory,
+    S32 serial_num,
+    void* user_data)
+{
+    //LLVOInventoryListener
+    refreshFromInventory();
+}
+
+LLInventoryObject* LLFloaterChangeItemThumbnail::getInventoryObject()
+{
+    LLInventoryObject* obj = NULL;
+    if (mTaskId.isNull())
+    {
+        // it is in agent inventory
+        if (!mObserverInitialized)
+        {
+            gInventory.addObserver(this);
+            mObserverInitialized = true;
+        }
+
+        obj = gInventory.getObject(mItemId);
+    }
+    else
+    {
+        LLViewerObject* object = gObjectList.findObject(mTaskId);
+        if (object)
+        {
+            if (!mObserverInitialized)
+            {
+                registerVOInventoryListener(object, NULL);
+                mObserverInitialized = false;
+            }
+
+            obj = object->getInventoryObject(mItemId);
+        }
+    }
+    return obj;
+}
+
+void LLFloaterChangeItemThumbnail::refreshFromInventory()
+{
+    LLInventoryObject* obj = getInventoryObject();
+    if (!obj)
+    {
+        closeFloater();
+    }
+
+    if (obj)
+    {
+        const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+        bool in_trash = gInventory.isObjectDescendentOf(obj->getUUID(), trash_id);
+        if (in_trash && obj->getUUID() != trash_id)
+        {
+            // Close properties when moving to trash
+            // Aren't supposed to view properties from trash
+            closeFloater();
+        }
+        else
+        {
+            refreshFromObject(obj);
+        }
+    }
+    else
+    {
+        closeFloater();
+    }
+}
+
+class LLIsOutfitTextureType : public LLInventoryCollectFunctor
+{
+public:
+    LLIsOutfitTextureType() {}
+    virtual ~LLIsOutfitTextureType() {}
+    virtual bool operator()(LLInventoryCategory* cat,
+        LLInventoryItem* item);
+};
+
+bool LLIsOutfitTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+    return item && (item->getType() == LLAssetType::AT_TEXTURE);
+}
+
+void LLFloaterChangeItemThumbnail::refreshFromObject(LLInventoryObject* obj)
+{
+    LLUIImagePtr icon_img;
+    LLUUID thumbnail_id = obj->getThumbnailUUID();
+
+    LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(obj);
+    if (item)
+    {
+        setTitle(getString("title_item_thumbnail"));
+
+        icon_img = LLInventoryIcon::getIcon(item->getType(), item->getInventoryType(), item->getFlags(), FALSE);
+        mRemoveImageBtn->setEnabled(thumbnail_id.notNull() && ((item->getActualType() != LLAssetType::AT_TEXTURE) || (item->getAssetUUID() != thumbnail_id)));
+    }
+    else
+    {
+        LLViewerInventoryCategory* cat = dynamic_cast<LLViewerInventoryCategory*>(obj);
+
+        if (cat)
+        {
+            setTitle(getString("title_folder_thumbnail"));
+            icon_img = LLUI::getUIImage(LLViewerFolderType::lookupIconName(cat->getPreferredType(), true));
+
+            if (thumbnail_id.isNull() && (cat->getPreferredType() == LLFolderType::FT_OUTFIT))
+            {
+                // Legacy support, check if there is an image inside
+
+                LLInventoryModel::cat_array_t cats;
+                LLInventoryModel::item_array_t items;
+                // Not LLIsOfAssetType, because we allow links
+                LLIsOutfitTextureType f;
+                gInventory.getDirectDescendentsOf(mItemId, cats, items, f);
+
+                if (1 == items.size())
+                {
+                    LLViewerInventoryItem* item = items.front();
+                    if (item && item->getIsLinkType())
+                    {
+                        item = item->getLinkedItem();
+                    }
+                    if (item)
+                    {
+                        thumbnail_id = item->getAssetUUID();
+                        if (thumbnail_id.notNull())
+                        {
+                            // per SL-19188, set this image as a thumbnail
+                            LL_INFOS() << "Setting image " << thumbnail_id
+                                       << " from outfit as a thumbnail for inventory object " << obj->getUUID()
+                                       << LL_ENDL;
+                            assignAndValidateAsset(thumbnail_id, true);
+                        }
+                    }
+                }
+            }
+
+            mRemoveImageBtn->setEnabled(thumbnail_id.notNull());
+        }
+    }
+    mItemTypeIcon->setImage(icon_img);
+    mItemNameText->setValue(obj->getName());
+
+    mThumbnailCtrl->setValue(thumbnail_id);
+
+    mCopyToClipboardBtn->setEnabled(thumbnail_id.notNull());
+    mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
+
+    // todo: some elements might not support setting thumbnails
+    // since they already have them
+    // It is unclear how system folders should function
+}
+
+void LLFloaterChangeItemThumbnail::onUploadLocal(void *userdata)
+{
+    LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+
+    (new LLThumbnailImagePicker(self->mItemId, self->mTaskId))->getFile();
+
+    LLFloater* floaterp = self->mPickerHandle.get();
+    if (floaterp)
+    {
+        floaterp->closeFloater();
+    }
+    floaterp = self->mSnapshotHandle.get();
+    if (floaterp)
+    {
+        floaterp->closeFloater();
+    }
+}
+
+void LLFloaterChangeItemThumbnail::onUploadSnapshot(void *userdata)
+{
+    LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+
+    LLFloater* floaterp = self->mSnapshotHandle.get();
+    // Show the dialog
+    if (floaterp)
+    {
+        floaterp->openFloater();
+    }
+    else
+    {
+        LLSD key;
+        key["item_id"] = self->mItemId;
+        key["task_id"] = self->mTaskId;
+        LLFloaterSimpleSnapshot* snapshot_floater = (LLFloaterSimpleSnapshot*)LLFloaterReg::showInstance("simple_snapshot", key, true);
+        if (snapshot_floater)
+        {
+            self->addDependentFloater(snapshot_floater);
+            self->mSnapshotHandle = snapshot_floater->getHandle();
+            snapshot_floater->setOwner(self);
+        }
+    }
+
+    floaterp = self->mPickerHandle.get();
+    if (floaterp)
+    {
+        floaterp->closeFloater();
+    }
+}
+
+void LLFloaterChangeItemThumbnail::onUseTexture(void *userdata)
+{
+    LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+    LLInventoryObject* obj = self->getInventoryObject();
+    if (obj)
+    {
+        self->showTexturePicker(obj->getThumbnailUUID());
+    }
+
+    LLFloater* floaterp = self->mSnapshotHandle.get();
+    if (floaterp)
+    {
+        floaterp->closeFloater();
+    }
+}
+
+void LLFloaterChangeItemThumbnail::onCopyToClipboard(void *userdata)
+{
+    LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+    LLInventoryObject* obj = self->getInventoryObject();
+    if (obj)
+    {
+        LLClipboard::instance().reset();
+        LLClipboard::instance().addToClipboard(obj->getThumbnailUUID(), LLAssetType::AT_NONE);
+        self->mPasteFromClipboardBtn->setEnabled(true);
+    }
+}
+
+void LLFloaterChangeItemThumbnail::onPasteFromClipboard(void *userdata)
+{
+    LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+    std::vector<LLUUID> objects;
+    LLClipboard::instance().pasteFromClipboard(objects);
+    if (objects.size() > 0)
+    {
+        LLUUID potential_uuid = objects[0];
+        LLUUID asset_id;
+
+        if (potential_uuid.notNull())
+        {
+            LLViewerInventoryItem* item = gInventory.getItem(potential_uuid);
+            if (item)
+            {
+                // no point checking snapshot?
+                if (item->getType() == LLAssetType::AT_TEXTURE)
+                {
+                    bool copy = item->getPermissions().allowCopyBy(gAgent.getID());
+                    bool xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID());
+
+                    if (copy && xfer)
+                    {
+                        asset_id = item->getAssetUUID();
+                    }
+                    else
+                    {
+                        LLNotificationsUtil::add("ThumbnailInsufficientPermissions");
+                        return;
+                    }
+                }
+            }
+            else
+            {
+                // assume that this is a texture
+                asset_id = potential_uuid;
+            }
+        }
+
+        LLInventoryObject* obj = self->getInventoryObject();
+        if (obj && obj->getThumbnailUUID() == asset_id)
+        {
+            // nothing to do
+            return;
+        }
+        if (asset_id.notNull())
+        {
+            self->assignAndValidateAsset(asset_id);
+        }
+        // else show 'buffer has no texture' warning?
+    }
+}
+
+void LLFloaterChangeItemThumbnail::onRemove(void *userdata)
+{
+    LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+
+    LLSD payload;
+    payload["item_id"] = self->mItemId;
+    payload["object_id"] = self->mTaskId;
+    LLNotificationsUtil::add("DeleteThumbnail", LLSD(), payload, boost::bind(&LLFloaterChangeItemThumbnail::onRemovalConfirmation, _1, _2, self->getHandle()));
+}
+
+// static 
+void LLFloaterChangeItemThumbnail::onRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFloater> handle)
+{
+    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+    if (option == 0 && !handle.isDead() && !handle.get()->isDead())
+    {
+        LLFloaterChangeItemThumbnail* self = (LLFloaterChangeItemThumbnail*)handle.get();
+        self->setThumbnailId(LLUUID::null);
+    }
+}
+
+struct ImageLoadedData
+{
+    LLUUID mThumbnailId;
+    LLUUID mObjectId;
+    LLHandle<LLFloater> mFloaterHandle;
+    bool mSilent;
+    // Keep image reference to prevent deletion on timeout
+    LLPointer<LLViewerFetchedTexture> mTexturep;
+};
+
+void LLFloaterChangeItemThumbnail::assignAndValidateAsset(const LLUUID &asset_id, bool silent)
+{
+    LLPointer<LLViewerFetchedTexture> texturep = LLViewerTextureManager::getFetchedTexture(asset_id);
+    if (texturep->isMissingAsset())
+    {
+        LL_WARNS() << "Attempted to assign missing asset " << asset_id << LL_ENDL;
+        if (!silent)
+        {
+            LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+        }
+    }
+    else if (texturep->getFullWidth() == 0)
+    {
+        if (silent)
+        {
+            mExpectingAssetId = LLUUID::null;
+        }
+        else
+        {
+            // don't warn user multiple times if some textures took their time
+            mExpectingAssetId = asset_id;
+        }
+        ImageLoadedData *data = new ImageLoadedData();
+        data->mObjectId = mItemId;
+        data->mThumbnailId = asset_id;
+        data->mFloaterHandle = getHandle();
+        data->mSilent = silent;
+        data->mTexturep = texturep;
+
+        texturep->setLoadedCallback(onImageDataLoaded,
+            MAX_DISCARD_LEVEL, // Don't need full image, just size data
+            FALSE,
+            FALSE,
+            (void*)data,
+            NULL,
+            FALSE);
+    }
+    else
+    {
+        if (validateAsset(asset_id))
+        {
+            setThumbnailId(asset_id);
+        }
+        else if (!silent)
+        {
+            LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+        }
+    }
+}
+bool LLFloaterChangeItemThumbnail::validateAsset(const LLUUID &asset_id)
+{
+    if (asset_id.isNull())
+    {
+        return false;
+    }
+
+    LLPointer<LLViewerFetchedTexture> texturep = LLViewerTextureManager::findFetchedTexture(asset_id, TEX_LIST_STANDARD);
+
+    if (!texturep)
+    {
+        return false;
+    }
+
+    if (texturep->isMissingAsset())
+    {
+        return false;
+    }
+
+    if (texturep->getFullWidth() != texturep->getFullHeight())
+    {
+        return false;
+    }
+
+    if (texturep->getFullWidth() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX
+        || texturep->getFullHeight() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX)
+    {
+        return false;
+    }
+
+    if (texturep->getFullWidth() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN
+        || texturep->getFullHeight() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN)
+    {
+        return false;
+    }
+    return true;
+}
+
+//static
+void LLFloaterChangeItemThumbnail::onImageDataLoaded(
+    BOOL success,
+    LLViewerFetchedTexture *src_vi,
+    LLImageRaw* src,
+    LLImageRaw* aux_src,
+    S32 discard_level,
+    BOOL final,
+    void* userdata)
+{
+    if (!userdata) return;
+
+    if (!final && success) return; //not done yet
+
+    ImageLoadedData* data = (ImageLoadedData*)userdata;
+
+    if (success)
+    {
+        // Update the item, set it even if floater is dead
+        if (validateAsset(data->mThumbnailId))
+        {
+            setThumbnailId(data->mThumbnailId, data->mObjectId);
+        }
+        else if (!data->mSilent)
+        {
+            // Should this only appear if floater is alive?
+            LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+        }
+    }
+
+    // Update floater
+    if (!data->mSilent && !data->mFloaterHandle.isDead())
+    {
+        LLFloaterChangeItemThumbnail* self = static_cast<LLFloaterChangeItemThumbnail*>(data->mFloaterHandle.get());
+        if (self && self->mExpectingAssetId == data->mThumbnailId)
+        {
+            self->mExpectingAssetId = LLUUID::null;
+        }
+    }
+
+    delete data;
+}
+
+//static
+void LLFloaterChangeItemThumbnail::onFullImageLoaded(
+    BOOL success,
+    LLViewerFetchedTexture* src_vi,
+    LLImageRaw* src,
+    LLImageRaw* aux_src,
+    S32 discard_level,
+    BOOL final,
+    void* userdata)
+{
+    if (!userdata) return;
+
+    if (!final && success) return; //not done yet
+
+    ImageLoadedData* data = (ImageLoadedData*)userdata;
+
+    if (success)
+    {
+        if (src_vi->getFullWidth() != src_vi->getFullHeight()
+            || src_vi->getFullWidth() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN)
+        {
+            if (!data->mSilent)
+            {
+                LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+            }
+        }
+        else if (src_vi->getFullWidth() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX)
+        {
+            LLFloaterSimpleSnapshot::uploadThumbnail(src, data->mObjectId, LLUUID::null);
+        }
+        else
+        {
+            setThumbnailId(data->mThumbnailId, data->mObjectId);
+        }
+    }
+
+    delete data;
+}
+
+void LLFloaterChangeItemThumbnail::showTexturePicker(const LLUUID &thumbnail_id)
+{
+    // show hourglass cursor when loading inventory window
+    getWindow()->setCursor(UI_CURSOR_WAIT);
+
+    LLFloater* floaterp = mPickerHandle.get();
+    // Show the dialog
+    if (floaterp)
+    {
+        floaterp->openFloater();
+    }
+    else
+    {
+        floaterp = new LLFloaterTexturePicker(
+            this,
+            thumbnail_id,
+            thumbnail_id,
+            thumbnail_id,
+            thumbnail_id,
+            FALSE,
+            TRUE,
+            "SELECT PHOTO",
+            PERM_NONE,
+            PERM_NONE,
+            FALSE,
+            NULL);
+
+        mPickerHandle = floaterp->getHandle();
+
+        LLFloaterTexturePicker* texture_floaterp = dynamic_cast<LLFloaterTexturePicker*>(floaterp);
+        if (texture_floaterp)
+        {
+            //texture_floaterp->setTextureSelectedCallback();
+            //texture_floaterp->setOnUpdateImageStatsCallback();
+            texture_floaterp->setOnFloaterCommitCallback([this](LLTextureCtrl::ETexturePickOp op, LLPickerSource, const LLUUID&, const LLUUID&)
+            {
+                if (op == LLTextureCtrl::TEXTURE_SELECT)
+                {
+                    onTexturePickerCommit();
+                }
+            }
+            );
+
+            texture_floaterp->setLocalTextureEnabled(FALSE);
+            texture_floaterp->setBakeTextureEnabled(FALSE);
+            texture_floaterp->setCanApplyImmediately(false);
+            texture_floaterp->setCanApply(false, true, false /*Hide 'preview disabled'*/);
+            texture_floaterp->setMinDimentionsLimits(LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN);
+
+            addDependentFloater(texture_floaterp);
+        }
+
+        floaterp->openFloater();
+    }
+    floaterp->setFocus(TRUE);
+}
+
+void LLFloaterChangeItemThumbnail::onTexturePickerCommit()
+{
+    LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mPickerHandle.get();
+
+    if (floaterp)
+    {
+        LLUUID asset_id = floaterp->getAssetID();
+
+        if (asset_id.isNull())
+        {
+            setThumbnailId(asset_id);
+            return;
+        }
+
+        LLInventoryObject* obj = getInventoryObject();
+        if (obj && obj->getThumbnailUUID() == asset_id)
+        {
+            // nothing to do
+            return;
+        }
+
+        LLPointer<LLViewerFetchedTexture> texturep = LLViewerTextureManager::findFetchedTexture(asset_id, TEX_LIST_STANDARD);
+        if (!texturep)
+        {
+            LL_WARNS() << "Image " << asset_id << " doesn't exist" << LL_ENDL;
+            return;
+        }
+
+        if (texturep->isMissingAsset())
+        {
+            LL_WARNS() << "Image " << asset_id << " is missing" << LL_ENDL;
+            return;
+        }
+
+        if (texturep->getFullWidth() != texturep->getFullHeight())
+        {
+            LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+            return;
+        }
+
+        if (texturep->getFullWidth() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN
+            && texturep->getFullWidth() > 0)
+        {
+            LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+            return;
+        }
+
+        if (texturep->getFullWidth() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX
+            || texturep->getFullWidth() == 0)
+        {
+            if (texturep->isFullyLoaded()
+                && (texturep->getCachedRawImageLevel() == 0 || texturep->getRawImageLevel() == 0)
+                && (texturep->isCachedRawImageReady() || texturep->isRawImageValid()))
+            {
+                if (texturep->isRawImageValid())
+                {
+                    LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getRawImage(), mItemId, mTaskId);
+                }
+                else
+                {
+                    LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getCachedRawImage(), mItemId, mTaskId);
+                }
+            }
+            else
+            {
+                ImageLoadedData* data = new ImageLoadedData();
+                data->mObjectId = mItemId;
+                data->mThumbnailId = asset_id;
+                data->mFloaterHandle = getHandle();
+                data->mSilent = false;
+                data->mTexturep = texturep;
+
+                texturep->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
+                texturep->setMinDiscardLevel(0);
+                texturep->setLoadedCallback(onFullImageLoaded,
+                                            0, // Need best quality
+                                            TRUE,
+                                            FALSE,
+                                            (void*)data,
+                                            NULL,
+                                            FALSE);
+                texturep->forceToSaveRawImage(0);
+            }
+            return;
+        }
+
+        setThumbnailId(asset_id);
+    }
+}
+
+
+void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID &new_thumbnail_id)
+{
+    LLInventoryObject* obj = getInventoryObject();
+    if (!obj)
+    {
+        return;
+    }
+
+    if (mTaskId.notNull())
+    {
+        LL_ERRS() << "Not implemented yet" << LL_ENDL;
+        return;
+    }
+
+    setThumbnailId(new_thumbnail_id, mItemId, obj);
+}
+
+void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id)
+{
+    LLInventoryObject* obj = gInventory.getObject(object_id);
+    if (!obj)
+    {
+        return;
+    }
+
+    setThumbnailId(new_thumbnail_id, object_id, obj);
+}
+void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id, LLInventoryObject* obj)
+{
+    if (obj->getThumbnailUUID() != new_thumbnail_id)
+    {
+        LLSD updates;
+        if (new_thumbnail_id.notNull())
+        {
+            // At the moment server expects id as a string
+            updates["thumbnail"] = LLSD().with("asset_id", new_thumbnail_id.asString());
+        }
+        else
+        {
+            // No thumbnail isntead of 'null id thumbnail'
+            updates["thumbnail"] = LLSD();
+        }
+        LLViewerInventoryCategory* view_folder = dynamic_cast<LLViewerInventoryCategory*>(obj);
+        if (view_folder)
+        {
+            update_inventory_category(object_id, updates, NULL);
+        }
+        LLViewerInventoryItem* view_item = dynamic_cast<LLViewerInventoryItem*>(obj);
+        if (view_item)
+        {
+            update_inventory_item(object_id, updates, NULL);
+        }
+    }
+}
+
+void LLFloaterChangeItemThumbnail::onButtonMouseEnter(LLUICtrl* button, const LLSD& param, EToolTipState state)
+{
+    mTooltipState = state;
+
+    std::string tooltip_text;
+    std::string tooltip_name = "tooltip_" + button->getName();
+    if (hasString(tooltip_name))
+    {
+        tooltip_text = getString(tooltip_name);
+    }
+
+    mToolTipTextBox->setValue(tooltip_text);
+}
+
+void LLFloaterChangeItemThumbnail::onButtonMouseLeave(LLUICtrl* button, const LLSD& param, EToolTipState state)
+{
+    if (mTooltipState == state)
+    {
+        mTooltipState = TOOLTIP_NONE;
+        LLSD tooltip_text;
+        mToolTipTextBox->setValue(tooltip_text);
+    }
+}
+
diff --git a/indra/newview/llfloaterchangeitemthumbnail.h b/indra/newview/llfloaterchangeitemthumbnail.h
new file mode 100644
index 0000000000000000000000000000000000000000..a91e9b8ee9124c6683d37b45960c8fc2c7acc9b6
--- /dev/null
+++ b/indra/newview/llfloaterchangeitemthumbnail.h
@@ -0,0 +1,139 @@
+/** 
+ * @file llfloaterchangeitemthumbnail.h
+ * @brief LLFloaterChangeItemThumbnail class definition
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERCHANGEITEMTHUMBNAIL_H
+#define LL_LLFLOATERCHANGEITEMTHUMBNAIL_H
+
+#include "llfloater.h"
+#include "llinventoryobserver.h"
+#include "llvoinventorylistener.h"
+
+class LLButton;
+class LLIconCtrl;
+class LLTextBox;
+class LLThumbnailCtrl;
+class LLUICtrl;
+class LLViewerInventoryItem;
+class LLViewerFetchedTexture;
+
+class LLFloaterChangeItemThumbnail : public LLFloater, public LLInventoryObserver, public LLVOInventoryListener
+{
+public:
+    LLFloaterChangeItemThumbnail(const LLSD& key);
+	~LLFloaterChangeItemThumbnail();
+
+    BOOL postBuild() override;
+    void onOpen(const LLSD& key) override;
+    void onFocusReceived() override;
+    void onMouseEnter(S32 x, S32 y, MASK mask) override;
+
+    BOOL handleDragAndDrop(
+        S32 x,
+        S32 y,
+        MASK mask,
+        BOOL drop,
+        EDragAndDropType cargo_type,
+        void *cargo_data,
+        EAcceptance *accept,
+        std::string& tooltip_msg) override;
+
+    void changed(U32 mask) override;
+    void inventoryChanged(LLViewerObject* object,
+        LLInventoryObject::object_list_t* inventory,
+        S32 serial_num,
+        void* user_data) override;
+
+    static bool validateAsset(const LLUUID &asset_id);
+
+private:
+
+    LLInventoryObject* getInventoryObject();
+    void refreshFromInventory();
+    void refreshFromObject(LLInventoryObject* obj);
+
+    static void onUploadLocal(void*);
+    static void onUploadSnapshot(void*);
+    static void onUseTexture(void*);
+    static void onCopyToClipboard(void*);
+    static void onPasteFromClipboard(void*);
+    static void onRemove(void*);
+    static void onRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFloater> handle);
+
+    void assignAndValidateAsset(const LLUUID &asset_id, bool silent = false);
+    static void onImageDataLoaded(BOOL success,
+        LLViewerFetchedTexture *src_vi,
+        LLImageRaw* src,
+        LLImageRaw* aux_src,
+        S32 discard_level,
+        BOOL final,
+        void* userdata);
+    static void onFullImageLoaded(BOOL success,
+                                  LLViewerFetchedTexture* src_vi,
+                                  LLImageRaw* src,
+                                  LLImageRaw* aux_src,
+                                  S32 discard_level,
+                                  BOOL final,
+                                  void* userdata);
+
+    void showTexturePicker(const LLUUID &thumbnail_id);
+    void onTexturePickerCommit();
+
+    void setThumbnailId(const LLUUID &new_thumbnail_id);
+    static void setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id);
+    static void setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id, LLInventoryObject* obj);
+
+    enum EToolTipState
+    {
+        TOOLTIP_NONE,
+        TOOLTIP_UPLOAD_LOCAL,
+        TOOLTIP_UPLOAD_SNAPSHOT,
+        TOOLTIP_USE_TEXTURE,
+        TOOLTIP_COPY_TO_CLIPBOARD,
+        TOOLTIP_COPY_FROM_CLIPBOARD,
+        TOOLTIP_REMOVE,
+    };
+
+    void onButtonMouseEnter(LLUICtrl* button, const LLSD& param, EToolTipState state);
+    void onButtonMouseLeave(LLUICtrl* button, const LLSD& param, EToolTipState state);
+
+    bool mObserverInitialized;
+    EToolTipState mTooltipState;
+    LLUUID mItemId;
+    LLUUID mTaskId;
+    LLUUID mExpectingAssetId;
+
+    LLIconCtrl *mItemTypeIcon;
+    LLUICtrl *mItemNameText;
+    LLThumbnailCtrl *mThumbnailCtrl;
+    LLTextBox *mToolTipTextBox;
+    LLButton *mCopyToClipboardBtn;
+    LLButton *mPasteFromClipboardBtn;
+    LLButton *mRemoveImageBtn;
+
+    LLHandle<LLFloater> mPickerHandle;
+    LLHandle<LLFloater> mSnapshotHandle;
+};
+#endif  // LL_LLFLOATERCHANGEITEMTHUMBNAIL_H
diff --git a/indra/newview/llfloatereditenvironmentbase.cpp b/indra/newview/llfloatereditenvironmentbase.cpp
index 285095166849f8fb461e6882a06b4c22dcc6e8b4..cd24d79b7f7968c9f3b5e30cd745d435e80e8658 100644
--- a/indra/newview/llfloatereditenvironmentbase.cpp
+++ b/indra/newview/llfloatereditenvironmentbase.cpp
@@ -260,7 +260,7 @@ void LLFloaterEditEnvironmentBase::onSaveAsCommit(const LLSD& notification, cons
         }
         else if (mInventoryItem)
         {
-            const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+            const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
             LLUUID parent_id = mInventoryItem->getParentUUID();
             if (marketplacelistings_id == parent_id || gInventory.isObjectDescendentOf(mInventoryItem->getUUID(), gInventory.getLibraryRootFolderID()))
             {
diff --git a/indra/newview/llfloaterforgetuser.cpp b/indra/newview/llfloaterforgetuser.cpp
index f5dd324d14e7a0e2ffe544458c3d8315a9c13dbf..0f15eadf5253723610decc495afcb622941aefc8 100644
--- a/indra/newview/llfloaterforgetuser.cpp
+++ b/indra/newview/llfloaterforgetuser.cpp
@@ -124,6 +124,12 @@ bool LLFloaterForgetUser::onConfirmLogout(const LLSD& notification, const LLSD&
     if (option == 0)
     {
         // Remove creds
+        std::string grid_id = LLGridManager::getInstance()->getGridId(grid);
+        if (grid_id.empty())
+        {
+            grid_id = grid;
+        }
+        gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid_id, LLStartUp::getUserId()); // doesn't write
         gSecAPIHandler->removeFromCredentialMap("login_list", grid, LLStartUp::getUserId());
 
         LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid);
@@ -188,7 +194,13 @@ void LLFloaterForgetUser::processForgetUser()
 void LLFloaterForgetUser::forgetUser(const std::string &userid, const std::string &fav_id, const std::string &grid, bool delete_data)
 {
     // Remove creds
-    gSecAPIHandler->removeFromCredentialMap("login_list", grid, userid);
+    std::string grid_id = LLGridManager::getInstance()->getGridId(grid);
+    if (grid_id.empty())
+    {
+        grid_id = grid;
+    }
+    gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid_id, userid); // doesn't write
+    gSecAPIHandler->removeFromCredentialMap("login_list", grid, userid); // write operation
 
     LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid);
     if (cred.notNull() && cred->userID() == userid)
diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp
index f71a4511d65b2613d94fd8eeabe660651fcb735d..65b93951417f4face0c5775c64546b28de3bf7db 100644
--- a/indra/newview/llfloatergesture.cpp
+++ b/indra/newview/llfloatergesture.cpp
@@ -211,7 +211,7 @@ BOOL LLFloaterGesture::postBuild()
 	getChildView("play_btn")->setVisible( true);
 	getChildView("stop_btn")->setVisible( false);
 	setDefaultBtn("play_btn");
-	mGestureFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE, false);
+	mGestureFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
 
 	uuid_vec_t folders;
 	folders.push_back(mGestureFolderID);
diff --git a/indra/newview/llfloaterinventorysettings.cpp b/indra/newview/llfloaterinventorysettings.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..29d6e90a330e31597e26950e66e7ad9c09d740e2
--- /dev/null
+++ b/indra/newview/llfloaterinventorysettings.cpp
@@ -0,0 +1,44 @@
+/**
+ * @file llfloaterinventorysettings.cpp
+ * @brief LLFloaterInventorySettings class implementation
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterinventorysettings.h"
+
+LLFloaterInventorySettings::LLFloaterInventorySettings(const LLSD& key)
+  : LLFloater(key)
+{
+}
+
+LLFloaterInventorySettings::~LLFloaterInventorySettings()
+{}
+
+BOOL LLFloaterInventorySettings::postBuild()
+{
+    getChild<LLButton>("ok_btn")->setCommitCallback(boost::bind(&LLFloater::closeFloater, this, false));
+    return TRUE;
+}
+
diff --git a/indra/newview/llfloaterinventorysettings.h b/indra/newview/llfloaterinventorysettings.h
new file mode 100644
index 0000000000000000000000000000000000000000..50304276c71f2bd4616b43e6451007356486e749
--- /dev/null
+++ b/indra/newview/llfloaterinventorysettings.h
@@ -0,0 +1,45 @@
+/**
+ * @file llfloaterinventorysettings.h
+ * @brief LLFloaterInventorySettings class definition
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERINVENTORYSETTINGS_H
+#define LL_LLFLOATERINVENTORYSETTINGS_H
+
+#include "llfloater.h"
+
+class LLFloaterInventorySettings
+    :    public LLFloater
+{
+    friend class LLFloaterReg;
+
+public:
+    virtual BOOL postBuild();
+
+private:
+    LLFloaterInventorySettings(const LLSD& key);
+    ~LLFloaterInventorySettings();
+};
+
+#endif
diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp
index 8ee7a72055e3fabee739830e47287d43d130eee4..b42c49c607dd32679834e9940c7d116591cdf917 100644
--- a/indra/newview/llfloaterlinkreplace.cpp
+++ b/indra/newview/llfloaterlinkreplace.cpp
@@ -335,8 +335,8 @@ BOOL LLFloaterLinkReplace::tick()
 void LLFloaterLinkReplace::processBatch(LLInventoryModel::item_array_t items)
 {
 	const LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID);
-	const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
-	const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+	const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+	const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
 
 	for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it)
 	{
diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp
index e755e9924c067a01a6c0f0cd717e7c49352e81da..71b3b16809743e5a2c7525dda75881ff5b6c56a6 100644
--- a/indra/newview/llfloatermarketplacelistings.cpp
+++ b/indra/newview/llfloatermarketplacelistings.cpp
@@ -41,8 +41,11 @@
 #include "llnotificationmanager.h"
 #include "llnotificationsutil.h"
 #include "llsidepaneliteminfo.h"
+#include "llsidepaneltaskinfo.h"
+#include "lltabcontainer.h"
 #include "lltextbox.h"
 #include "lltrans.h"
+#include "llviewerwindow.h"
 
 ///----------------------------------------------------------------------------
 /// LLPanelMarketplaceListings
@@ -227,18 +230,31 @@ void LLPanelMarketplaceListings::onTabChange()
 
 void LLPanelMarketplaceListings::onAddButtonClicked()
 {
-	// Find active panel
-	LLInventoryPanel* panel = (LLInventoryPanel*)getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel();
-	if (panel)
-	{
-        LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
-        llassert(marketplacelistings_id.notNull());
-        LLFolderType::EType preferred_type = LLFolderType::lookup("category");
-        LLUUID category = gInventory.createNewCategory(marketplacelistings_id, preferred_type, LLStringUtil::null);
-        gInventory.notifyObservers();
-        panel->setSelectionByID(category, TRUE);
-        panel->getRootFolder()->setNeedsAutoRename(TRUE);
+    LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+    llassert(marketplacelistings_id.notNull());
+    LLFolderType::EType preferred_type = LLFolderType::lookup("category");
+    LLHandle<LLPanel> handle = getHandle();
+    gInventory.createNewCategory(
+        marketplacelistings_id,
+        preferred_type,
+        LLStringUtil::null,
+        [handle](const LLUUID &new_cat_id)
+    {
+        // Find active panel
+        LLPanel *marketplace_panel = handle.get();
+        if (!marketplace_panel)
+        {
+            return;
+        }
+        LLInventoryPanel* panel = (LLInventoryPanel*)marketplace_panel->getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel();
+        if (panel)
+        {
+            gInventory.notifyObservers();
+            panel->setSelectionByID(new_cat_id, TRUE);
+            panel->getRootFolder()->setNeedsAutoRename(TRUE);
+        }
     }
+    );
 }
 
 void LLPanelMarketplaceListings::onAuditButtonClicked()
@@ -359,6 +375,7 @@ LLFloaterMarketplaceListings::LLFloaterMarketplaceListings(const LLSD& key)
 , mInventoryTitle(NULL)
 , mPanelListings(NULL)
 , mPanelListingsSet(false)
+, mRootFolderCreating(false)
 {
 }
 
@@ -431,7 +448,7 @@ void LLFloaterMarketplaceListings::fetchContents()
 	{
         LLMarketplaceData::instance().setDataFetchedSignal(boost::bind(&LLFloaterMarketplaceListings::updateView, this));
         LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_LOADING);
-		LLInventoryModelBackgroundFetch::instance().start(mRootFolderId);
+		LLInventoryModelBackgroundFetch::instance().start(mRootFolderId, true);
         LLMarketplaceData::instance().getSLMListings();
 	}
 }
@@ -444,15 +461,50 @@ void LLFloaterMarketplaceListings::setRootFolder()
 		// If we are *not* a merchant or we have no market place connection established yet, do nothing
 		return;
 	}
+    if (!gInventory.isInventoryUsable())
+    {
+        return;
+    }
     
+    LLFolderType::EType preferred_type = LLFolderType::FT_MARKETPLACE_LISTINGS;
 	// We are a merchant. Get the Marketplace listings folder, create it if needs be.
-	LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true);
-	if (marketplacelistings_id.isNull())
-	{
-		// We should never get there unless the inventory fails badly
-		LL_ERRS("SLM") << "Inventory problem: failure to create the marketplace listings folder for a merchant!" << LL_ENDL;
-		return;
-	}
+	LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(preferred_type);
+
+    if (marketplacelistings_id.isNull())
+    {
+        if (!mRootFolderCreating)
+        {
+            mRootFolderCreating = true;
+            gInventory.createNewCategory(
+                gInventory.getRootFolderID(),
+                preferred_type,
+                LLStringUtil::null,
+                [](const LLUUID &new_cat_id)
+            {
+                LLFloaterMarketplaceListings* marketplace = LLFloaterReg::findTypedInstance<LLFloaterMarketplaceListings>("marketplace_listings");
+                if (marketplace)
+                {
+                    if (new_cat_id.notNull())
+                    {
+                        // will call setRootFolder again
+                        marketplace->updateView();
+                    }
+                    // don't update in case of failure, createNewCategory can return
+                    // immediately if cap is missing and will cause a loop
+                    else
+                    {
+                        // unblock
+                        marketplace->mRootFolderCreating = false;
+                        LL_WARNS("SLM") << "Inventory warning: Failed to create marketplace listings folder for a merchant" << LL_ENDL;
+                    }
+                }
+            }
+            );
+        }
+        return;
+    }
+
+    mRootFolderCreating = false;
     
 	// No longer need to observe new category creation
 	if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
@@ -540,6 +592,11 @@ void LLFloaterMarketplaceListings::updateView()
     {
         setRootFolder();
     }
+    if (mRootFolderCreating)
+    {
+        // waiting for callback
+        return;
+    }
 
     // Update the bottom initializing status and progress dial if we are initializing or if we're a merchant and still loading
     if ((mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING) || (is_merchant && (data_fetched <= MarketplaceFetchCodes::MARKET_FETCH_LOADING)) )
@@ -843,14 +900,17 @@ void LLFloaterMarketplaceValidation::onOpen(const LLSD& key)
     LLUUID cat_id(key.asUUID());
     if (cat_id.isNull())
     {
-        cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+        cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
     }
 
     // Validates the folder
     if (cat_id.notNull())
     {
-        LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
-        validate_marketplacelistings(cat, boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3), false);
+        LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+            cat_id,
+            NULL,
+            boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3),
+            false);
     }
     
     // Handle the listing folder being processed
@@ -954,18 +1014,44 @@ LLFloaterItemProperties::~LLFloaterItemProperties()
 
 BOOL LLFloaterItemProperties::postBuild()
 {
-    // On the standalone properties floater, we have no need for a back button...
-    LLSidepanelItemInfo* panel = getChild<LLSidepanelItemInfo>("item_panel");
-    LLButton* back_btn = panel->getChild<LLButton>("back_btn");
-    back_btn->setVisible(FALSE);
-    
 	return LLFloater::postBuild();
 }
 
 void LLFloaterItemProperties::onOpen(const LLSD& key)
 {
     // Tell the panel which item it needs to visualize
-    LLSidepanelItemInfo* panel = getChild<LLSidepanelItemInfo>("item_panel");
-    panel->setItemID(key["id"].asUUID());
+    LLPanel* panel = findChild<LLPanel>("sidepanel");
+    
+    LLSidepanelItemInfo* item_panel = dynamic_cast<LLSidepanelItemInfo*>(panel);
+    if (item_panel)
+    {
+        item_panel->setItemID(key["id"].asUUID());
+        if (key.has("object"))
+        {
+            item_panel->setObjectID(key["object"].asUUID());
+        }
+        item_panel->setParentFloater(this);
+    }
+    
+    LLSidepanelTaskInfo* task_panel = dynamic_cast<LLSidepanelTaskInfo*>(panel);
+    if (task_panel)
+    {
+        task_panel->setObjectSelection(LLSelectMgr::getInstance()->getSelection());
+    }
 }
 
+LLMultiItemProperties::LLMultiItemProperties(const LLSD& key)
+	: LLMultiFloater(LLSD())
+{
+	// start with a small rect in the top-left corner ; will get resized
+	LLRect rect;
+	rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 350, 350);
+	setRect(rect);
+	LLFloater* last_floater = LLFloaterReg::getLastFloaterInGroup(key.asString());
+	if (last_floater)
+	{
+		stackWith(*last_floater);
+	}
+	setTitle(LLTrans::getString("MultiPropertiesTitle"));
+	buildTabContainer();
+}
diff --git a/indra/newview/llfloatermarketplacelistings.h b/indra/newview/llfloatermarketplacelistings.h
index c56baac1158330d2138931ca37609f1e6041fa30..ea245d6f3d5c3a7efcde8cdc66eee5efb4405bce 100644
--- a/indra/newview/llfloatermarketplacelistings.h
+++ b/indra/newview/llfloatermarketplacelistings.h
@@ -33,6 +33,7 @@
 #include "llinventorypanel.h"
 #include "llnotificationptr.h"
 #include "llmodaldialog.h"
+#include "llmultifloater.h"
 #include "lltexteditor.h"
 
 class LLInventoryCategoriesObserver;
@@ -139,6 +140,7 @@ class LLFloaterMarketplaceListings final : public LLFloater
 	LLTextBox *		mInventoryTitle;
 
 	LLUUID			mRootFolderId;
+    bool            mRootFolderCreating;
 	LLPanelMarketplaceListings * mPanelListings;
     bool            mPanelListingsSet;
 };
@@ -223,4 +225,10 @@ class LLFloaterItemProperties final : public LLFloater
 private:
 };
 
+class LLMultiItemProperties : public LLMultiFloater
+{
+public:
+	LLMultiItemProperties(const LLSD& key);
+};
+
 #endif // LL_LLFLOATERMARKETPLACELISTINGS_H
diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp
index f77e58aec17ec1b7ece4eae5e92be098471148b8..77cfb08bd3646ad97fbac7063fc0a6f0847b4149 100644
--- a/indra/newview/llfloateropenobject.cpp
+++ b/indra/newview/llfloateropenobject.cpp
@@ -176,34 +176,12 @@ void LLFloaterOpenObject::moveToInventory(bool wear, bool replace)
 	}
 
 	inventory_func_type func = boost::bind(LLFloaterOpenObject::callbackCreateInventoryCategory,_1,object_id,wear,replace);
-	LLUUID category_id = gInventory.createNewCategory(parent_category_id, 
-													  LLFolderType::FT_NONE, 
-													  name,
-													  func);
-
-	//If we get a null category ID, we are using a capability in createNewCategory and we will
-	//handle the following in the callbackCreateInventoryCategory routine.
-	if ( category_id.notNull() )
-	{
-		LLCatAndWear* data = new LLCatAndWear;
-		data->mCatID = category_id;
-		data->mWear = wear;
-		data->mFolderResponded = false;
-		data->mReplace = replace;
-
-		// Copy and/or move the items into the newly created folder.
-		// Ignore any "you're going to break this item" messages.
-		BOOL success = move_inv_category_world_to_agent(object_id, category_id, TRUE,
-														callbackMoveInventory, 
-														(void*)data);
-		if (!success)
-		{
-			delete data;
-			data = NULL;
-
-			LLNotificationsUtil::add("OpenObjectCannotCopy");
-		}
-	}
+	// D567 copy thumbnail info
+	gInventory.createNewCategory(
+        parent_category_id,
+        LLFolderType::FT_NONE,
+        name,
+        func);
 }
 
 // static
@@ -218,9 +196,14 @@ void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLUUID& category
 	
 	// Copy and/or move the items into the newly created folder.
 	// Ignore any "you're going to break this item" messages.
-	BOOL success = move_inv_category_world_to_agent(object_id, category_id, TRUE,
-													callbackMoveInventory, 
-													(void*)wear_data);
+	BOOL success = move_inv_category_world_to_agent(object_id,
+                                                    category_id,
+                                                    TRUE,
+                                                    [](S32 result, void* data, const LLMoveInv*)
+                                                    {
+                                                        callbackMoveInventory(result, data);
+                                                    },
+                                                    (void*)wear_data);
 	if (!success)
 	{
 		delete wear_data;
diff --git a/indra/newview/llfloateroutfitphotopreview.cpp b/indra/newview/llfloateroutfitphotopreview.cpp
deleted file mode 100644
index ade258aef74ee07ffbc8a95c8cfe811ee40139f5..0000000000000000000000000000000000000000
--- a/indra/newview/llfloateroutfitphotopreview.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/** 
- * @file llfloateroutfitphotopreview.cpp
- * @brief LLFloaterOutfitPhotoPreview class implementation
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llwindow.h"
-
-#include "llfloateroutfitphotopreview.h"
-
-#include "llagent.h"
-#include "llappearancemgr.h"
-#include "llbutton.h"
-#include "llcombobox.h"
-#include "llfilepicker.h"
-#include "llfloaterreg.h"
-#include "llimagetga.h"
-#include "llimagepng.h"
-#include "llinventory.h"
-#include "llinventorymodel.h"
-#include "llnotificationsutil.h"
-#include "llresmgr.h"
-#include "lltrans.h"
-#include "lltextbox.h"
-#include "lltextureview.h"
-#include "llui.h"
-#include "llviewerinventory.h"
-#include "llviewertexture.h"
-#include "llviewertexturelist.h"
-#include "lluictrlfactory.h"
-#include "llviewerwindow.h"
-#include "lllineeditor.h"
-
-const S32 MAX_OUTFIT_PHOTO_WIDTH = 256;
-const S32 MAX_OUTFIT_PHOTO_HEIGHT = 256;
-
-const S32 CLIENT_RECT_VPAD = 4;
-
-LLFloaterOutfitPhotoPreview::LLFloaterOutfitPhotoPreview(const LLSD& key)
-	: LLPreview(key),
-	  mUpdateDimensions(TRUE),
-	  mImage(NULL),
-	  mOutfitID(LLUUID()),
-	  mImageOldBoostLevel(LLGLTexture::BOOST_NONE),
-	  mExceedLimits(FALSE)
-{
-	updateImageID();
-}
-
-LLFloaterOutfitPhotoPreview::~LLFloaterOutfitPhotoPreview()
-{
-	LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ;
-
-	if (mImage.notNull())
-	{
-		mImage->setBoostLevel(mImageOldBoostLevel);
-		mImage = NULL;
-	}
-}
-
-// virtual
-BOOL LLFloaterOutfitPhotoPreview::postBuild()
-{
-	getChild<LLButton>("ok_btn")->setClickedCallback(boost::bind(&LLFloaterOutfitPhotoPreview::onOkBtn, this));
-	getChild<LLButton>("cancel_btn")->setClickedCallback(boost::bind(&LLFloaterOutfitPhotoPreview::onCancelBtn, this));
-
-	return LLPreview::postBuild();
-}
-
-void LLFloaterOutfitPhotoPreview::draw()
-{
-	updateDimensions();
-	
-	LLPreview::draw();
-
-	if (!isMinimized())
-	{
-		LLGLSUIDefault gls_ui;
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		
-		const LLRect& border = mClientRect;
-		LLRect interior = mClientRect;
-		interior.stretch( -PREVIEW_BORDER_WIDTH );
-
-		// ...border
-		gl_rect_2d( border, LLColor4(0.f, 0.f, 0.f, 1.f));
-		gl_rect_2d_checkerboard( interior );
-
-		if ( mImage.notNull() )
-		{
-			// Draw the texture
-			gGL.diffuseColor3f( 1.f, 1.f, 1.f );
-			gl_draw_scaled_image(interior.mLeft,
-								interior.mBottom,
-								interior.getWidth(),
-								interior.getHeight(),
-								mImage);
-
-			// Pump the texture priority
-			F32 pixel_area = (F32)(interior.getWidth() * interior.getHeight() );
-			mImage->addTextureStats( pixel_area );
-
-			S32 int_width = interior.getWidth();
-			S32 int_height = interior.getHeight();
-			mImage->setKnownDrawSize(int_width, int_height);
-		}
-	} 
-
-}
-
-// virtual
-void LLFloaterOutfitPhotoPreview::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
-	LLPreview::reshape(width, height, called_from_parent);
-
-	LLRect dim_rect(getChildView("dimensions")->getRect());
-
-	S32 horiz_pad = 2 * (LLPANEL_BORDER_WIDTH + PREVIEW_PAD) + PREVIEW_RESIZE_HANDLE_SIZE;
-
-	S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD;
-
-	LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0);
-	client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD);
-	client_rect.mBottom += PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height ;
-
-	S32 client_width = client_rect.getWidth();
-	S32 client_height = client_width;
-
-	if(client_height > client_rect.getHeight())
-	{
-		client_height = client_rect.getHeight();
-		client_width = client_height;
-	}
-	mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() +  (client_height / 2), client_width, client_height);
-
-}
-
-
-void LLFloaterOutfitPhotoPreview::updateDimensions()
-{
-	if (!mImage)
-	{
-		return;
-	}
-	if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0)
-	{
-		return;
-	}
-
-	if (mAssetStatus != PREVIEW_ASSET_LOADED)
-	{
-		mAssetStatus = PREVIEW_ASSET_LOADED;
-		mUpdateDimensions = TRUE;
-	}
-	
-	getChild<LLUICtrl>("dimensions")->setTextArg("[WIDTH]",  llformat("%d", mImage->getFullWidth()));
-	getChild<LLUICtrl>("dimensions")->setTextArg("[HEIGHT]", llformat("%d", mImage->getFullHeight()));
-
-	if ((mImage->getFullWidth() <= MAX_OUTFIT_PHOTO_WIDTH) && (mImage->getFullHeight() <= MAX_OUTFIT_PHOTO_HEIGHT))
-	{
-		getChild<LLButton>("ok_btn")->setEnabled(TRUE);
-		mExceedLimits = FALSE;
-	}
-	else
-	{
-		mExceedLimits = TRUE;
-		LLStringUtil::format_map_t args;
-		args["MAX_WIDTH"] = llformat("%d", MAX_OUTFIT_PHOTO_WIDTH);
-		args["MAX_HEIGHT"] = llformat("%d", MAX_OUTFIT_PHOTO_HEIGHT);
-		std::string label = getString("exceed_limits", args);
-		getChild<LLUICtrl>("notification")->setValue(label);
-		getChild<LLUICtrl>("notification")->setColor(LLColor4::yellow);
-		getChild<LLButton>("ok_btn")->setEnabled(FALSE);
-	}
-
-	if (mUpdateDimensions)
-	{
-		mUpdateDimensions = FALSE;
-
-		reshape(getRect().getWidth(), getRect().getHeight());
-		gFloaterView->adjustToFitScreen(this, FALSE);
-	}
-}
-
-void LLFloaterOutfitPhotoPreview::loadAsset()
-{
-	if (mImage.notNull())
-	{
-		mImage->setBoostLevel(mImageOldBoostLevel);
-	}
-	mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
-	mImageOldBoostLevel = mImage->getBoostLevel();
-	mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
-	mImage->forceToSaveRawImage(0) ;
-	mAssetStatus = PREVIEW_ASSET_LOADING;
-	mUpdateDimensions = TRUE;
-	updateDimensions();
-}
-
-LLPreview::EAssetStatus LLFloaterOutfitPhotoPreview::getAssetStatus()
-{
-	if (mImage.notNull() && (mImage->getFullWidth() * mImage->getFullHeight() > 0))
-	{
-		mAssetStatus = PREVIEW_ASSET_LOADED;
-	}
-	return mAssetStatus;
-}
-
-void LLFloaterOutfitPhotoPreview::updateImageID()
-{
-	const LLViewerInventoryItem *item = static_cast<const LLViewerInventoryItem*>(getItem());
-	if(item)
-	{
-		mImageID = item->getAssetUUID();
-	}
-	else
-	{
-		mImageID = mItemUUID;
-	}
-
-}
-
-/* virtual */
-void LLFloaterOutfitPhotoPreview::setObjectID(const LLUUID& object_id)
-{
-	mObjectUUID = object_id;
-
-	const LLUUID old_image_id = mImageID;
-
-	updateImageID();
-	if (mImageID != old_image_id)
-	{
-		mAssetStatus = PREVIEW_ASSET_UNLOADED;
-		loadAsset();
-	}
-	refreshFromItem();
-}
-
-void LLFloaterOutfitPhotoPreview::setOutfitID(const LLUUID& outfit_id)
-{
-	mOutfitID = outfit_id;
-	LLViewerInventoryCategory* outfit_folder = gInventory.getCategory(mOutfitID);
-	if(outfit_folder && !mExceedLimits)
-	{
-		getChild<LLUICtrl>("notification")->setValue( getString("photo_confirmation"));
-		getChild<LLUICtrl>("notification")->setTextArg("[OUTFIT]", outfit_folder->getName());
-		getChild<LLUICtrl>("notification")->setColor(LLColor4::white);
-	}
-
-}
-
-void LLFloaterOutfitPhotoPreview::onOkBtn()
-{
-	if(mOutfitID.notNull() && getItem())
-	{
-		LLAppearanceMgr::instance().removeOutfitPhoto(mOutfitID);
-		LLPointer<LLInventoryCallback> cb = NULL;
-		link_inventory_object(mOutfitID, LLConstPointer<LLInventoryObject>(getItem()), cb);
-	}
-	closeFloater();
-}
-
-void LLFloaterOutfitPhotoPreview::onCancelBtn()
-{
-	closeFloater();
-}
diff --git a/indra/newview/llfloateroutfitphotopreview.h b/indra/newview/llfloateroutfitphotopreview.h
deleted file mode 100644
index 4b68c3b9bf5a93c6f936933cc4548e3cb6dc238e..0000000000000000000000000000000000000000
--- a/indra/newview/llfloateroutfitphotopreview.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/** 
- * @file llfloateroutfitphotopreview.h
- * @brief LLFloaterOutfitPhotoPreview class definition
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLFLOATEROUTFITPHOTOPREVIEW_H
-#define LL_LLFLOATEROUTFITPHOTOPREVIEW_H
-
-#include "llpreview.h"
-#include "llbutton.h"
-#include "llframetimer.h"
-#include "llviewertexture.h"
-
-class LLComboBox;
-class LLImageRaw;
-
-class LLFloaterOutfitPhotoPreview final : public LLPreview
-{
-public:
-	LLFloaterOutfitPhotoPreview(const LLSD& key);
-	~LLFloaterOutfitPhotoPreview();
-
-	virtual void		draw();
-
-	virtual void		loadAsset();
-	virtual EAssetStatus	getAssetStatus();
-	
-	virtual void		reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
-
-	/*virtual*/ void setObjectID(const LLUUID& object_id);
-
-	void setOutfitID(const LLUUID& outfit_id);
-	void onOkBtn();
-	void onCancelBtn();
-
-protected:
-	void				init();
-	/* virtual */ BOOL	postBuild();
-	
-private:
-	void				updateImageID(); // set what image is being uploaded.
-	void				updateDimensions();
-	LLUUID				mImageID;
-	LLUUID				mOutfitID;
-	LLPointer<LLViewerFetchedTexture>		mImage;
-	S32                 mImageOldBoostLevel;
-
-	// This is stored off in a member variable, because the save-as
-	// button and drag and drop functionality need to know.
-	BOOL mUpdateDimensions;
-
-	BOOL mExceedLimits;
-
-	LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ;
-};
-#endif  // LL_LLFLOATEROUTFITPHOTOPREVIEW_H
diff --git a/indra/newview/llfloatersidepanelcontainer.cpp b/indra/newview/llfloatersidepanelcontainer.cpp
index d7c8a7359d8e62605475d876152dc69c5345c6d0..038bd331c1f1304a9629594aca87ad5d174c84cd 100644
--- a/indra/newview/llfloatersidepanelcontainer.cpp
+++ b/indra/newview/llfloatersidepanelcontainer.cpp
@@ -100,6 +100,29 @@ void LLFloaterSidePanelContainer::closeFloater(bool app_quitting)
 	}
 }
 
+LLFloater* LLFloaterSidePanelContainer::getTopmostInventoryFloater()
+{
+    LLFloater* topmost_floater = NULL;
+    S32 z_min = S32_MAX;
+    
+    LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
+    for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+    {
+        LLFloater* inventory_floater = (*iter);
+
+        if (inventory_floater && inventory_floater->getVisible())
+        {
+            S32 z_order = gFloaterView->getZOrder(inventory_floater);
+            if (z_order < z_min)
+            {
+                z_min = z_order;
+                topmost_floater = inventory_floater;
+            }
+        }
+    }
+    return topmost_floater;
+}
+
 LLPanel* LLFloaterSidePanelContainer::openChildPanel(std::string_view panel_name, const LLSD& params)
 {
 	LLView* view = findChildView(panel_name, true);
diff --git a/indra/newview/llfloatersidepanelcontainer.h b/indra/newview/llfloatersidepanelcontainer.h
index 1d2d6be2e11d2924eebf7d9b2dda9d990d207bea..cf9b6835adede0b46139746b928240afed3f3b0e 100644
--- a/indra/newview/llfloatersidepanelcontainer.h
+++ b/indra/newview/llfloatersidepanelcontainer.h
@@ -61,6 +61,8 @@ class LLFloaterSidePanelContainer final : public LLFloater
 
 	LLPanel* openChildPanel(std::string_view panel_name, const LLSD& params);
 
+    static LLFloater* getTopmostInventoryFloater();
+
 // [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
 	static bool canShowPanel(std::string_view floater_name, const LLSD& key);
 	static bool canShowPanel(std::string_view floater_name, std::string_view panel_name, const LLSD& key);
diff --git a/indra/newview/llfloatersimpleoutfitsnapshot.cpp b/indra/newview/llfloatersimpleoutfitsnapshot.cpp
deleted file mode 100644
index bab2efbbd56aa0fb59c516223b08922a49cef42d..0000000000000000000000000000000000000000
--- a/indra/newview/llfloatersimpleoutfitsnapshot.cpp
+++ /dev/null
@@ -1,333 +0,0 @@
-/** 
-* @file llfloatersimpleoutfitsnapshot.cpp
-* @brief Snapshot preview window for saving as an outfit thumbnail in visual outfit gallery
-*
-* $LicenseInfo:firstyear=2022&license=viewerlgpl$
-* Second Life Viewer Source Code
-* Copyright (C) 2022, Linden Research, Inc.
-* 
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU Lesser General Public
-* License as published by the Free Software Foundation;
-* version 2.1 of the License only.
-* 
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-* Lesser General Public License for more details.
-* 
-* You should have received a copy of the GNU Lesser General Public
-* License along with this library; if not, write to the Free Software
-* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-* 
-* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-* $/LicenseInfo$
-*/
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llfloatersimpleoutfitsnapshot.h"
-
-#include "llfloaterreg.h"
-#include "llimagefiltersmanager.h"
-#include "llstatusbar.h" // can_afford_transaction()
-#include "llnotificationsutil.h"
-#include "llagentbenefits.h"
-#include "llviewercontrol.h"
-
-LLSimpleOutfitSnapshotFloaterView* gSimpleOutfitSnapshotFloaterView = NULL;
-
-const S32 OUTFIT_SNAPSHOT_WIDTH = 256;
-const S32 OUTFIT_SNAPSHOT_HEIGHT = 256;
-
-static LLDefaultChildRegistry::Register<LLSimpleOutfitSnapshotFloaterView> r("simple_snapshot_outfit_floater_view");
-
-///----------------------------------------------------------------------------
-/// Class LLFloaterSimpleOutfitSnapshot::Impl
-///----------------------------------------------------------------------------
-
-LLSnapshotModel::ESnapshotFormat LLFloaterSimpleOutfitSnapshot::Impl::getImageFormat(LLFloaterSnapshotBase* floater)
-{
-    return LLSnapshotModel::SNAPSHOT_FORMAT_PNG;
-}
-
-LLSnapshotModel::ESnapshotLayerType LLFloaterSimpleOutfitSnapshot::Impl::getLayerType(LLFloaterSnapshotBase* floater)
-{
-    return LLSnapshotModel::SNAPSHOT_TYPE_COLOR;
-}
-
-void LLFloaterSimpleOutfitSnapshot::Impl::updateControls(LLFloaterSnapshotBase* floater)
-{
-    LLSnapshotLivePreview* previewp = getPreviewView();
-    updateResolution(floater);
-    if (previewp)
-    {
-        previewp->setSnapshotType(LLSnapshotModel::ESnapshotType::SNAPSHOT_TEXTURE);
-        previewp->setSnapshotFormat(LLSnapshotModel::ESnapshotFormat::SNAPSHOT_FORMAT_PNG);
-        previewp->setSnapshotBufferType(LLSnapshotModel::ESnapshotLayerType::SNAPSHOT_TYPE_COLOR);
-    }
-}
-
-std::string LLFloaterSimpleOutfitSnapshot::Impl::getSnapshotPanelPrefix()
-{
-    return "panel_outfit_snapshot_";
-}
-
-void LLFloaterSimpleOutfitSnapshot::Impl::updateResolution(void* data)
-{
-    LLFloaterSimpleOutfitSnapshot *view = (LLFloaterSimpleOutfitSnapshot *)data;
-
-    if (!view)
-    {
-        llassert(view);
-        return;
-    }
-
-    S32 width = OUTFIT_SNAPSHOT_WIDTH;
-    S32 height = OUTFIT_SNAPSHOT_HEIGHT;
-
-    LLSnapshotLivePreview* previewp = getPreviewView();
-    if (previewp)
-    {
-        S32 original_width = 0, original_height = 0;
-        previewp->getSize(original_width, original_height);
-
-        if (gSavedSettings.getBOOL("RenderHUDInSnapshot"))
-        { //clamp snapshot resolution to window size when showing UI HUD in snapshot
-            width = llmin(width, gViewerWindow->getWindowWidthRaw());
-            height = llmin(height, gViewerWindow->getWindowHeightRaw());
-        }
-
-        llassert(width > 0 && height > 0);
-
-        previewp->setSize(width, height);
-
-        if (original_width != width || original_height != height)
-        {
-            // hide old preview as the aspect ratio could be wrong
-            checkAutoSnapshot(previewp, FALSE);
-            previewp->updateSnapshot(TRUE);
-        }
-    }
-}
-
-void LLFloaterSimpleOutfitSnapshot::Impl::setStatus(EStatus status, bool ok, const std::string& msg)
-{
-    switch (status)
-    {
-    case STATUS_READY:
-        mFloater->setCtrlsEnabled(true);
-        break;
-    case STATUS_WORKING:
-        mFloater->setCtrlsEnabled(false);
-        break;
-    case STATUS_FINISHED:
-        mFloater->setCtrlsEnabled(true);
-        break;
-    }
-
-    mStatus = status;
-}
-
-///----------------------------------------------------------------re------------
-/// Class LLFloaterSimpleOutfitSnapshot
-///----------------------------------------------------------------------------
-
-LLFloaterSimpleOutfitSnapshot::LLFloaterSimpleOutfitSnapshot(const LLSD& key)
-    : LLFloaterSnapshotBase(key),
-    mOutfitGallery(NULL)
-{
-    impl = new Impl(this);
-}
-
-LLFloaterSimpleOutfitSnapshot::~LLFloaterSimpleOutfitSnapshot()
-{
-}
-
-BOOL LLFloaterSimpleOutfitSnapshot::postBuild()
-{
-    getChild<LLUICtrl>("save_btn")->setLabelArg("[UPLOAD_COST]", std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()));
-
-    childSetAction("new_snapshot_btn", ImplBase::onClickNewSnapshot, this);
-    childSetAction("save_btn", boost::bind(&LLFloaterSimpleOutfitSnapshot::onSend, this));
-    childSetAction("cancel_btn", boost::bind(&LLFloaterSimpleOutfitSnapshot::onCancel, this));
-
-    mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
-
-    // create preview window
-    LLRect full_screen_rect = getRootView()->getRect();
-    LLSnapshotLivePreview::Params p;
-    p.rect(full_screen_rect);
-    LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
-    LLView* parent_view = gSnapshotFloaterView->getParent();
-
-    parent_view->removeChild(gSnapshotFloaterView);
-    // make sure preview is below snapshot floater
-    parent_view->addChild(previewp);
-    parent_view->addChild(gSnapshotFloaterView);
-
-    //move snapshot floater to special purpose snapshotfloaterview
-    gFloaterView->removeChild(this);
-    gSnapshotFloaterView->addChild(this);
-
-    impl->mPreviewHandle = previewp->getHandle();
-    previewp->setContainer(this);
-    impl->updateControls(this);
-    impl->setAdvanced(true);
-    impl->setSkipReshaping(true);
-
-    previewp->mKeepAspectRatio = FALSE;
-    previewp->setThumbnailPlaceholderRect(getThumbnailPlaceholderRect());
-    previewp->setAllowRenderUI(false);
-
-    return TRUE;
-}
-const S32 PREVIEW_OFFSET_X = 12;
-const S32 PREVIEW_OFFSET_Y = 70;
-
-void LLFloaterSimpleOutfitSnapshot::draw()
-{
-    LLSnapshotLivePreview* previewp = getPreviewView();
-
-    if (previewp && (previewp->isSnapshotActive() || previewp->getThumbnailLock()))
-    {
-        // don't render snapshot window in snapshot, even if "show ui" is turned on
-        return;
-    }
-
-    LLFloater::draw();
-
-    if (previewp && !isMinimized() && mThumbnailPlaceholder->getVisible())
-    {		
-        if(previewp->getThumbnailImage())
-        {
-            bool working = impl->getStatus() == ImplBase::STATUS_WORKING;
-            const LLRect& thumbnail_rect = getThumbnailPlaceholderRect();
-            const S32 thumbnail_w = previewp->getThumbnailWidth();
-            const S32 thumbnail_h = previewp->getThumbnailHeight();
-
-            S32 offset_x = PREVIEW_OFFSET_X;
-            S32 offset_y = PREVIEW_OFFSET_Y;
-
-            gGL.matrixMode(LLRender::MM_MODELVIEW);
-            // Apply floater transparency to the texture unless the floater is focused.
-            F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
-            LLColor4 color = working ? LLColor4::grey4 : LLColor4::white;
-            gl_draw_scaled_image(offset_x, offset_y, 
-                thumbnail_w, thumbnail_h,
-                previewp->getThumbnailImage(), color % alpha);
-#if LL_DARWIN
-            std::string alpha_color = getTransparencyType() == TT_ACTIVE ? "OutfitSnapshotMacMask" : "OutfitSnapshotMacMask2";
-#else
-            std::string alpha_color = getTransparencyType() == TT_ACTIVE ? "FloaterFocusBackgroundColor" : "DkGray";
-#endif
-
-            previewp->drawPreviewRect(offset_x, offset_y, LLUIColorTable::instance().getColor(alpha_color));
-
-            gGL.pushUIMatrix();
-            LLUI::translate((F32) thumbnail_rect.mLeft, (F32) thumbnail_rect.mBottom);
-            mThumbnailPlaceholder->draw();
-            gGL.popUIMatrix();
-        }
-    }
-    impl->updateLayout(this);
-}
-
-void LLFloaterSimpleOutfitSnapshot::onOpen(const LLSD& key)
-{
-    LLSnapshotLivePreview* preview = getPreviewView();
-    if (preview)
-    {
-        preview->updateSnapshot(TRUE);
-    }
-    focusFirstItem(FALSE);
-    gSnapshotFloaterView->setEnabled(TRUE);
-    gSnapshotFloaterView->setVisible(TRUE);
-    gSnapshotFloaterView->adjustToFitScreen(this, FALSE);
-
-    impl->updateControls(this);
-    impl->setStatus(ImplBase::STATUS_READY);
-}
-
-void LLFloaterSimpleOutfitSnapshot::onCancel()
-{
-    closeFloater();
-}
-
-void LLFloaterSimpleOutfitSnapshot::onSend()
-{
-    S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost();
-    if (can_afford_transaction(expected_upload_cost))
-    {
-        saveTexture();
-        postSave();
-    }
-    else
-    {
-        LLSD args;
-        args["COST"] = llformat("%d", expected_upload_cost);
-        LLNotificationsUtil::add("ErrorPhotoCannotAfford", args);
-        inventorySaveFailed();
-    }
-}
-
-void LLFloaterSimpleOutfitSnapshot::postSave()
-{
-    impl->setStatus(ImplBase::STATUS_WORKING);
-}
-
-// static 
-void LLFloaterSimpleOutfitSnapshot::update()
-{
-    LLFloaterSimpleOutfitSnapshot* inst = findInstance();
-    if (inst != NULL)
-    {
-        inst->impl->updateLivePreview();
-    }
-}
-
-
-// static
-LLFloaterSimpleOutfitSnapshot* LLFloaterSimpleOutfitSnapshot::findInstance()
-{
-    return LLFloaterReg::findTypedInstance<LLFloaterSimpleOutfitSnapshot>("simple_outfit_snapshot");
-}
-
-// static
-LLFloaterSimpleOutfitSnapshot* LLFloaterSimpleOutfitSnapshot::getInstance()
-{
-    return LLFloaterReg::getTypedInstance<LLFloaterSimpleOutfitSnapshot>("simple_outfit_snapshot");
-}
-
-void LLFloaterSimpleOutfitSnapshot::saveTexture()
-{
-     LLSnapshotLivePreview* previewp = getPreviewView();
-    if (!previewp)
-    {
-        llassert(previewp != NULL);
-        return;
-    }
-
-    if (mOutfitGallery)
-    {
-        mOutfitGallery->onBeforeOutfitSnapshotSave();
-    }
-    previewp->saveTexture(TRUE, getOutfitID().asString());
-    if (mOutfitGallery)
-    {
-        mOutfitGallery->onAfterOutfitSnapshotSave();
-    }
-    closeFloater();
-}
-
-///----------------------------------------------------------------------------
-/// Class LLSimpleOutfitSnapshotFloaterView
-///----------------------------------------------------------------------------
-
-LLSimpleOutfitSnapshotFloaterView::LLSimpleOutfitSnapshotFloaterView(const Params& p) : LLFloaterView(p)
-{
-}
-
-LLSimpleOutfitSnapshotFloaterView::~LLSimpleOutfitSnapshotFloaterView()
-{
-}
diff --git a/indra/newview/llfloatersimplesnapshot.cpp b/indra/newview/llfloatersimplesnapshot.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..58604c5628ebb496383ceceb9956f998e976539c
--- /dev/null
+++ b/indra/newview/llfloatersimplesnapshot.cpp
@@ -0,0 +1,499 @@
+/** 
+* @file llfloatersimplesnapshot.cpp
+* @brief Snapshot preview window for saving as a thumbnail
+*
+* $LicenseInfo:firstyear=2022&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2022, Linden Research, Inc.
+* 
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+* 
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+* 
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+* 
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloatersimplesnapshot.h"
+
+#include "llfloaterreg.h"
+#include "llimagefiltersmanager.h"
+#include "llinventorymodel.h"
+#include "llinventoryobserver.h"
+#include "llstatusbar.h" // can_afford_transaction()
+#include "llnotificationsutil.h"
+#include "llagent.h"
+#include "llagentbenefits.h"
+#include "llviewercontrol.h"
+#include "llviewertexturelist.h"
+
+
+
+LLSimpleSnapshotFloaterView* gSimpleSnapshotFloaterView = NULL;
+
+const S32 LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX = 256;
+const S32 LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN = 64;
+
+// Thumbnail posting coro
+
+static const std::string THUMBNAIL_UPLOAD_CAP = "InventoryThumbnailUpload";
+
+void post_thumbnail_image_coro(std::string cap_url, std::string path_to_image, LLSD first_data)
+{
+    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("post_profile_image_coro", httpPolicy));
+    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+    LLCore::HttpHeaders::ptr_t httpHeaders;
+
+    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+    httpOpts->setFollowRedirects(true);
+
+    LLSD result = httpAdapter->postAndSuspend(httpRequest, cap_url, first_data, httpOpts, httpHeaders);
+
+    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+    if (!status)
+    {
+        // todo: notification?
+        LL_WARNS("AvatarProperties") << "Failed to get uploader cap " << status.toString() << LL_ENDL;
+        return;
+    }
+    if (!result.has("uploader"))
+    {
+        // todo: notification?
+        LL_WARNS("AvatarProperties") << "Failed to get uploader cap, response contains no data." << LL_ENDL;
+        return;
+    }
+    std::string uploader_cap = result["uploader"].asString();
+    if (uploader_cap.empty())
+    {
+        LL_WARNS("AvatarProperties") << "Failed to get uploader cap, cap invalid." << LL_ENDL;
+        return;
+    }
+
+    // Upload the image
+
+    LLCore::HttpRequest::ptr_t uploaderhttpRequest(new LLCore::HttpRequest);
+    LLCore::HttpHeaders::ptr_t uploaderhttpHeaders(new LLCore::HttpHeaders);
+    LLCore::HttpOptions::ptr_t uploaderhttpOpts(new LLCore::HttpOptions);
+    S64 length;
+
+    {
+        llifstream instream(path_to_image.c_str(), std::iostream::binary | std::iostream::ate);
+        if (!instream.is_open())
+        {
+            LL_WARNS("AvatarProperties") << "Failed to open file " << path_to_image << LL_ENDL;
+            return;
+        }
+        length = instream.tellg();
+    }
+
+    uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/jp2"); // optional
+    uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_LENGTH, llformat("%d", length)); // required!
+    uploaderhttpOpts->setFollowRedirects(true);
+
+    result = httpAdapter->postFileAndSuspend(uploaderhttpRequest, uploader_cap, path_to_image, uploaderhttpOpts, uploaderhttpHeaders);
+
+    httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+    status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+    LL_DEBUGS("Thumbnail") << result << LL_ENDL;
+
+    if (!status)
+    {
+        LL_WARNS("Thumbnail") << "Failed to upload image " << status.toString() << LL_ENDL;
+        return;
+    }
+
+    if (result["state"].asString() != "complete")
+    {
+        if (result.has("message"))
+        {
+            LL_WARNS("Thumbnail") << "Failed to upload image, state " << result["state"] << " message: " << result["message"] << LL_ENDL;
+        }
+        else
+        {
+            LL_WARNS("Thumbnail") << "Failed to upload image " << result << LL_ENDL;
+        }
+        return;
+    }
+
+    if (first_data.has("category_id"))
+    {
+        LLUUID cat_id = first_data["category_id"].asUUID();
+        LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+        if (cat)
+        {
+            cat->setThumbnailUUID(result["new_asset"].asUUID());
+        }
+        gInventory.addChangedMask(LLInventoryObserver::INTERNAL, cat_id);
+    }
+    if (first_data.has("item_id"))
+    {
+        LLUUID item_id = first_data["item_id"].asUUID();
+        LLViewerInventoryItem* item = gInventory.getItem(item_id);
+        if (item)
+        {
+            item->setThumbnailUUID(result["new_asset"].asUUID());
+        }
+        // Are we supposed to get BulkUpdateInventory?
+        gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Class LLFloaterSimpleSnapshot::Impl
+///----------------------------------------------------------------------------
+
+LLSnapshotModel::ESnapshotFormat LLFloaterSimpleSnapshot::Impl::getImageFormat(LLFloaterSnapshotBase* floater)
+{
+    return LLSnapshotModel::SNAPSHOT_FORMAT_PNG;
+}
+
+LLSnapshotModel::ESnapshotLayerType LLFloaterSimpleSnapshot::Impl::getLayerType(LLFloaterSnapshotBase* floater)
+{
+    return LLSnapshotModel::SNAPSHOT_TYPE_COLOR;
+}
+
+void LLFloaterSimpleSnapshot::Impl::updateControls(LLFloaterSnapshotBase* floater)
+{
+    LLSnapshotLivePreview* previewp = getPreviewView();
+    updateResolution(floater);
+    if (previewp)
+    {
+        previewp->setSnapshotType(LLSnapshotModel::ESnapshotType::SNAPSHOT_TEXTURE);
+        previewp->setSnapshotFormat(LLSnapshotModel::ESnapshotFormat::SNAPSHOT_FORMAT_PNG);
+        previewp->setSnapshotBufferType(LLSnapshotModel::ESnapshotLayerType::SNAPSHOT_TYPE_COLOR);
+    }
+}
+
+std::string LLFloaterSimpleSnapshot::Impl::getSnapshotPanelPrefix()
+{
+    return "panel_outfit_snapshot_";
+}
+
+void LLFloaterSimpleSnapshot::Impl::updateResolution(void* data)
+{
+    LLFloaterSimpleSnapshot *view = (LLFloaterSimpleSnapshot *)data;
+
+    if (!view)
+    {
+        llassert(view);
+        return;
+    }
+
+    S32 width = THUMBNAIL_SNAPSHOT_DIM_MAX;
+    S32 height = THUMBNAIL_SNAPSHOT_DIM_MAX;
+
+    LLSnapshotLivePreview* previewp = getPreviewView();
+    if (previewp)
+    {
+        S32 original_width = 0, original_height = 0;
+        previewp->getSize(original_width, original_height);
+
+        if (gSavedSettings.getBOOL("RenderHUDInSnapshot"))
+        { //clamp snapshot resolution to window size when showing UI HUD in snapshot
+            width = llmin(width, gViewerWindow->getWindowWidthRaw());
+            height = llmin(height, gViewerWindow->getWindowHeightRaw());
+        }
+
+        llassert(width > 0 && height > 0);
+
+        previewp->setSize(width, height);
+
+        if (original_width != width || original_height != height)
+        {
+            // hide old preview as the aspect ratio could be wrong
+            checkAutoSnapshot(previewp, FALSE);
+            previewp->updateSnapshot(TRUE);
+        }
+    }
+}
+
+void LLFloaterSimpleSnapshot::Impl::setStatus(EStatus status, bool ok, const std::string& msg)
+{
+    switch (status)
+    {
+    case STATUS_READY:
+        mFloater->setCtrlsEnabled(true);
+        break;
+    case STATUS_WORKING:
+        mFloater->setCtrlsEnabled(false);
+        break;
+    case STATUS_FINISHED:
+        mFloater->setCtrlsEnabled(true);
+        break;
+    }
+
+    mStatus = status;
+}
+
+///----------------------------------------------------------------re------------
+/// Class LLFloaterSimpleSnapshot
+///----------------------------------------------------------------------------
+
+LLFloaterSimpleSnapshot::LLFloaterSimpleSnapshot(const LLSD& key)
+    : LLFloaterSnapshotBase(key)
+    , mOwner(NULL)
+    , mContextConeOpacity(0.f)
+{
+    impl = new Impl(this);
+}
+
+LLFloaterSimpleSnapshot::~LLFloaterSimpleSnapshot()
+{
+}
+
+BOOL LLFloaterSimpleSnapshot::postBuild()
+{
+    childSetAction("new_snapshot_btn", ImplBase::onClickNewSnapshot, this);
+    childSetAction("save_btn", boost::bind(&LLFloaterSimpleSnapshot::onSend, this));
+    childSetAction("cancel_btn", boost::bind(&LLFloaterSimpleSnapshot::onCancel, this));
+
+    mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
+
+    // create preview window
+    LLRect full_screen_rect = getRootView()->getRect();
+    LLSnapshotLivePreview::Params p;
+    p.rect(full_screen_rect);
+    LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
+
+    // Do not move LLFloaterSimpleSnapshot floater into gSnapshotFloaterView
+    // since it can be a dependednt floater and does not draw UI
+
+    impl->mPreviewHandle = previewp->getHandle();
+    previewp->setContainer(this);
+    impl->updateControls(this);
+    impl->setAdvanced(true);
+    impl->setSkipReshaping(true);
+
+    previewp->mKeepAspectRatio = FALSE;
+    previewp->setThumbnailPlaceholderRect(getThumbnailPlaceholderRect());
+    previewp->setAllowRenderUI(false);
+    previewp->setThumbnailSubsampled(TRUE);
+
+    return TRUE;
+}
+
+const S32 PREVIEW_OFFSET_Y = 70;
+
+void LLFloaterSimpleSnapshot::draw()
+{
+    if (mOwner)
+    {
+        static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f);
+        drawConeToOwner(mContextConeOpacity, max_opacity, mOwner);
+    }
+
+    LLSnapshotLivePreview* previewp = getPreviewView();
+
+    if (previewp && (previewp->isSnapshotActive() || previewp->getThumbnailLock()))
+    {
+        // don't render snapshot window in snapshot, even if "show ui" is turned on
+        return;
+    }
+
+    LLFloater::draw();
+
+    if (previewp && !isMinimized() && mThumbnailPlaceholder->getVisible())
+    {		
+        if(previewp->getThumbnailImage())
+        {
+            bool working = impl->getStatus() == ImplBase::STATUS_WORKING;
+            const S32 thumbnail_w = previewp->getThumbnailWidth();
+            const S32 thumbnail_h = previewp->getThumbnailHeight();
+
+            LLRect local_rect = getLocalRect();
+            S32 offset_x = (local_rect.getWidth() - thumbnail_w) / 2;
+            S32 offset_y = PREVIEW_OFFSET_Y;
+
+            gGL.matrixMode(LLRender::MM_MODELVIEW);
+            // Apply floater transparency to the texture unless the floater is focused.
+            F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
+            LLColor4 color = working ? LLColor4::grey4 : LLColor4::white;
+            gl_draw_scaled_image(offset_x, offset_y, 
+                thumbnail_w, thumbnail_h,
+                previewp->getThumbnailImage(), color % alpha);
+        }
+    }
+    impl->updateLayout(this);
+}
+
+void LLFloaterSimpleSnapshot::onOpen(const LLSD& key)
+{
+    LLSnapshotLivePreview* preview = getPreviewView();
+    if (preview)
+    {
+        preview->updateSnapshot(TRUE);
+    }
+    focusFirstItem(FALSE);
+    gSnapshotFloaterView->setEnabled(TRUE);
+    gSnapshotFloaterView->setVisible(TRUE);
+    gSnapshotFloaterView->adjustToFitScreen(this, FALSE);
+
+    impl->updateControls(this);
+    impl->setStatus(ImplBase::STATUS_READY);
+
+    mInventoryId = key["item_id"].asUUID();
+    mTaskId = key["task_id"].asUUID();
+}
+
+void LLFloaterSimpleSnapshot::onCancel()
+{
+    closeFloater();
+}
+
+void LLFloaterSimpleSnapshot::onSend()
+{
+    LLSnapshotLivePreview* previewp = getPreviewView();
+
+    std::string temp_file = gDirUtilp->getTempFilename();
+    if (previewp->createUploadFile(temp_file, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN))
+    {
+        uploadImageUploadFile(temp_file, mInventoryId, mTaskId);
+        closeFloater();
+    }
+    else
+    {
+        LLSD notif_args;
+        notif_args["REASON"] = LLImage::getLastError().c_str();
+        LLNotificationsUtil::add("CannotUploadTexture", notif_args);
+    }
+}
+
+void LLFloaterSimpleSnapshot::postSave()
+{
+    impl->setStatus(ImplBase::STATUS_WORKING);
+}
+
+// static
+void LLFloaterSimpleSnapshot::uploadThumbnail(const std::string &file_path, const LLUUID &inventory_id, const LLUUID &task_id)
+{
+    // generate a temp texture file for coroutine
+    std::string temp_file = gDirUtilp->getTempFilename();
+    U32 codec = LLImageBase::getCodecFromExtension(gDirUtilp->getExtension(file_path));
+    if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN, true))
+    {
+        LLSD notif_args;
+        notif_args["REASON"] = LLImage::getLastError().c_str();
+        LLNotificationsUtil::add("CannotUploadTexture", notif_args);
+        LL_WARNS("Thumbnail") << "Failed to upload thumbnail for " << inventory_id << " " << task_id << ", reason: " << notif_args["REASON"].asString() << LL_ENDL;
+        return;
+    }
+    uploadImageUploadFile(temp_file, inventory_id, task_id);
+}
+
+// static
+void LLFloaterSimpleSnapshot::uploadThumbnail(LLPointer<LLImageRaw> raw_image, const LLUUID& inventory_id, const LLUUID& task_id)
+{
+    std::string temp_file = gDirUtilp->getTempFilename();
+    if (!LLViewerTextureList::createUploadFile(raw_image, temp_file, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN))
+    {
+        LLSD notif_args;
+        notif_args["REASON"] = LLImage::getLastError().c_str();
+        LLNotificationsUtil::add("CannotUploadTexture", notif_args);
+        LL_WARNS("Thumbnail") << "Failed to upload thumbnail for " << inventory_id << " " << task_id << ", reason: " << notif_args["REASON"].asString() << LL_ENDL;
+        return;
+    }
+    uploadImageUploadFile(temp_file, inventory_id, task_id);
+}
+
+// static
+void LLFloaterSimpleSnapshot::uploadImageUploadFile(const std::string &temp_file, const LLUUID &inventory_id, const LLUUID &task_id)
+{
+    LLSD data;
+
+    if (task_id.notNull())
+    {
+        data["item_id"] = inventory_id;
+        data["task_id"] = task_id;
+    }
+    else if (gInventory.getCategory(inventory_id))
+    {
+        data["category_id"] = inventory_id;
+    }
+    else
+    {
+        data["item_id"] = inventory_id;
+    }
+
+    std::string cap_url = gAgent.getRegionCapability(THUMBNAIL_UPLOAD_CAP);
+    if (cap_url.empty())
+    {
+        LLSD args;
+        args["CAPABILITY"] = THUMBNAIL_UPLOAD_CAP;
+        LLNotificationsUtil::add("RegionCapabilityRequestError", args);
+        LL_WARNS("Thumbnail") << "Failed to upload profile image for item " << inventory_id << " " << task_id << ", no cap found" << LL_ENDL;
+        return;
+    }
+
+    LLCoros::instance().launch("postAgentUserImageCoro",
+        boost::bind(post_thumbnail_image_coro, cap_url, temp_file, data));
+}
+
+void LLFloaterSimpleSnapshot::update()
+{
+    // initializes snapshots when needed
+    LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("simple_snapshot");
+    for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin();
+        iter != inst_list.end(); ++iter)
+    {
+        LLFloaterSimpleSnapshot* floater = dynamic_cast<LLFloaterSimpleSnapshot*>(*iter);
+        if (floater)
+        {
+            floater->impl->updateLivePreview();
+        }
+    }
+}
+
+
+// static
+LLFloaterSimpleSnapshot* LLFloaterSimpleSnapshot::findInstance(const LLSD &key)
+{
+    return LLFloaterReg::findTypedInstance<LLFloaterSimpleSnapshot>("simple_snapshot", key);
+}
+
+// static
+LLFloaterSimpleSnapshot* LLFloaterSimpleSnapshot::getInstance(const LLSD &key)
+{
+    return LLFloaterReg::getTypedInstance<LLFloaterSimpleSnapshot>("simple_snapshot", key);
+}
+
+void LLFloaterSimpleSnapshot::saveTexture()
+{
+    LLSnapshotLivePreview* previewp = getPreviewView();
+    if (!previewp)
+    {
+        llassert(previewp != NULL);
+        return;
+    }
+
+    previewp->saveTexture(TRUE, getInventoryId().asString());
+    closeFloater();
+}
+
+///----------------------------------------------------------------------------
+/// Class LLSimpleOutfitSnapshotFloaterView
+///----------------------------------------------------------------------------
+
+LLSimpleSnapshotFloaterView::LLSimpleSnapshotFloaterView(const Params& p) : LLFloaterView(p)
+{
+}
+
+LLSimpleSnapshotFloaterView::~LLSimpleSnapshotFloaterView()
+{
+}
diff --git a/indra/newview/llfloatersimpleoutfitsnapshot.h b/indra/newview/llfloatersimplesnapshot.h
similarity index 62%
rename from indra/newview/llfloatersimpleoutfitsnapshot.h
rename to indra/newview/llfloatersimplesnapshot.h
index cc9a6c5d1e4016ef57382321ce743b09ddff1f96..91a81ee5c3bcec771a0699ec3e15ae3fa4db7e00 100644
--- a/indra/newview/llfloatersimpleoutfitsnapshot.h
+++ b/indra/newview/llfloatersimplesnapshot.h
@@ -1,6 +1,6 @@
 /**
-* @file llfloatersimpleoutfitsnapshot.h
-* @brief Snapshot preview window for saving as an outfit thumbnail in visual outfit gallery
+* @file llfloatersimplesnapshot.h
+* @brief Snapshot preview window for saving as a thumbnail
 *
 * $LicenseInfo:firstyear=2022&license=viewerlgpl$
 * Second Life Viewer Source Code
@@ -24,26 +24,25 @@
 * $/LicenseInfo$
 */
 
-#ifndef LL_LLFLOATERSIMPLEOUTFITSNAPSHOT_H
-#define LL_LLFLOATERSIMPLEOUTFITSNAPSHOT_H
+#ifndef LL_LLFLOATERSIMPLESNAPSHOT_H
+#define LL_LLFLOATERSIMPLESNAPSHOT_H
 
 #include "llfloater.h"
 #include "llfloatersnapshot.h"
-#include "lloutfitgallery.h"
 #include "llsnapshotlivepreview.h"
 
 ///----------------------------------------------------------------------------
-/// Class LLFloaterSimpleOutfitSnapshot
+/// Class LLFloaterSimpleSnapshot
 ///----------------------------------------------------------------------------
 
-class LLFloaterSimpleOutfitSnapshot : public LLFloaterSnapshotBase
+class LLFloaterSimpleSnapshot : public LLFloaterSnapshotBase
 {
-    LOG_CLASS(LLFloaterSimpleOutfitSnapshot);
+    LOG_CLASS(LLFloaterSimpleSnapshot);
 
 public:
 
-    LLFloaterSimpleOutfitSnapshot(const LLSD& key);
-    ~LLFloaterSimpleOutfitSnapshot();
+    LLFloaterSimpleSnapshot(const LLSD& key);
+    ~LLFloaterSimpleSnapshot();
 
     BOOL postBuild();
     void onOpen(const LLSD& key);
@@ -51,36 +50,48 @@ class LLFloaterSimpleOutfitSnapshot : public LLFloaterSnapshotBase
 
     static void update();
 
-    static LLFloaterSimpleOutfitSnapshot* getInstance();
-    static LLFloaterSimpleOutfitSnapshot* findInstance();
+    static LLFloaterSimpleSnapshot* getInstance(const LLSD &key);
+    static LLFloaterSimpleSnapshot* findInstance(const LLSD &key);
     void saveTexture();
 
     const LLRect& getThumbnailPlaceholderRect() { return mThumbnailPlaceholder->getRect(); }
 
-    void setOutfitID(LLUUID id) { mOutfitID = id; }
-    LLUUID getOutfitID() { return mOutfitID; }
-    void setGallery(LLOutfitGallery* gallery) { mOutfitGallery = gallery; }
+    void setInventoryId(const LLUUID &inventory_id) { mInventoryId = inventory_id; }
+    LLUUID getInventoryId() { return mInventoryId; }
+    void setTaskId(const LLUUID &task_id) { mTaskId = task_id; }
+    void setOwner(LLView *owner_view) { mOwner = owner_view; }
 
     void postSave();
+    static void uploadThumbnail(const std::string &file_path, const LLUUID &inventory_id, const LLUUID &task_id);
+    static void uploadThumbnail(LLPointer<LLImageRaw> raw_image, const LLUUID& inventory_id, const LLUUID& task_id);
 
     class Impl;
     friend class Impl;
 
+    static const S32 THUMBNAIL_SNAPSHOT_DIM_MAX;
+    static const S32 THUMBNAIL_SNAPSHOT_DIM_MIN;
+
 private:
     void onSend();
     void onCancel();
 
-    LLUUID mOutfitID;
-    LLOutfitGallery* mOutfitGallery;
+    // uploads upload-ready file
+    static void uploadImageUploadFile(const std::string &temp_file, const LLUUID &inventory_id, const LLUUID &task_id);
+
+    LLUUID mInventoryId;
+    LLUUID mTaskId;
+
+    LLView* mOwner;
+    F32	 mContextConeOpacity;
 };
 
 ///----------------------------------------------------------------------------
-/// Class LLFloaterSimpleOutfitSnapshot::Impl
+/// Class LLFloaterSimpleSnapshot::Impl
 ///----------------------------------------------------------------------------
 
-class LLFloaterSimpleOutfitSnapshot::Impl : public LLFloaterSnapshotBase::ImplBase
+class LLFloaterSimpleSnapshot::Impl : public LLFloaterSnapshotBase::ImplBase
 {
-    LOG_CLASS(LLFloaterSimpleOutfitSnapshot::Impl);
+    LOG_CLASS(LLFloaterSimpleSnapshot::Impl);
 public:
     Impl(LLFloaterSnapshotBase* floater)
         : LLFloaterSnapshotBase::ImplBase(floater)
@@ -108,7 +119,7 @@ class LLFloaterSimpleOutfitSnapshot::Impl : public LLFloaterSnapshotBase::ImplBa
 /// Class LLSimpleOutfitSnapshotFloaterView
 ///----------------------------------------------------------------------------
 
-class LLSimpleOutfitSnapshotFloaterView : public LLFloaterView
+class LLSimpleSnapshotFloaterView : public LLFloaterView
 {
 public:
     struct Params
@@ -117,13 +128,13 @@ class LLSimpleOutfitSnapshotFloaterView : public LLFloaterView
     };
 
 protected:
-    LLSimpleOutfitSnapshotFloaterView(const Params& p);
+    LLSimpleSnapshotFloaterView(const Params& p);
     friend class LLUICtrlFactory;
 
 public:
-    virtual ~LLSimpleOutfitSnapshotFloaterView();
+    virtual ~LLSimpleSnapshotFloaterView();
 };
 
-extern LLSimpleOutfitSnapshotFloaterView* gSimpleOutfitSnapshotFloaterView;
+extern LLSimpleSnapshotFloaterView* gSimpleOutfitSnapshotFloaterView;
 
-#endif // LL_LLFLOATERSIMPLEOUTFITSNAPSHOT_H
+#endif // LL_LLFLOATERSIMPLESNAPSHOT_H
diff --git a/indra/newview/llfloatertexturepicker.cpp b/indra/newview/llfloatertexturepicker.cpp
index ea9522f30d421d9360add083228d9aa23befd99e..6e8d34718c96f5133a41e6ece86108adcbcb3938 100644
--- a/indra/newview/llfloatertexturepicker.cpp
+++ b/indra/newview/llfloatertexturepicker.cpp
@@ -85,6 +85,9 @@ LLFloaterTexturePicker::LLFloaterTexturePicker(
 	mSelectedItemPinned( FALSE ),
 	mCanApply(true),
 	mCanPreview(true),
+    mLimitsSet(false),
+    mMaxDim(S32_MAX),
+    mMinDim(0),
 	mPreviewSettingChanged(false),
 	mOnFloaterCommitCallback(NULL),
 	mOnFloaterCloseCallback(NULL),
@@ -187,8 +190,9 @@ void LLFloaterTexturePicker::stopUsingPipette()
 	}
 }
 
-void LLFloaterTexturePicker::updateImageStats()
+bool LLFloaterTexturePicker::updateImageStats()
 {
+    bool result = true;
     if (mGLTFMaterial.notNull())
     {
         S32 width = 0;
@@ -244,14 +248,31 @@ void LLFloaterTexturePicker::updateImageStats()
 	else if (mTexturep.notNull())
 	{
 		//RN: have we received header data for this image?
-		if (mTexturep->getFullWidth() > 0 && mTexturep->getFullHeight() > 0)
+        S32 width = mTexturep->getFullWidth();
+        S32 height = mTexturep->getFullHeight();
+		if (width > 0 && height > 0)
 		{
-			std::string formatted_dims = llformat("%d x %d", mTexturep->getFullWidth(),mTexturep->getFullHeight());
-			mResolutionLabel->setTextArg("[DIMENSIONS]", formatted_dims);
-			if (mOnUpdateImageStatsCallback)
-			{
-				mOnUpdateImageStatsCallback(mTexturep);
-			}
+            if ((mLimitsSet && (width != height))
+                || width < mMinDim
+                || width > mMaxDim
+                || height < mMinDim
+                || height > mMaxDim
+                )
+            {
+                std::string formatted_dims = llformat("%dx%d", width, height);
+                mResolutionWarning->setTextArg("[TEXDIM]", formatted_dims);
+                result = false;
+            }
+            else
+            {
+                std::string formatted_dims = llformat("%d x %d", width, height);
+                mResolutionLabel->setTextArg("[DIMENSIONS]", formatted_dims);
+            }
+
+            if (mOnUpdateImageStatsCallback)
+            {
+                mOnUpdateImageStatsCallback(mTexturep);
+            }
 		}
 		else
 		{
@@ -262,6 +283,21 @@ void LLFloaterTexturePicker::updateImageStats()
 	{
 		mResolutionLabel->setTextArg("[DIMENSIONS]", std::string(""));
 	}
+    mResolutionLabel->setVisible(result);
+    mResolutionWarning->setVisible(!result);
+
+    // Hide buttons and pipete to make space for mResolutionWarning
+    // Hiding buttons is suboptimal, but at the moment limited to inventory thumbnails
+    // may be this should be an info/warning icon with a tooltip?
+    S32 index = mModeSelector->getValue().asInteger();
+    if (index == 0)
+    {
+        mDefaultBtn->setVisible(result);
+        mNoneBtn->setVisible(result);
+        mBlankBtn->setVisible(result);
+        mPipetteBtn->setVisible(result);
+    }
+    return result;
 }
 
 // virtual
@@ -394,12 +430,24 @@ BOOL LLFloaterTexturePicker::postBuild()
 	mTentativeLabel = getChild<LLTextBox>("Multiple");
 
 	mResolutionLabel = getChild<LLTextBox>("size_lbl");
+    mResolutionWarning = getChild<LLTextBox>("over_limit_lbl");
+
 
+    mDefaultBtn = getChild<LLButton>("Default");
+    mNoneBtn = getChild<LLButton>("None");
+    mBlankBtn = getChild<LLButton>("Blank");
+	mTransparentBtn = getChild<LLButton>("Transparent");
+    mPipetteBtn = getChild<LLButton>("Pipette");
+    mSelectBtn = getChild<LLButton>("Select");
+    mCancelBtn = getChild<LLButton>("Cancel");
 
-	childSetAction("Default",LLFloaterTexturePicker::onBtnSetToDefault,this);
-	childSetAction("None", LLFloaterTexturePicker::onBtnNone,this);
-	childSetAction("Blank", LLFloaterTexturePicker::onBtnBlank,this);
-    childSetAction("Transparent", LLFloaterTexturePicker::onBtnTransparent, this);
+    mDefaultBtn->setClickedCallback(boost::bind(LLFloaterTexturePicker::onBtnSetToDefault,this));
+    mNoneBtn->setClickedCallback(boost::bind(LLFloaterTexturePicker::onBtnNone, this));
+    mBlankBtn->setClickedCallback(boost::bind(LLFloaterTexturePicker::onBtnBlank, this));
+    mPipetteBtn->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onBtnPipette, this));
+    mSelectBtn->setClickedCallback(boost::bind(LLFloaterTexturePicker::onBtnSelect, this));
+    mCancelBtn->setClickedCallback(boost::bind(LLFloaterTexturePicker::onBtnCancel, this));
+    mTransparentBtn->setClickedCallback(boost::bind(LLFloaterTexturePicker::onBtnTransparent, this));
 
     mFilterEdit = getChild<LLFilterEditor>("inventory search editor");
     mFilterEdit->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onFilterEdit, this, _2));
@@ -483,12 +531,13 @@ void LLFloaterTexturePicker::draw()
 
     // This is going to spam mOnUpdateImageStatsCallback,
     // either move elsewhere or fix to cause update once per image
-	updateImageStats();
+	bool valid_dims = updateImageStats();
 
 	// if we're inactive, gray out "apply immediate" checkbox
-	getChildView("Select")->setEnabled(mActive && mCanApply);
-	getChildView("Pipette")->setEnabled(mActive);
-	getChild<LLUICtrl>("Pipette")->setValue(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance());
+	getChildView("show_folders_check")->setEnabled(mActive && mCanApplyImmediately && !mNoCopyTextureSelected);
+	mSelectBtn->setEnabled(mActive && mCanApply && valid_dims);
+	mPipetteBtn->setEnabled(mActive);
+    mPipetteBtn->setValue(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance());
 
 	//BOOL allow_copy = FALSE;
 	if( mOwner ) 
@@ -533,10 +582,10 @@ void LLFloaterTexturePicker::draw()
 			mTentativeLabel->setVisible( FALSE  );
 		}
 
-		getChildView("Default")->setEnabled(mImageAssetID != mDefaultImageAssetID || mTentative);
-        getChildView("Transparent")->setEnabled((mImageAssetID != mTransparentImageAssetID && mTransparentImageAssetID.notNull()) || mTentative);
-		getChildView("Blank")->setEnabled((mImageAssetID != mBlankImageAssetID && mBlankImageAssetID.notNull()) || mTentative);
-		getChildView("None")->setEnabled(mAllowNoTexture && (!mImageAssetID.isNull() || mTentative));
+		mDefaultBtn->setEnabled(mImageAssetID != mDefaultImageAssetID || mTentative);
+        mTransparentBtn->setEnabled((mImageAssetID != mTransparentImageAssetID && mTransparentImageAssetID.notNull()) || mTentative);
+		mBlankBtn->setEnabled((mImageAssetID != mBlankImageAssetID && mBlankImageAssetID.notNull()) || mTentative);
+		mNoneBtn->setEnabled(mAllowNoTexture && (!mImageAssetID.isNull() || mTentative));
 
 		LLFloater::draw();
 
@@ -661,17 +710,86 @@ const LLUUID& LLFloaterTexturePicker::findItemID(const LLUUID& asset_id, BOOL co
 
 void LLFloaterTexturePicker::commitIfImmediateSet()
 {
-	if (!mNoCopyTextureSelected && mOnFloaterCommitCallback && mCanApply)
+	if (!mNoCopyTextureSelected && mCanApply)
 	{
-		mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CHANGE, LLUUID::null);
+        commitCallback(LLTextureCtrl::TEXTURE_CHANGE);
 	}
 }
 
+void LLFloaterTexturePicker::commitCallback(LLTextureCtrl::ETexturePickOp op)
+{
+    if (!mOnFloaterCommitCallback)
+    {
+        return;
+    }
+    LLUUID asset_id = mImageAssetID;
+    LLUUID inventory_id;
+    LLPickerSource mode = (LLPickerSource)mModeSelector->getValue().asInteger();
+
+    switch (mode)
+    {
+        case PICKER_INVENTORY:
+            {
+                LLFolderView* root_folder = mInventoryPanel->getRootFolder();
+                if (root_folder && root_folder->getCurSelectedItem())
+                {
+                    LLFolderViewItem* last_selected = root_folder->getCurSelectedItem();
+                    LLFolderViewModelItemInventory* inv_view = static_cast<LLFolderViewModelItemInventory*>(last_selected->getViewModelItem());
+
+                    LLInventoryItem* itemp = gInventory.getItem(inv_view->getUUID());
+                    if (itemp && itemp->getAssetUUID() == mImageAssetID)
+                    {
+                        inventory_id = inv_view->getUUID();
+                    }
+                    else
+                    {
+                        mode = PICKER_UNKNOWN; // source of id unknown
+                    }
+                }
+                else
+                {
+                    mode = PICKER_UNKNOWN; // source of id unknown
+                }
+                break;
+            }
+        case PICKER_LOCAL:
+            {
+                if (!mLocalScrollCtrl->getAllSelected().empty())
+                {
+                    LLSD data = mLocalScrollCtrl->getFirstSelected()->getValue();
+                    LLUUID temp_id = data["id"];
+                    S32 asset_type = data["type"].asInteger();
+
+                    if (LLAssetType::AT_MATERIAL == asset_type)
+                    {
+                        asset_id = LLLocalGLTFMaterialMgr::getInstance()->getWorldID(temp_id);
+                    }
+                    else
+                    {
+                        asset_id = LLLocalBitmapMgr::getInstance()->getWorldID(temp_id);
+                    }
+                }
+                else
+                {
+                    asset_id = mImageAssetID;
+                    mode = PICKER_UNKNOWN; // source of id unknown
+                }
+                break;
+            }
+        case PICKER_BAKE:
+            break;
+        default:
+            mode = PICKER_UNKNOWN; // source of id unknown
+            break;
+    }
+
+    mOnFloaterCommitCallback(op, mode, asset_id, inventory_id);
+}
 void LLFloaterTexturePicker::commitCancel()
 {
 	if (!mNoCopyTextureSelected && mOnFloaterCommitCallback && mCanApply)
 	{
-		mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CANCEL, LLUUID::null);
+		mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CANCEL, PICKER_UNKNOWN, mOriginalImageAssetID, LLUUID::null);
 	}
 }
 
@@ -734,7 +852,7 @@ void LLFloaterTexturePicker::onBtnCancel(void* userdata)
 	self->setImageID( self->mOriginalImageAssetID );
 	if (self->mOnFloaterCommitCallback)
 	{
-		self->mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CANCEL, LLUUID::null);
+		self->mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CANCEL, PICKER_UNKNOWN, self->mOriginalImageAssetID, LLUUID::null);
 	}
 	self->mViewModel->resetDirty();
 	self->closeFloater();
@@ -743,30 +861,10 @@ void LLFloaterTexturePicker::onBtnCancel(void* userdata)
 // static
 void LLFloaterTexturePicker::onBtnSelect(void* userdata)
 {
-	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
-	LLUUID local_id = LLUUID::null;
-	if (self->mOwner)
-	{
-		if (self->mLocalScrollCtrl->getVisible() && !self->mLocalScrollCtrl->getAllSelected().empty())
-		{
-            LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue();
-            LLUUID temp_id = data["id"];
-            S32 asset_type = data["type"].asInteger();
-
-            if (LLAssetType::AT_MATERIAL == asset_type)
-            {
-                local_id = LLLocalGLTFMaterialMgr::getInstance()->getWorldID(temp_id);
-            }
-            else
-            {
-                local_id = LLLocalBitmapMgr::getInstance()->getWorldID(temp_id);
-            }
-		}
-	}
-	
+	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;	
 	if (self->mOnFloaterCommitCallback)
 	{
-		self->mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_SELECT, local_id);
+		self->commitCallback(LLTextureCtrl::TEXTURE_SELECT);
 	}
 	self->closeFloater();
 }
@@ -841,27 +939,31 @@ void LLFloaterTexturePicker::onModeSelect(LLUICtrl* ctrl, void *userdata)
 	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
     int index = self->mModeSelector->getValue().asInteger();
 
-	self->getChild<LLButton>("Default")->setVisible(index == 0 ? TRUE : FALSE);
-    self->getChild<LLButton>("Transparent")->setVisible(index == 0 ? TRUE : FALSE);
-	self->getChild<LLButton>("Blank")->setVisible(index == 0 ? TRUE : FALSE);
-	self->getChild<LLButton>("None")->setVisible(index == 0 ? TRUE : FALSE);
-	self->getChild<LLFilterEditor>("inventory search editor")->setVisible(index == 0 ? TRUE : FALSE);
-	self->getChild<LLInventoryPanel>("inventory panel")->setVisible(index == 0 ? TRUE : FALSE);
-    self->getChild<LLLineEditor>("uuid_editor")->setVisible(index == 0 ? TRUE : FALSE);
-    self->getChild<LLButton>("apply_uuid_btn")->setVisible(index == 0 ? TRUE : FALSE);
+	self->mDefaultBtn->setVisible(index == PICKER_INVENTORY ? TRUE : FALSE);
+    self->mTransparentBtn->setVisible(index == 0 ? TRUE : FALSE);
+	self->mBlankBtn->setVisible(index == PICKER_INVENTORY ? TRUE : FALSE);
+	self->mNoneBtn->setVisible(index == PICKER_INVENTORY ? TRUE : FALSE);
+	self->getChild<LLFilterEditor>("inventory search editor")->setVisible(index == PICKER_INVENTORY ? TRUE : FALSE);
+	self->getChild<LLInventoryPanel>("inventory panel")->setVisible(index == PICKER_INVENTORY ? TRUE : FALSE);
+    self->getChild<LLLineEditor>("uuid_editor")->setVisible(index == PICKER_INVENTORY ? TRUE : FALSE);
+    self->getChild<LLButton>("apply_uuid_btn")->setVisible(index == PICKER_INVENTORY ? TRUE : FALSE);
 
-	self->getChild<LLButton>("l_add_btn")->setVisible(index == 1 ? TRUE : FALSE);
-	self->getChild<LLButton>("l_rem_btn")->setVisible(index == 1 ? TRUE : FALSE);
-	self->getChild<LLButton>("l_upl_btn")->setVisible(index == 1 ? TRUE : FALSE);
-	self->getChild<LLScrollListCtrl>("l_name_list")->setVisible(index == 1 ? TRUE : FALSE);
+	/*self->getChild<LLCheckBox>("show_folders_check")->setVisible(mode);
+	  no idea under which conditions the above is even shown, needs testing. */
 
-	self->getChild<LLComboBox>("l_bake_use_texture_combo_box")->setVisible(index == 2 ? TRUE : FALSE);
+	self->getChild<LLButton>("l_add_btn")->setVisible(index == PICKER_LOCAL ? TRUE : FALSE);
+	self->getChild<LLButton>("l_rem_btn")->setVisible(index == PICKER_LOCAL ? TRUE : FALSE);
+	self->getChild<LLButton>("l_upl_btn")->setVisible(index == PICKER_LOCAL ? TRUE : FALSE);
+	self->getChild<LLScrollListCtrl>("l_name_list")->setVisible(index == PICKER_LOCAL ? TRUE : FALSE);
 
-    bool pipette_visible = (index == 0)
+	self->getChild<LLComboBox>("l_bake_use_texture_combo_box")->setVisible(index == PICKER_BAKE ? TRUE : FALSE);
+	self->getChild<LLCheckBoxCtrl>("hide_base_mesh_region")->setVisible(FALSE);// index == 2 ? TRUE : FALSE);
+
+    bool pipette_visible = (index == PICKER_INVENTORY)
         && (self->mInventoryPickType != LLTextureCtrl::PICK_MATERIAL);
-	self->getChild<LLButton>("Pipette")->setVisible(pipette_visible);
+	self->mPipetteBtn->setVisible(pipette_visible);
 
-	if (index == 2)
+	if (index == PICKER_BAKE)
 	{
 		self->stopUsingPipette();
 
@@ -1047,7 +1149,7 @@ void LLFloaterTexturePicker::onLocalScrollCommit(LLUICtrl* ctrl, void* userdata)
 		{
 			if (self->mOnFloaterCommitCallback)
 			{
-				self->mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CHANGE, inworld_id);
+				self->mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CHANGE, PICKER_LOCAL, inworld_id, LLUUID::null);
 			}
 		}
 	}
@@ -1137,10 +1239,10 @@ void LLFloaterTexturePicker::onBakeTextureSelect(LLUICtrl* ctrl, void *user_data
 	}
 }
 
-void LLFloaterTexturePicker::setCanApply(bool can_preview, bool can_apply)
+void LLFloaterTexturePicker::setCanApply(bool can_preview, bool can_apply, bool inworld_image)
 {
-	getChildRef<LLUICtrl>("Select").setEnabled(can_apply);
-	getChildRef<LLUICtrl>("preview_disabled").setVisible(!can_preview);
+	mSelectBtn->setEnabled(can_apply);
+	getChildRef<LLUICtrl>("preview_disabled").setVisible(!can_preview && inworld_image);
 	getChildRef<LLUICtrl>("apply_immediate_check").setVisible(can_preview);
 
 	mCanApply = can_apply;
@@ -1148,6 +1250,15 @@ void LLFloaterTexturePicker::setCanApply(bool can_preview, bool can_apply)
 	mPreviewSettingChanged = true;
 }
 
+void LLFloaterTexturePicker::setMinDimentionsLimits(S32 min_dim)
+{
+    mMinDim = min_dim;
+    mLimitsSet = true;
+
+    std::string formatted_dims = llformat("%dx%d", mMinDim, mMinDim);
+    mResolutionWarning->setTextArg("[MINTEXDIM]", formatted_dims);
+}
+
 void LLFloaterTexturePicker::onFilterEdit(const std::string& search_string )
 {
 	std::string upper_case_search_string = search_string;
@@ -1285,8 +1396,8 @@ void LLFloaterTexturePicker::setInventoryPickType(LLTextureCtrl::EPickInventoryT
 
 void LLFloaterTexturePicker::setImmediateFilterPermMask(PermissionMask mask)
 {
-	mImmediateFilterPermMask = mask;
-	mInventoryPanel->setFilterPermMask(mask);
+    mImmediateFilterPermMask = mask;
+    mInventoryPanel->setFilterPermMask(mask);
 }
 
 void LLFloaterTexturePicker::onPickerCallback(const std::vector<std::string>& filenames, LLHandle<LLFloater> handle)
@@ -1359,9 +1470,9 @@ void LLFloaterTexturePicker::onTextureSelect( const LLTextureEntry& te )
 		}
 		
 		commitIfImmediateSet();
-    }
-    else
-    {
-        LLToolPipette::getInstance()->setResult(FALSE, LLTrans::getString("InventoryNoTexture"));
-    }
+	}
+	else
+	{
+		LLToolPipette::getInstance()->setResult(FALSE, LLTrans::getString("InventoryNoTexture"));
+	}
 }
diff --git a/indra/newview/llfloatertexturepicker.h b/indra/newview/llfloatertexturepicker.h
index 0a13aec02cda1509bbd1a4aad1c89345fc281837..cb11ebb5500a4150d5f9913e6f1ccb251927f3cd 100644
--- a/indra/newview/llfloatertexturepicker.h
+++ b/indra/newview/llfloatertexturepicker.h
@@ -35,7 +35,7 @@
 class LLFilterEditor;
 class LLTabContainer;
 
-typedef std::function<void(LLTextureCtrl::ETexturePickOp op, LLUUID id)> floater_commit_callback;
+typedef std::function<void(LLTextureCtrl::ETexturePickOp op, LLPickerSource source, const LLUUID& asset_id, const LLUUID& inventory_id)> floater_commit_callback;
 typedef std::function<void()> floater_close_callback;
 typedef std::function<void(const LLUUID& asset_id)> set_image_asset_id_callback;
 typedef std::function<void(LLPointer<LLViewerTexture> texture)> set_on_update_image_stats_callback;
@@ -43,7 +43,8 @@ typedef std::function<void(LLPointer<LLViewerTexture> texture)> set_on_update_im
 class LLFloaterTexturePicker final : public LLFloater
 {
   public:
-    LLFloaterTexturePicker(LLView*            owner,
+    LLFloaterTexturePicker(
+                           LLView*            owner,
                            LLUUID             image_asset_id,
                            LLUUID             default_image_asset_id,
                            LLUUID             transparent_image_asset_id,
@@ -54,7 +55,8 @@ class LLFloaterTexturePicker final : public LLFloater
                            PermissionMask     immediate_filter_perm_mask,
                            PermissionMask     dnd_filter_perm_mask,
                            BOOL               can_apply_immediately,
-                           LLUIImagePtr       fallback_image_name);
+                           LLUIImagePtr       fallback_image_name
+						   );
 
 	virtual ~LLFloaterTexturePicker();
 
@@ -72,7 +74,7 @@ class LLFloaterTexturePicker final : public LLFloater
 
 	// New functions
 	void setImageID(const LLUUID& image_asset_id, bool set_selection = true);
-	void updateImageStats();
+	bool updateImageStats(); // true if within limits
 	const LLUUID&	getAssetID() { return mImageAssetID; }
 	const LLUUID&	findItemID(const LLUUID& asset_id, BOOL copyable_only, BOOL ignore_library = FALSE);
 	void			setCanApplyImmediately(BOOL b);
@@ -84,11 +86,13 @@ class LLFloaterTexturePicker final : public LLFloater
 	void			stopUsingPipette();
 
 	void commitIfImmediateSet();
+    void commitCallback(LLTextureCtrl::ETexturePickOp op);
 	void commitCancel();
 
 	void onFilterEdit(const std::string& search_string);
 
-	void setCanApply(bool can_preview, bool can_apply);
+	void setCanApply(bool can_preview, bool can_apply, bool inworld_image = true);
+    void setMinDimentionsLimits(S32 min_dim);
 	void setTextureSelectedCallback(const texture_selected_callback& cb) { mTextureSelectedCallback = cb; }
 	void setOnFloaterCloseCallback(const floater_close_callback& cb) { mOnFloaterCloseCallback = cb; }
 	void setOnFloaterCommitCallback(const floater_commit_callback& cb) { mOnFloaterCommitCallback = cb; }
@@ -124,15 +128,14 @@ class LLFloaterTexturePicker final : public LLFloater
 	void 			setBakeTextureEnabled(BOOL enabled);
 
     void setInventoryPickType(LLTextureCtrl::EPickInventoryType type);
-
-	void			setImmediateFilterPermMask(PermissionMask mask);
+    void setImmediateFilterPermMask(PermissionMask mask);
 
     static void		onPickerCallback(const std::vector<std::string>& filenames, LLHandle<LLFloater> handle);
 
 protected:
     void refreshLocalList();
     void refreshInventoryFilter();
-	void setImageIDFromItem(const LLInventoryItem* itemp, bool set_selection = true);
+    void setImageIDFromItem(const LLInventoryItem* itemp, bool set_selection = true);
 
 	LLPointer<LLViewerTexture> mTexturep;
     LLPointer<LLFetchedGLTFMaterial> mGLTFMaterial;
@@ -152,6 +155,7 @@ class LLFloaterTexturePicker final : public LLFloater
 
 	LLTextBox*			mTentativeLabel;
 	LLTextBox*			mResolutionLabel;
+    LLTextBox*          mResolutionWarning;
 
 	std::string			mPendingName;
 	BOOL				mActive;
@@ -168,11 +172,21 @@ class LLFloaterTexturePicker final : public LLFloater
 
 	LLComboBox*			mModeSelector;
 	LLScrollListCtrl*	mLocalScrollCtrl;
+    LLButton*           mDefaultBtn;
+    LLButton*           mNoneBtn;
+    LLButton*           mBlankBtn;
+	LLButton*			mTransparentBtn;
+    LLButton*           mPipetteBtn;
+    LLButton*           mSelectBtn;
+    LLButton*           mCancelBtn;
 
 private:
 	bool mCanApply;
 	bool mCanPreview;
 	bool mPreviewSettingChanged;
+    bool mLimitsSet;
+    S32 mMaxDim;
+    S32 mMinDim;
     LLTextureCtrl::EPickInventoryType mInventoryPickType;
 
 
diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h
index 7ea24c4b9126e3dd0175a432281226964d257a0a..3b8eb2d6b27d7c75337e5c418bcf4b0d52f58948 100644
--- a/indra/newview/llfolderviewmodelinventory.h
+++ b/indra/newview/llfolderviewmodelinventory.h
@@ -39,12 +39,14 @@ class LLFolderViewModelItemInventory
 public:
 	LLFolderViewModelItemInventory(class LLFolderViewModelInventory& root_view_model);
 	virtual const LLUUID& getUUID() const = 0;
+    virtual const LLUUID& getThumbnailUUID() const = 0;
 	virtual time_t getCreationDate() const = 0;	// UTC seconds
 	virtual void setCreationDate(time_t creation_date_utc) = 0;
 	virtual PermissionMask getPermissionMask() const = 0;
 	virtual LLFolderType::EType getPreferredType() const = 0;
 	virtual void showProperties(void) = 0;
 	virtual BOOL isItemInTrash( void) const { return FALSE; } // TODO: make   into pure virtual.
+    virtual bool isItemInOutfits() const { return false; }
 	virtual BOOL isAgentInventory() const { return FALSE; }
 	virtual BOOL isUpToDate() const = 0;
     virtual void addChild(LLFolderViewModelItem* child);
diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp
index 0ba283f5f401cf660425900dd5697b58dbb1167d..43837e448f6f64ec52369e7002bf7d247e93f893 100644
--- a/indra/newview/llfriendcard.cpp
+++ b/indra/newview/llfriendcard.cpp
@@ -478,14 +478,24 @@ void LLFriendCardsManager::ensureFriendsFolderExists()
 			LL_WARNS() << "Failed to find \"" << cat_name << "\" category descendents in Category Tree." << LL_ENDL;
 		}
 
-		friends_folder_ID = gInventory.createNewCategory(calling_cards_folder_ID,
-			LLFolderType::FT_CALLINGCARD, get_friend_folder_name());
-
-		gInventory.createNewCategory(friends_folder_ID,
-			LLFolderType::FT_CALLINGCARD, get_friend_all_subfolder_name());
-
-		// Now when we have all needed folders we can sync their contents with buddies list.
-		syncFriendsFolder();
+		gInventory.createNewCategory(
+            calling_cards_folder_ID,
+			LLFolderType::FT_CALLINGCARD,
+            get_friend_folder_name(),
+            [](const LLUUID &new_category_id)
+        {
+            gInventory.createNewCategory(
+                new_category_id,
+                LLFolderType::FT_CALLINGCARD,
+                get_friend_all_subfolder_name(),
+                [](const LLUUID &new_category_id)
+            {
+                // Now when we have all needed folders we can sync their contents with buddies list.
+                LLFriendCardsManager::getInstance()->syncFriendsFolder();
+            }
+            );
+        }
+        );
 	}
 }
 
@@ -510,11 +520,16 @@ void LLFriendCardsManager::ensureFriendsAllFolderExists()
 			LL_WARNS() << "Failed to find \"" << cat_name << "\" category descendents in Category Tree." << LL_ENDL;
 		}
 
-		friends_all_folder_ID = gInventory.createNewCategory(friends_folder_ID,
-			LLFolderType::FT_CALLINGCARD, get_friend_all_subfolder_name());
-
-		// Now when we have all needed folders we can sync their contents with buddies list.
-		syncFriendsFolder();
+        gInventory.createNewCategory(
+            friends_folder_ID,
+			LLFolderType::FT_CALLINGCARD,
+            get_friend_all_subfolder_name(),
+            [](const LLUUID &new_cat_id)
+        {
+            // Now when we have all needed folders we can sync their contents with buddies list.
+            LLFriendCardsManager::getInstance()->syncFriendsFolder();
+        }
+        );
 	}
 }
 
diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp
index 0bc19b40d76f73345513a805477c535389b450a2..fc9af7b38857039c960a70a170f97d77ef32c7c5 100644
--- a/indra/newview/llinspectobject.cpp
+++ b/indra/newview/llinspectobject.cpp
@@ -697,9 +697,7 @@ void LLInspectObject::onClickOpen()
 
 void LLInspectObject::onClickMoreInfo()
 {
-	LLSD key;
-	key["task"] = "task";
-	LLFloaterSidePanelContainer::showPanel("inventory", key);
+    LLFloaterReg::showInstance("task_properties");
 	closeFloater();
 }
 
diff --git a/indra/newview/llinspecttexture.cpp b/indra/newview/llinspecttexture.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..da4e3c0949f327b874c052dae15f56cb1b20723e
--- /dev/null
+++ b/indra/newview/llinspecttexture.cpp
@@ -0,0 +1,249 @@
+/**
+ * @file llinspecttexture.cpp
+ *
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llinspect.h"
+#include "llinspecttexture.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h"
+#include "lltexturectrl.h"
+#include "lltrans.h"
+#include "llviewertexturelist.h"
+
+
+// ============================================================================
+// Helper functions
+//
+
+LLToolTip* LLInspectTextureUtil::createInventoryToolTip(LLToolTip::Params p)
+{
+    const LLSD& sdTooltip = p.create_params;
+    
+    if (sdTooltip.has("thumbnail_id") && sdTooltip["thumbnail_id"].asUUID().notNull())
+    {
+        // go straight for thumbnail regardless of type
+        // TODO: make a tooltip factory?
+        return LLUICtrlFactory::create<LLTextureToolTip>(p);
+    }
+
+	LLInventoryType::EType eInvType = (sdTooltip.has("inv_type")) ? (LLInventoryType::EType)sdTooltip["inv_type"].asInteger() : LLInventoryType::IT_NONE;
+	switch (eInvType)
+	{
+		case LLInventoryType::IT_CATEGORY:
+			{
+				if (sdTooltip.has("item_id"))
+				{
+					const LLUUID idCategory = sdTooltip["item_id"].asUUID();
+                    LLViewerInventoryCategory* cat = gInventory.getCategory(idCategory);
+                    if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT)
+                    {
+                        LLInventoryModel::cat_array_t cats;
+                        LLInventoryModel::item_array_t items;
+                        // Not LLIsOfAssetType, because we allow links
+                        LLIsTextureType f;
+                        gInventory.getDirectDescendentsOf(idCategory, cats, items, f);
+
+                        // Exactly one texture found => show the texture tooltip
+                        if (1 == items.size())
+                        {
+                            LLViewerInventoryItem* item = items.front();
+                            if (item && item->getIsLinkType())
+                            {
+                                item = item->getLinkedItem();
+                            }
+                            if (item)
+                            {
+                                // Note: LLFloaterChangeItemThumbnail will attempt to write this
+                                // into folder's thumbnail id when opened
+                                p.create_params.getValue()["thumbnail_id"] = item->getAssetUUID();
+                                return LLUICtrlFactory::create<LLTextureToolTip>(p);
+                            }
+                        }
+                    }
+				}
+
+				// No or more than one texture found => show default tooltip
+				return LLUICtrlFactory::create<LLToolTip>(p);
+			}
+		default:
+			return LLUICtrlFactory::create<LLToolTip>(p);
+	}
+}
+
+// ============================================================================
+// LLTexturePreviewView helper class
+//
+
+class LLTexturePreviewView : public LLView
+{
+public:
+	LLTexturePreviewView(const LLView::Params& p);
+	~LLTexturePreviewView();
+
+public:
+	void draw() override;
+
+public:
+	void setImageFromAssetId(const LLUUID& idAsset);
+	void setImageFromItemId(const LLUUID& idItem);
+
+protected:
+	LLPointer<LLViewerFetchedTexture> m_Image;
+	S32         mImageBoostLevel = LLGLTexture::BOOST_NONE;
+	std::string mLoadingText;
+};
+
+
+LLTexturePreviewView::LLTexturePreviewView(const LLView::Params& p)
+	: LLView(p)
+{
+	mLoadingText = LLTrans::getString("texture_loading");
+}
+
+LLTexturePreviewView::~LLTexturePreviewView()
+{
+	if (m_Image)
+	{
+		m_Image->setBoostLevel(mImageBoostLevel);
+		m_Image = nullptr;
+	}
+}
+
+void LLTexturePreviewView::draw()
+{
+    LLView::draw();
+
+	if (m_Image)
+	{
+		LLRect rctClient = getLocalRect();
+
+        if (4 == m_Image->getComponents())
+        {
+            const LLColor4 color(.098f, .098f, .098f);
+            gl_rect_2d(rctClient, color, TRUE);
+        }
+		gl_draw_scaled_image(rctClient.mLeft, rctClient.mBottom, rctClient.getWidth(), rctClient.getHeight(), m_Image);
+
+		bool isLoading = (!m_Image->isFullyLoaded()) && (m_Image->getDiscardLevel() > 0);
+		if (isLoading)
+			LLFontGL::getFontSansSerif()->renderUTF8(mLoadingText, 0, llfloor(rctClient.mLeft + 3),  llfloor(rctClient.mTop - 25), LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
+		m_Image->addTextureStats((isLoading) ? MAX_IMAGE_AREA : (F32)(rctClient.getWidth() * rctClient.getHeight()));
+	}
+}
+
+void LLTexturePreviewView::setImageFromAssetId(const LLUUID& idAsset)
+{
+	m_Image = LLViewerTextureManager::getFetchedTexture(idAsset, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+	if (m_Image)
+	{
+		mImageBoostLevel = m_Image->getBoostLevel();
+		m_Image->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
+		m_Image->forceToSaveRawImage(0);
+		if ( (!m_Image->isFullyLoaded()) && (!m_Image->hasFetcher()) )
+		{
+			if (m_Image->isInFastCacheList())
+			{
+				m_Image->loadFromFastCache();
+			}
+			gTextureList.forceImmediateUpdate(m_Image);
+		}
+	}
+}
+
+void LLTexturePreviewView::setImageFromItemId(const LLUUID& idItem)
+{
+	const LLViewerInventoryItem* pItem = gInventory.getItem(idItem);
+	setImageFromAssetId( (pItem) ? pItem->getAssetUUID() : LLUUID::null );
+}
+
+// ============================================================================
+// LLTextureToolTip class
+//
+
+LLTextureToolTip::LLTextureToolTip(const LLToolTip::Params& p)
+	: LLToolTip(p)
+	, mPreviewView(nullptr)
+	, mPreviewSize(256)
+{
+	mMaxWidth = llmax(mMaxWidth, mPreviewSize);
+
+    // Currently has to share params with LLToolTip, override values
+    setBackgroundColor(LLColor4::black);
+    setTransparentColor(LLColor4::black);
+    setBorderVisible(true);
+}
+
+LLTextureToolTip::~LLTextureToolTip()
+{
+}
+
+void LLTextureToolTip::initFromParams(const LLToolTip::Params& p)
+{
+    LLToolTip::initFromParams(p);
+    
+    // Create and add the preview control
+    LLView::Params p_preview;
+    p_preview.name = "texture_preview";
+    LLRect rctPreview;
+    rctPreview.setOriginAndSize(mPadding, mTextBox->getRect().mTop, mPreviewSize, mPreviewSize);
+    p_preview.rect = rctPreview;
+    mPreviewView = LLUICtrlFactory::create<LLTexturePreviewView>(p_preview);
+    addChild(mPreviewView);
+    
+    // Parse the control params
+    const LLSD& sdTextureParams = p.create_params;
+    if (sdTextureParams.has("thumbnail_id"))
+    {
+        mPreviewView->setImageFromAssetId(sdTextureParams["thumbnail_id"].asUUID());
+    }
+    else if (sdTextureParams.has("item_id"))
+    {
+        mPreviewView->setImageFromItemId(sdTextureParams["item_id"].asUUID());
+    }
+
+    // Currently has to share params with LLToolTip, override values manually
+    // Todo: provide from own params instead, may be like object inspector does it
+    LLViewBorder::Params border_params;
+    border_params.border_thickness(LLPANEL_BORDER_WIDTH);
+    border_params.highlight_light_color(LLColor4::white);
+    border_params.highlight_dark_color(LLColor4::white);
+    border_params.shadow_light_color(LLColor4::white);
+    border_params.shadow_dark_color(LLColor4::white);
+    addBorder(border_params);
+    setBorderVisible(true);
+
+    setBackgroundColor(LLColor4::black);
+    setBackgroundVisible(true);
+    setBackgroundOpaque(true);
+    setBackgroundImage(nullptr);
+    setTransparentImage(nullptr);
+
+    mTextBox->setColor(LLColor4::white);
+
+	snapToChildren();
+}
+
+// ============================================================================
diff --git a/indra/newview/llinspecttexture.h b/indra/newview/llinspecttexture.h
new file mode 100644
index 0000000000000000000000000000000000000000..ff0d80b825160d932a82ebe3f90c96bdc7df9bd3
--- /dev/null
+++ b/indra/newview/llinspecttexture.h
@@ -0,0 +1,49 @@
+/**
+ * @file llinspecttexture.h
+ *
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#pragma once
+
+#include "lltooltip.h"
+
+class LLTexturePreviewView;
+
+namespace LLInspectTextureUtil
+{
+	LLToolTip* createInventoryToolTip(LLToolTip::Params p);
+}
+
+class LLTextureToolTip : public LLToolTip
+{
+public:
+	LLTextureToolTip(const LLToolTip::Params& p);
+	~LLTextureToolTip();
+
+public:
+	void initFromParams(const LLToolTip::Params& p) override;
+
+protected:
+	LLTexturePreviewView* mPreviewView;
+	S32                   mPreviewSize;
+};
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index cf43765ad710bb40ffd75521b8aaa0a285c76ae7..d108d9ce00ca036cfe9ff16e94013cc3ee4d1b56 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -43,7 +43,6 @@
 #include "llfloateropenobject.h"
 #include "llfloaterreg.h"
 #include "llfloatermarketplacelistings.h"
-#include "llfloateroutfitphotopreview.h"
 #include "llfloatersidepanelcontainer.h"
 #include "llsidepanelinventory.h"
 #include "llfloaterworldmap.h"
@@ -98,29 +97,13 @@
 
 void copy_slurl_to_clipboard_callback_inv(const std::string& slurl);
 
-typedef std::pair<LLUUID, LLUUID> two_uuids_t;
-typedef std::list<two_uuids_t> two_uuids_list_t;
-
 const F32 SOUND_GAIN = 1.0f;
 
-struct LLMoveInv
-{
-	LLUUID mObjectID;
-	LLUUID mCategoryID;
-	two_uuids_list_t mMoveList;
-	void (*mCallback)(S32, void*);
-	void* mUserData;
-};
-
 using namespace LLOldEvents;
 
 // Function declarations
-bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, std::shared_ptr<LLMoveInv>);
 bool confirm_attachment_rez(const LLSD& notification, const LLSD& response);
 void teleport_via_landmark(const LLUUID& asset_id);
-static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit);
-static bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit);
-static BOOL can_move_to_landmarks(LLInventoryItem* inv_item);
 static bool check_category(LLInventoryModel* model,
 						   const LLUUID& cat_id,
 						   LLInventoryPanel* active_panel,
@@ -146,6 +129,12 @@ bool isMarketplaceSendAction(const std::string& action)
 	return ("send_to_marketplace" == action);
 }
 
+bool isPanelActive(const std::string& panel_name)
+{
+    LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
+    return (active_panel && (active_panel->getName() == panel_name));
+}
+
 // Used by LLFolderBridge as callback for directory fetching recursion
 class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver
 {
@@ -181,6 +170,65 @@ class LLRightClickInventoryFetchObserver : public LLInventoryFetchItemsObserver
 	}
 };
 
+class LLPasteIntoFolderCallback: public LLInventoryCallback
+{
+public:
+    LLPasteIntoFolderCallback(LLHandle<LLInventoryPanel>& handle)
+        : mInventoryPanel(handle)
+    {
+    }
+    ~LLPasteIntoFolderCallback()
+    {
+        processItems();
+    }
+
+    void fire(const LLUUID& inv_item)
+    {
+        mChangedIds.push_back(inv_item);
+    }
+
+    void processItems()
+    {
+        LLInventoryPanel* panel = mInventoryPanel.get();
+        bool has_elements = false;
+        for (LLUUID& inv_item : mChangedIds)
+        {
+            LLInventoryItem* item = gInventory.getItem(inv_item);
+            if (item && panel)
+            {
+                LLUUID root_id = panel->getRootFolderID();
+
+                if (inv_item == root_id)
+                {
+                    return;
+                }
+
+                LLFolderViewItem* item = panel->getItemByID(inv_item);
+                if (item)
+                {
+                    if (!has_elements)
+                    {
+                        panel->clearSelection();
+                        panel->getRootFolder()->clearSelection();
+                        panel->getRootFolder()->requestArrange();
+                        panel->getRootFolder()->update();
+                        has_elements = true;
+                    }
+                    panel->getRootFolder()->changeSelection(item, TRUE);
+                }
+            }
+        }
+
+        if (has_elements)
+        {
+            panel->getRootFolder()->scrollToShowSelection();
+        }
+    }
+private:
+    LLHandle<LLInventoryPanel> mInventoryPanel;
+    std::vector<LLUUID> mChangedIds;
+};
+
 // +=================================================+
 // |        LLInvFVBridge                            |
 // +=================================================+
@@ -220,54 +268,17 @@ const std::string& LLInvFVBridge::getDisplayName() const
 
 std::string LLInvFVBridge::getSearchableDescription() const
 {
-	const LLInventoryModel* model = getInventoryModel();
-	if (model)
-	{
-		const LLInventoryItem *item = model->getItem(mUUID);
-		if(item)
-		{
-			std::string desc = item->getDescription();
-			LLStringUtil::toUpper(desc);
-			return desc;
-		}
-	}
-	return LLStringUtil::null;
+    return get_searchable_description(getInventoryModel(), mUUID);
 }
 
 std::string LLInvFVBridge::getSearchableCreatorName() const
 {
-	const LLInventoryModel* model = getInventoryModel();
-	if (model)
-	{
-		const LLInventoryItem *item = model->getItem(mUUID);
-		if(item)
-		{
-			LLAvatarName av_name;
-			if (LLAvatarNameCache::get(item->getCreatorUUID(), &av_name))
-			{
-				std::string username = av_name.getUserName();
-				LLStringUtil::toUpper(username);
-				return username;
-			}
-		}
-	}
-	return LLStringUtil::null;
+    return get_searchable_creator_name(getInventoryModel(), mUUID);
 }
 
 std::string LLInvFVBridge::getSearchableUUIDString() const
 {
-	const LLInventoryModel* model = getInventoryModel();
-	if (model)
-	{
-		const LLViewerInventoryItem *item = model->getItem(mUUID);
-		if(item && (item->getIsFullPerm() || gAgent.isGodlikeWithoutAdminMenuFakery()))
-		{
-			std::string uuid = item->getAssetUUID().asString();
-			LLStringUtil::toUpper(uuid);
-			return uuid;
-		}
-	}
-	return LLStringUtil::null;
+    return get_searchable_UUID(getInventoryModel(), mUUID);
 }
 
 // Folders have full perms
@@ -341,7 +352,7 @@ BOOL LLInvFVBridge::cutToClipboard()
 	if ( (obj) && (isItemMovable()) )
 // [/SL:KB]
 	{
-        const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+        const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
         const BOOL cut_from_marketplacelistings = gInventory.isObjectDescendentOf(mUUID, marketplacelistings_id);
             
         if (cut_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(mUUID) ||
@@ -427,6 +438,32 @@ void LLInvFVBridge::showProperties()
     }
 }
 
+void LLInvFVBridge::navigateToFolder(bool new_window, bool change_mode)
+{
+    if(new_window)
+    {
+        mInventoryPanel.get()->openSingleViewInventory(mUUID);
+    }
+    else
+    {
+        if(change_mode)
+        {
+            LLInventoryPanel::setSFViewAndOpenFolder(mInventoryPanel.get(), mUUID);
+        }
+        else
+        {
+            LLInventorySingleFolderPanel* panel = dynamic_cast<LLInventorySingleFolderPanel*>(mInventoryPanel.get());
+            if (!panel || !getInventoryModel() || mUUID.isNull())
+            {
+                return;
+            }
+
+            panel->changeFolderRoot(mUUID);
+        }
+
+    }
+}
+
 void LLInvFVBridge::removeBatch(std::vector<LLFolderViewModelItem*>& batch)
 {
 	// Deactivate gestures when moving them into Trash
@@ -857,6 +894,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
 										menuentry_vec_t &disabled_items, U32 flags)
 {
 	const LLInventoryObject *obj = getInventoryObject();
+    bool single_folder_root = (mRoot == NULL);
 
 	if (obj)
 	{
@@ -871,7 +909,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
 //			disabled_items.push_back(std::string("Copy"));
 //		}
 
-        if (isAgentInventory() && !isCOFFolder() && !isInboxFolder() && !isOutfitsFolder())
+        if (isAgentInventory() && !isCOFFolder() && !isInboxFolder() && !isOutfitsFolder() && !single_folder_root)
         {
             items.push_back(std::string("New folder from selected"));
             items.push_back(std::string("Subfolder Separator"));
@@ -909,7 +947,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
 				items.push_back(std::string("Find Links"));
 			}
 
-			if (!isInboxFolder())
+			if (!isInboxFolder() && !single_folder_root)
 			{
 				items.push_back(std::string("Rename"));
 				if (!isItemRenameable() || ((flags & FIRST_SELECTED_ITEM) == 0))
@@ -917,14 +955,20 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
 					disabled_items.push_back(std::string("Rename"));
 				}
 			}
-			
+
+            items.push_back(std::string("thumbnail"));
+            if (isLibraryItem())
+            {
+                disabled_items.push_back(std::string("thumbnail"));
+            }
+
+            LLViewerInventoryItem *inv_item = gInventory.getItem(mUUID);
 			if (show_asset_id)
 			{
 				items.push_back(std::string("Copy Asset UUID"));
 
 				bool is_asset_knowable = false;
 
-				LLViewerInventoryItem* inv_item = gInventory.getItem(mUUID);
 				if (inv_item)
 				{
 					is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(inv_item->getType());
@@ -937,6 +981,8 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
 				}
 			}
 
+            if(!single_folder_root)
+            {
 //			items.push_back(std::string("Cut"));
 //			if (!isItemMovable() || !isItemRemovable())
 //			{
@@ -958,6 +1004,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
                     }
                 }
 			}
+            }
             static LLCachedControl<bool> sPowerfulWizard(gSavedSettings, "AlchemyPowerfulWizard", false);
             if (show_asset_id && sPowerfulWizard)
             {
@@ -980,10 +1027,13 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
 			disabled_items.push_back(std::string("Copy"));
 		}
 
-		items.push_back(std::string("Cut"));
-		if ( (!isItemMovable()) || (isLibraryItem()) )
-		{
-			disabled_items.push_back(std::string("Cut"));
+        if(!single_folder_root)
+        {
+			items.push_back(std::string("Cut"));
+			if ( (!isItemMovable()) || (isLibraryItem()) )
+			{
+				disabled_items.push_back(std::string("Cut"));
+			}
 		}
 // [/SL:KB]
 	}
@@ -1013,16 +1063,12 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
 		items.push_back(std::string("Paste Separator"));
 	}
 
-	addDeleteContextMenuOptions(items, disabled_items);
-
-	// If multiple items are selected, only disable properties if we're not showing them in a multi-floater
-	if ( ((flags & FIRST_SELECTED_ITEM) == 0) && (!gSavedSettings.getBOOL("ShowPropertiesFloaters")) )
-	{
-		disabled_items.push_back(std::string("Properties"));
-	}
+    if(!single_folder_root)
+    {
+        addDeleteContextMenuOptions(items, disabled_items);
+    }
 
-	LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
-	if (active_panel && (active_panel->getName() != "All Items"))
+	if (!isPanelActive("All Items") && !isPanelActive("comb_single_folder_inv"))
 	{
 		items.push_back(std::string("Show in Main Panel"));
 	}
@@ -1134,7 +1180,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
 
 	items.push_back(std::string("Delete"));
 
-	if (!isItemRemovable())
+	if (!isItemRemovable() || isPanelActive("Favorite Items"))
 	{
 		disabled_items.push_back(std::string("Delete"));
 	}
@@ -1365,6 +1411,16 @@ BOOL LLInvFVBridge::isLinkedObjectInTrash() const
 	return FALSE;
 }
 
+bool LLInvFVBridge::isItemInOutfits() const
+{
+    const LLInventoryModel* model = getInventoryModel();
+    if(!model) return false;
+
+    const LLUUID my_outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+    return isCOFFolder() || (my_outfits_cat == mUUID) || model->isObjectDescendentOf(mUUID, my_outfits_cat);
+}
+
 BOOL LLInvFVBridge::isLinkedObjectMissing() const
 {
 	const LLInventoryObject *obj = getInventoryObject();
@@ -1395,7 +1451,7 @@ BOOL LLInvFVBridge::isCOFFolder() const
 // *TODO : Suppress isInboxFolder() once Merchant Outbox is fully deprecated
 BOOL LLInvFVBridge::isInboxFolder() const
 {
-	const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false);
+	const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
 	
 	if (inbox_id.isNull())
 	{
@@ -1407,7 +1463,7 @@ BOOL LLInvFVBridge::isInboxFolder() const
 
 BOOL LLInvFVBridge::isMarketplaceListingsFolder() const
 {
-	const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+	const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
 	
 	if (folder_id.isNull())
 	{
@@ -1419,7 +1475,7 @@ BOOL LLInvFVBridge::isMarketplaceListingsFolder() const
 
 BOOL LLInvFVBridge::isOutfitsFolder() const
 {
-	const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+	const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
 	
 	if (inbox_id.isNull())
 	{
@@ -1734,7 +1790,7 @@ bool LLInvFVBridge::canListOnMarketplaceNow() const
 		{
             std::string error_msg;
             LLInventoryModel* model = getInventoryModel();
-            const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+            const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
             if (marketplacelistings_id.notNull())
             {
                 LLViewerInventoryCategory * master_folder = model->getCategory(marketplacelistings_id);
@@ -1833,6 +1889,12 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
 		restoreItem();
 		return;
 	}
+    else if ("thumbnail" == action)
+    {
+        LLSD data(mUUID);
+        LLFloaterReg::showInstance("change_item_thumbnail", data);
+        return;
+    }
 	else if ("copy_uuid" == action)
 	{
 		// Single item only
@@ -1887,7 +1949,7 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
 	{
 		LLInventoryItem* itemp = model->getItem(mUUID);
 		if (!itemp) return;
-        const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+        const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
         // Note: For a single item, if it's not a copy, then it's a move
         move_item_to_marketplacelistings(itemp, marketplacelistings_id, ("copy_to_marketplace_listings" == action));
     }
@@ -2110,9 +2172,9 @@ std::string LLItemBridge::getLabelSuffix() const
 {
 	// String table is loaded before login screen and inventory items are
 	// loaded after login, so LLTrans should be ready.
-	static std::string NO_COPY = LLTrans::getString("no_copy");
-	static std::string NO_MOD = LLTrans::getString("no_modify");
-	static std::string NO_XFER = LLTrans::getString("no_transfer");
+	static std::string NO_COPY = LLTrans::getString("no_copy_lbl");
+	static std::string NO_MOD = LLTrans::getString("no_modify_lbl");
+	static std::string NO_XFER = LLTrans::getString("no_transfer_lbl");
 	static std::string LINK = LLTrans::getString("link");
 	static std::string BROKEN_LINK = LLTrans::getString("broken_link");
 	std::string suffix;
@@ -2133,17 +2195,20 @@ std::string LLItemBridge::getLabelSuffix() const
 			BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
 			if (!copy)
 			{
+                suffix += " ";
 				suffix += NO_COPY;
 			}
 			BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
 			if (!mod)
 			{
-				suffix += NO_MOD;
+                suffix += suffix.empty() ? " " : ",";
+                suffix += NO_MOD;
 			}
 			BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
 																gAgent.getID());
 			if (!xfer)
 			{
+                suffix += suffix.empty() ? " " : ",";
 				suffix += NO_XFER;
 			}
 		}
@@ -2366,6 +2431,21 @@ LLViewerInventoryItem* LLItemBridge::getItem() const
 	return item;
 }
 
+const LLUUID& LLItemBridge::getThumbnailUUID() const
+{
+    LLViewerInventoryItem* item = NULL;
+    LLInventoryModel* model = getInventoryModel();
+    if(model)
+    {
+        item = (LLViewerInventoryItem*)model->getItem(mUUID);
+    }
+    if (item)
+    {
+        return item->getThumbnailUUID();
+    }
+    return LLUUID::null;
+}
+
 BOOL LLItemBridge::isItemPermissive() const
 {
 	LLViewerInventoryItem* item = getItem();
@@ -2452,6 +2532,7 @@ void LLFolderBridge::buildDisplayName() const
 std::string LLFolderBridge::getLabelSuffix() const
 {
     static LLCachedControl<F32> folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime", 0.5f);
+    static LLCachedControl<bool> xui_debug(gSavedSettings, "DebugShowXUINames", 0);
     
     if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay())
     {
@@ -2459,7 +2540,25 @@ std::string LLFolderBridge::getLabelSuffix() const
 		return fmt::format(FMT_STRING(" ( {:s} ) "), LOADING_DATA_STR);
     }
     std::string suffix = "";
-    if(mShowDescendantsCount)
+    if (xui_debug)
+    {
+        LLInventoryModel::cat_array_t* cats;
+        LLInventoryModel::item_array_t* items;
+        gInventory.getDirectDescendentsOf(getUUID(), cats, items);
+        
+        LLViewerInventoryCategory* cat = gInventory.getCategory(getUUID());
+        if (cat)
+        {
+            LLStringUtil::format_map_t args;
+            args["[FOLDER_COUNT]"] = llformat("%d", cats->size());
+            args["[ITEMS_COUNT]"] = llformat("%d", items->size());
+            args["[VERSION]"] = llformat("%d", cat->getVersion());
+            args["[VIEWER_DESCENDANT_COUNT]"] = llformat("%d", cats->size() + items->size());
+            args["[SERVER_DESCENDANT_COUNT]"] = llformat("%d", cat->getDescendentCount());
+            suffix = " " + LLTrans::getString("InventoryFolderDebug", args);
+        }
+    }
+    else if(mShowDescendantsCount)
     {
         LLInventoryModel::cat_array_t cat_array;
         LLInventoryModel::item_array_t item_array;
@@ -2481,6 +2580,16 @@ LLFontGL::StyleFlags LLFolderBridge::getLabelStyle() const
     return LLFontGL::NORMAL;
 }
 
+const LLUUID& LLFolderBridge::getThumbnailUUID() const
+{
+    LLViewerInventoryCategory* cat = getCategory();
+    if (cat)
+    {
+        return cat->getThumbnailUUID();
+    }
+    return LLUUID::null;
+}
+
 void LLFolderBridge::update()
 {
 	// we know we have children but  haven't  fetched them (doesn't obey filter)
@@ -2699,7 +2808,8 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
 											BOOL drop,
 											std::string& tooltip_msg,
 											BOOL is_link,
-											BOOL user_confirm)
+											BOOL user_confirm,
+                                            LLPointer<LLInventoryCallback> cb)
 {
 
 	LLInventoryModel* model = getInventoryModel();
@@ -2716,8 +2826,8 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
 	if (!filter) return false;
 
 	const LLUUID &cat_id = inv_cat->getUUID();
-	const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
-	const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+	const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+	const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
     const LLUUID from_folder_uuid = inv_cat->getParentUUID();
 	
 	const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
@@ -2735,10 +2845,10 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
 
 	if (is_agent_inventory)
 	{
-		const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false);
-		const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false);
-		const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
-		const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND, false);
+		const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+		const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
+		const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+		const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
 
 		const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
 		const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
@@ -3012,7 +3122,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
 			{
 				// Category can contains objects,
 				// create a new folder and populate it with links to original objects
-				dropToMyOutfits(inv_cat);
+				dropToMyOutfits(inv_cat, cb);
 			}
 			// if target is current outfit folder we use link
 			else if (move_is_into_current_outfit &&
@@ -3022,14 +3132,16 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
 				// traverse category and add all contents to currently worn.
 				BOOL append = true;
 				LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append);
+                if (cb) cb->fire(inv_cat->getUUID());
 			}
 			else if (move_is_into_marketplacelistings)
 			{
 				move_folder_to_marketplacelistings(inv_cat, mUUID);
+                if (cb) cb->fire(inv_cat->getUUID());
 			}
 			else
 			{
-				if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX, false)))
+				if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX)))
 				{
 					set_dad_inbox_object(cat_id);
 				}
@@ -3041,6 +3153,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
 					(LLViewerInventoryCategory*)inv_cat,
 					mUUID,
 					move_is_into_trash);
+                if (cb) cb->fire(inv_cat->getUUID());
 			}
             if (move_is_from_marketplacelistings)
             {
@@ -3059,14 +3172,20 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
                     LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
                     if (version_folder_id.notNull())
                     {
-                        LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id);
-                        if (!validate_marketplacelistings(cat,NULL))
+                        LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+                            version_folder_id,
+                            [version_folder_id](bool result)
                         {
-                            LLMarketplaceData::instance().activateListing(version_folder_id,false);
+                            if (!result)
+                            {
+                                LLMarketplaceData::instance().activateListing(version_folder_id, false);
+                            }
                         }
+                        );
                     }
                     // In all cases, update the listing we moved from so suffix are updated
                     update_marketplace_category(from_folder_uuid);
+                    if (cb) cb->fire(inv_cat->getUUID());
                 }
             }
 		}
@@ -3080,7 +3199,22 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
 		}
 		else
 		{
-			accept = move_inv_category_world_to_agent(cat_id, mUUID, drop, NULL, NULL, filter);
+            // Todo: fix me. moving from task inventory doesn't have a completion callback,
+            // yet making a copy creates new item id so this doesn't work right
+            std::function<void(S32, void*, const LLMoveInv*)> callback = [cb](S32, void*, const LLMoveInv* move_inv) mutable
+            {
+                two_uuids_list_t::const_iterator move_it;
+                for (move_it = move_inv->mMoveList.begin();
+                     move_it != move_inv->mMoveList.end();
+                     ++move_it)
+                {
+                    if (cb)
+                    {
+                        cb->fire(move_it->second);
+                    }
+                }
+            };
+			accept = move_inv_category_world_to_agent(cat_id, mUUID, drop, callback, NULL, filter);
 		}
 	}
 	else if (LLToolDragAndDrop::SOURCE_LIBRARY == source)
@@ -3151,7 +3285,7 @@ void warn_move_inventory(LLViewerObject* object, std::shared_ptr<LLMoveInv> move
 BOOL move_inv_category_world_to_agent(const LLUUID& object_id,
 									  const LLUUID& category_id,
 									  BOOL drop,
-									  void (*callback)(S32, void*),
+									  std::function<void(S32, void*, const LLMoveInv*)> callback,
 									  void* user_data,
 									  LLInventoryFilter* filter)
 {
@@ -3454,6 +3588,12 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
 		
 		return;
 	}
+    else if ("thumbnail" == action)
+    {
+        LLSD data(mUUID);
+        LLFloaterReg::showInstance("change_item_thumbnail", data);
+        return;
+    }
 	else if ("paste" == action)
 	{
 		pasteFromClipboard();
@@ -3523,18 +3663,26 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
         if (depth_nesting_in_marketplace(mUUID) == 1)
         {
             LLUUID version_folder_id = LLMarketplaceData::instance().getVersionFolder(mUUID);
-            LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id);
             mMessage = "";
-            if (!validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3)))
-            {
-                LLSD subs;
-                subs["[ERROR_CODE]"] = mMessage;
-                LLNotificationsUtil::add("MerchantListingFailed", subs);
-            }
-            else
+
+            LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+                version_folder_id,
+                [this](bool result)
             {
-                LLMarketplaceData::instance().activateListing(mUUID,true);
-            }
+                // todo: might need to ensure bridge/mUUID exists or this will cause crashes
+                if (!result)
+                {
+                    LLSD subs;
+                    subs["[ERROR_CODE]"] = mMessage;
+                    LLNotificationsUtil::add("MerchantListingFailed", subs);
+                }
+                else
+                {
+                    LLMarketplaceData::instance().activateListing(mUUID, true);
+                }
+            },
+                boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3)
+            );
         }
 		return;
 	}
@@ -3542,18 +3690,27 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
 	{
         if (depth_nesting_in_marketplace(mUUID) == 2)
         {
-			LLInventoryCategory* category = gInventory.getCategory(mUUID);
             mMessage = "";
-            if (!validate_marketplacelistings(category,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),false,2))
-            {
-                LLSD subs;
-                subs["[ERROR_CODE]"] = mMessage;
-                LLNotificationsUtil::add("MerchantFolderActivationFailed", subs);
-            }
-            else
+
+            LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+                mUUID,
+                [this](bool result)
             {
-                LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID);
-            }
+                if (!result)
+                {
+                    LLSD subs;
+                    subs["[ERROR_CODE]"] = mMessage;
+                    LLNotificationsUtil::add("MerchantFolderActivationFailed", subs);
+                }
+                else
+                {
+                    LLInventoryCategory* category = gInventory.getCategory(mUUID);
+                    LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID);
+                }
+            },
+                boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
+                false,
+                2);
         }
 		return;
 	}
@@ -3576,29 +3733,44 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
 	}
 	else if ("marketplace_create_listing" == action)
 	{
-        LLViewerInventoryCategory* cat = gInventory.getCategory(mUUID);
         mMessage = "";
-        bool validates = validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),false);
-        if (!validates)
+
+        // first run vithout fix_hierarchy, second run with fix_hierarchy
+        LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+            mUUID,
+            [this](bool result)
         {
-            mMessage = "";
-            validates = validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),true);
-            if (validates)
+            if (!result)
             {
-                LLNotificationsUtil::add("MerchantForceValidateListing");
+                mMessage = "";
+
+                LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+                    mUUID,
+                    [this](bool result)
+                {
+                    if (result)
+                    {
+                        LLNotificationsUtil::add("MerchantForceValidateListing");
+                        LLMarketplaceData::instance().createListing(mUUID);
+                    }
+                    else
+                    {
+                        LLSD subs;
+                        subs["[ERROR_CODE]"] = mMessage;
+                        LLNotificationsUtil::add("MerchantListingFailed", subs);
+                    }
+                },
+                    boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
+                    true);
             }
-        }
+            else
+            {
+                LLMarketplaceData::instance().createListing(mUUID);
+            }
+        },
+            boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
+            false);
         
-        if (!validates)
-        {
-            LLSD subs;
-            subs["[ERROR_CODE]"] = mMessage;
-            LLNotificationsUtil::add("MerchantListingFailed", subs);
-        }
-        else
-        {
-            LLMarketplaceData::instance().createListing(mUUID);
-        }
 		return;
 	}
     else if ("marketplace_disassociate_listing" == action)
@@ -3642,7 +3814,7 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
 	{
 		LLInventoryCategory * cat = gInventory.getCategory(mUUID);
 		if (!cat) return;
-        const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+        const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
         move_folder_to_marketplacelistings(cat, marketplacelistings_id, ("move_to_marketplace_listings" != action), (("copy_or_move_to_marketplace_listings" == action)));
     }
 }
@@ -3901,7 +4073,7 @@ void LLFolderBridge::pasteFromClipboard()
 	LLInventoryModel* model = getInventoryModel();
 	if (model && isClipboardPasteable())
 	{
-        const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+        const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
         const BOOL paste_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
         
         BOOL cut_from_marketplacelistings = FALSE;
@@ -3962,11 +4134,11 @@ void LLFolderBridge::perform_pasteFromClipboard()
 	LLInventoryModel* model = getInventoryModel();
 	if (model && isClipboardPasteable())
 	{
-        const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
-        const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
-		const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false);
-		const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
-		const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND, false);
+        const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+        const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+		const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+		const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+		const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
 
 		const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
 		const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
@@ -3977,6 +4149,13 @@ void LLFolderBridge::perform_pasteFromClipboard()
 
 		std::vector<LLUUID> objects;
 		LLClipboard::instance().pasteFromClipboard(objects);
+
+        LLPointer<LLInventoryCallback> cb = NULL;
+        LLInventoryPanel* panel = mInventoryPanel.get();
+        if (panel->getRootFolder()->isSingleFolderMode() && panel->getRootFolderID() == mUUID)
+        {
+            cb = new LLPasteIntoFolderCallback(mInventoryPanel);
+        }
         
         LLViewerInventoryCategory * dest_folder = getCategory();
 		if (move_is_into_marketplacelistings)
@@ -4061,7 +4240,7 @@ void LLFolderBridge::perform_pasteFromClipboard()
 				{
 					if (!move_is_into_my_outfits && item && can_move_to_outfit(item, move_is_into_current_outfit))
 					{
-						dropToOutfit(item, move_is_into_current_outfit);
+						dropToOutfit(item, move_is_into_current_outfit, cb);
 					}
 					else if (move_is_into_my_outfits && LLAssetType::AT_CATEGORY == obj->getType())
 					{
@@ -4069,7 +4248,7 @@ void LLFolderBridge::perform_pasteFromClipboard()
 						U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit");
 						if (cat && can_move_to_my_outfits(model, cat, max_items_to_wear))
 						{
-							dropToMyOutfits(cat);
+							dropToMyOutfits(cat, cb);
 						}
 						else
 						{
@@ -4085,7 +4264,7 @@ void LLFolderBridge::perform_pasteFromClipboard()
 				{
 					if (item && can_move_to_outfit(item, move_is_into_current_outfit))
 					{
-						dropToOutfit(item, move_is_into_current_outfit);
+						dropToOutfit(item, move_is_into_current_outfit, cb);
 					}
 					else
 					{
@@ -4104,11 +4283,12 @@ void LLFolderBridge::perform_pasteFromClipboard()
                             {
                                 //changeItemParent() implicity calls dirtyFilter
                                 changeItemParent(model, viitem, parent_id, FALSE);
+                                if (cb) cb->fire(item_id);
                             }
                         }
                         else
                         {
-                            dropToFavorites(item);
+                            dropToFavorites(item, cb);
                         }
 					}
 				}
@@ -4136,6 +4316,7 @@ void LLFolderBridge::perform_pasteFromClipboard()
                                 //changeCategoryParent() implicity calls dirtyFilter
                                 changeCategoryParent(model, vicat, parent_id, FALSE);
                             }
+                            if (cb) cb->fire(item_id);
 						}
 					}
 					else
@@ -4157,6 +4338,7 @@ void LLFolderBridge::perform_pasteFromClipboard()
                                 //changeItemParent() implicity calls dirtyFilter
                                 changeItemParent(model, viitem, parent_id, FALSE);
                             }
+                            if (cb) cb->fire(item_id);
                         }
                     }
 				}
@@ -4177,6 +4359,7 @@ void LLFolderBridge::perform_pasteFromClipboard()
                             {
                                 copy_inventory_category(model, vicat, parent_id);
                             }
+                            if (cb) cb->fire(item_id);
 						}
 					}
                     else
@@ -4192,11 +4375,13 @@ void LLFolderBridge::perform_pasteFromClipboard()
                                     // Stop pasting into the marketplace as soon as we get an error
                                     break;
                                 }
+                                if (cb) cb->fire(item_id);
                             }
                             else if (item->getIsLinkType())
                             {
-                                link_inventory_object(parent_id, item_id,
-                                    LLPointer<LLInventoryCallback>(NULL));
+                                link_inventory_object(parent_id,
+                                                      item_id,
+                                                      cb);
                             }
                             else
                             {
@@ -4206,7 +4391,7 @@ void LLFolderBridge::perform_pasteFromClipboard()
                                                     item->getUUID(),
                                                     parent_id,
                                                     std::string(),
-                                                    LLPointer<LLInventoryCallback>(NULL));
+                                                    cb);
                             }
                         }
                     }
@@ -4223,9 +4408,9 @@ void LLFolderBridge::pasteLinkFromClipboard()
 	LLInventoryModel* model = getInventoryModel();
 	if(model)
 	{
-		const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
-        const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
-		const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+		const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+        const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+		const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
 
 		const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
 		const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
@@ -4242,6 +4427,14 @@ void LLFolderBridge::pasteLinkFromClipboard()
 
 		std::vector<LLUUID> objects;
 		LLClipboard::instance().pasteFromClipboard(objects);
+
+        LLPointer<LLInventoryCallback> cb = NULL;
+        LLInventoryPanel* panel = mInventoryPanel.get();
+        if (panel->getRootFolder()->isSingleFolderMode())
+        {
+            cb = new LLPasteIntoFolderCallback(mInventoryPanel);
+        }
+
 		for (std::vector<LLUUID>::const_iterator iter = objects.begin();
 			 iter != objects.end();
 			 ++iter)
@@ -4252,12 +4445,12 @@ void LLFolderBridge::pasteLinkFromClipboard()
 				LLInventoryItem *item = model->getItem(object_id);
 				if (item && can_move_to_outfit(item, move_is_into_current_outfit))
 				{
-					dropToOutfit(item, move_is_into_current_outfit);
+					dropToOutfit(item, move_is_into_current_outfit, cb);
 				}
 			}
 			else if (LLConstPointer<LLInventoryObject> obj = model->getObject(object_id))
 			{
-				link_inventory_object(parent_id, obj, LLPointer<LLInventoryCallback>(NULL));
+				link_inventory_object(parent_id, obj, cb);
 			}
 		}
 		// Change mode to paste for next paste
@@ -4295,8 +4488,8 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items
 	const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
 	const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
 	const LLUUID &favorites = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
-	const LLUUID &marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
-	const LLUUID &outfits_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+	const LLUUID &marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+	const LLUUID &outfits_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
 
 	if (outfits_id == mUUID)
 	{
@@ -4318,13 +4511,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items
 		}
 
 		disabled_items.push_back(std::string("New Folder"));
-		disabled_items.push_back(std::string("New Script"));
-		disabled_items.push_back(std::string("New Note"));
-		disabled_items.push_back(std::string("New Settings"));
-		disabled_items.push_back(std::string("New Gesture"));
-        disabled_items.push_back(std::string("New Material"));
-		disabled_items.push_back(std::string("New Clothes"));
-		disabled_items.push_back(std::string("New Body Parts"));
 		disabled_items.push_back(std::string("upload_def"));
 	}
 	if (favorites == mUUID)
@@ -4347,12 +4533,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items
     if (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK)
     {
         disabled_items.push_back(std::string("New Folder"));
-		disabled_items.push_back(std::string("New Script"));
-		disabled_items.push_back(std::string("New Note"));
-		disabled_items.push_back(std::string("New Gesture"));
-        disabled_items.push_back(std::string("New Material"));
-		disabled_items.push_back(std::string("New Clothes"));
-		disabled_items.push_back(std::string("New Body Parts"));
 		disabled_items.push_back(std::string("upload_def"));
     }
     if (marketplace_listings_id == mUUID)
@@ -4362,14 +4542,14 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items
         disabled_items.push_back(std::string("Cut"));
         disabled_items.push_back(std::string("Delete"));
     }
+
+	if (isPanelActive("Favorite Items"))
+	{
+		disabled_items.push_back(std::string("Delete"));
+	}
 	if(trash_id == mUUID)
 	{
-		bool is_recent_panel = false;
-		LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
-		if (active_panel && (active_panel->getName() == "Recent Items"))
-		{
-			is_recent_panel = true;
-		}
+		bool is_recent_panel = isPanelActive("Recent Items");
 
 		// This is the trash.
 		items.push_back(std::string("Empty Trash"));
@@ -4388,6 +4568,8 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items
 		{
 			disabled_items.push_back(std::string("Empty Trash"));
 		}
+
+        items.push_back(std::string("thumbnail"));
 	}
 	else if(isItemInTrash())
 	{
@@ -4414,22 +4596,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items
 				}
                 if (!isMarketplaceListingsFolder())
                 {
-                    items.push_back(std::string("New Script"));
-                    items.push_back(std::string("New Note"));
-                    items.push_back(std::string("New Gesture"));
-                    items.push_back(std::string("New Material"));
-                    items.push_back(std::string("New Clothes"));
-                    items.push_back(std::string("New Body Parts"));
-                    items.push_back(std::string("New Settings"));
                     items.push_back(std::string("upload_def"));
-                    
-                    menu_items_added = true;
-
-                    if (!LLEnvironment::instance().isInventoryEnabled())
-                    {
-                        disabled_items.push_back("New Settings");
-                    }
-
                 }
                 if (menu_items_added)
                 {
@@ -4444,6 +4611,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items
 			if (cat && (cat->getPreferredType() == LLFolderType::FT_OUTFIT))
 			{
 				items.push_back(std::string("Rename"));
+                items.push_back(std::string("thumbnail"));
 
 				addDeleteContextMenuOptions(items, disabled_items);
 				// EXT-4030: disallow deletion of currently worn outfit
@@ -4458,6 +4626,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items
 		if (model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) == mUUID)
 		{
 			items.push_back(std::string("Copy outfit list to clipboard"));
+            addOpenFolderMenuOptions(flags, items);
 		}
 
 		//Added by aura to force inventory pull on right-click to display folder options correctly. 07-17-06
@@ -4568,9 +4737,12 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags,   menuentry_vec_t&
 	if(!category) return;
 
 	const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
-	if (trash_id == mUUID) return;
-	if (isItemInTrash()) return;
-    
+	if ((trash_id == mUUID) || isItemInTrash())
+    {
+        addOpenFolderMenuOptions(flags, items);
+        return;
+    }
+
 	if (!isItemRemovable())
 	{
 		disabled_items.push_back(std::string("Delete"));
@@ -4586,7 +4758,7 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags,   menuentry_vec_t&
 // [/SL:KB]
 
 	// Only enable calling-card related options for non-system folders.
-	if (!is_system_folder && is_agent_inventory)
+	if (!is_system_folder && is_agent_inventory && (mRoot != NULL))
 	{
 		LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
 		if (mCallingCards || checkFolderForContentsOfType(model, is_callingcard))
@@ -4606,6 +4778,14 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags,   menuentry_vec_t&
         disabled_items.push_back(std::string("New folder from selected"));
     }
 
+    //skip the rest options in single-folder mode
+    if (mRoot == NULL)
+    {
+        return;
+    }
+
+    addOpenFolderMenuOptions(flags, items);
+
 #ifndef LL_RELEASE_FOR_DOWNLOAD
 	if (LLFolderType::lookupIsProtectedType(type) && is_agent_inventory)
 	{
@@ -4631,37 +4811,40 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags,   menuentry_vec_t&
 			if (type != LLFolderType::FT_OUTFIT)
 			{
 				items.push_back(std::string("Add To Outfit"));
+                if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID))
+                {
+                    disabled_items.push_back(std::string("Add To Outfit"));
+                }
 			}
 
 			items.push_back(std::string("Replace Outfit"));
-		}
-		if (is_agent_inventory)
-		{
-			items.push_back(std::string("Folder Wearables Separator"));
-			items.push_back(std::string("Remove From Outfit"));
-			if (!LLAppearanceMgr::getCanRemoveFromCOF(mUUID))
-			{
-					disabled_items.push_back(std::string("Remove From Outfit"));
-			}
-		}
-//		if (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID))
+//			if (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID))
 // [SL:KB] - Patch: Appearance-Misc | Checked: 2010-11-24 (Catznip-2.4)
-		if ( ((is_outfit) && (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID))) || 
-			 ((!is_outfit) && (gAgentWearables.isCOFChangeInProgress())) )
+			if ( ((is_outfit) && (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID))) || 
+				 ((!is_outfit) && (gAgentWearables.isCOFChangeInProgress())) )
 // [/SL:KB]
-		{
-			disabled_items.push_back(std::string("Replace Outfit"));
-		}
+            {
+                disabled_items.push_back(std::string("Replace Outfit"));
+            }
 // [RLVa:KB] - Checked: RLVa-2.0.3
-		// Block "Replace Current Outfit" if the user can't wear the new folder
-		if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(mUUID, RLV_LOCK_ADD)) )
-		{
-			disabled_items.push_back(std::string("Replace Outfit"));
-		}
+			// Block "Replace Current Outfit" if the user can't wear the new folder
+			if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(mUUID, RLV_LOCK_ADD)) )
+			{
+				disabled_items.push_back(std::string("Replace Outfit"));
+			}
 // [/RLVa:KB]
-		if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID))
+		}
+		if (is_agent_inventory)
 		{
-			disabled_items.push_back(std::string("Add To Outfit"));
+			items.push_back(std::string("Folder Wearables Separator"));
+            // Note: If user tries to unwear "My Inventory", it's going to deactivate everything including gestures
+            // Might be safer to disable this for "My Inventory"
+			items.push_back(std::string("Remove From Outfit"));
+            if (type != LLFolderType::FT_ROOT_INVENTORY // Unless COF is empty, whih shouldn't be, warrantied to have worn items
+                && !LLAppearanceMgr::getCanRemoveFromCOF(mUUID)) // expensive from root!
+            {
+                disabled_items.push_back(std::string("Remove From Outfit"));
+            }
 		}
 		items.push_back(std::string("Outfit Separator"));
 
@@ -4694,6 +4877,20 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 	menu.arrangeAndClear();
 }
 
+void LLFolderBridge::addOpenFolderMenuOptions(U32 flags, menuentry_vec_t& items)
+{
+    if ((flags & ITEM_IN_MULTI_SELECTION) == 0)
+    {
+        items.push_back(std::string("open_in_new_window"));
+        items.push_back(std::string("Open Folder Separator"));
+        items.push_back(std::string("Copy Separator"));
+        if(isPanelActive("comb_single_folder_inv"))
+        {
+            items.push_back(std::string("open_in_current_window"));
+        }
+    }
+}
+
 bool LLFolderBridge::hasChildren() const
 {
 	LLInventoryModel* model = getInventoryModel();
@@ -4710,6 +4907,18 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
 {
 	LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
 
+    static LLPointer<LLInventoryCallback> drop_cb = NULL;
+    LLInventoryPanel* panel = mInventoryPanel.get();
+    LLToolDragAndDrop* drop_tool = LLToolDragAndDrop::getInstance();
+    if (drop
+        && panel->getRootFolder()->isSingleFolderMode()
+        && panel->getRootFolderID() == mUUID
+        && drop_tool->getCargoIndex() == 0)
+    {
+        drop_cb = new LLPasteIntoFolderCallback(mInventoryPanel);
+    }
+
+
 	//LL_INFOS() << "LLFolderBridge::dragOrDrop()" << LL_ENDL;
 	BOOL accept = FALSE;
 	switch(cargo_type)
@@ -4728,7 +4937,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
 		case DAD_MESH:
         case DAD_SETTINGS:
         case DAD_MATERIAL:
-			accept = dragItemIntoFolder(inv_item, drop, tooltip_msg);
+			accept = dragItemIntoFolder(inv_item, drop, tooltip_msg, TRUE, drop_cb);
 			break;
 		case DAD_LINK:
 			// DAD_LINK type might mean one of two asset types: AT_LINK or AT_LINK_FOLDER.
@@ -4739,12 +4948,12 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
 				LLInventoryCategory* linked_category = gInventory.getCategory(inv_item->getLinkedUUID());
 				if (linked_category)
 				{
-					accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg, TRUE);
+					accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg, TRUE, TRUE, drop_cb);
 				}
 			}
 			else
 			{
-				accept = dragItemIntoFolder(inv_item, drop, tooltip_msg);
+				accept = dragItemIntoFolder(inv_item, drop, tooltip_msg, TRUE, drop_cb);
 			}
 			break;
 		case DAD_CATEGORY:
@@ -4754,7 +4963,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
 			}
 			else
 			{
-				accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, drop, tooltip_msg);
+				accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, drop, tooltip_msg, FALSE, TRUE, drop_cb);
 			}
 			break;
 		case DAD_ROOT_CATEGORY:
@@ -4764,6 +4973,11 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
 			LL_WARNS() << "Unhandled cargo type for drag&drop " << cargo_type << LL_ENDL;
 			break;
 	}
+
+    if (!drop || drop_tool->getCargoIndex() + 1 == drop_tool->getCargoCount())
+    {
+        drop_cb = NULL;
+    }
 	return accept;
 }
 
@@ -5064,138 +5278,56 @@ bool move_task_inventory_callback(const LLSD& notification, const LLSD& response
 
 	if (move_inv->mCallback)
 	{
-		move_inv->mCallback(option, move_inv->mUserData);
+		move_inv->mCallback(option, move_inv->mUserData, move_inv.get());
 	}
 
 	move_inv.reset(); //since notification will persist
 	return false;
 }
 
-// Returns true if the item can be moved to Current Outfit or any outfit folder.
-static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit)
+void drop_to_favorites_cb(const LLUUID& id, LLPointer<LLInventoryCallback> cb1, LLPointer<LLInventoryCallback> cb2)
 {
-	LLInventoryType::EType inv_type = inv_item->getInventoryType();
-	if ((inv_type != LLInventoryType::IT_WEARABLE) &&
-		(inv_type != LLInventoryType::IT_GESTURE) &&
-		(inv_type != LLInventoryType::IT_ATTACHMENT) &&
-		(inv_type != LLInventoryType::IT_OBJECT) &&
-		(inv_type != LLInventoryType::IT_SNAPSHOT) &&
-		(inv_type != LLInventoryType::IT_TEXTURE))
-	{
-		return FALSE;
-	}
-
-	U32 flags = inv_item->getFlags();
-	if(flags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS)
-	{
-		return FALSE;
-	}
-
-	if((inv_type == LLInventoryType::IT_TEXTURE) || (inv_type == LLInventoryType::IT_SNAPSHOT))
-	{
-		return !move_is_into_current_outfit;
-	}
-
-	if (move_is_into_current_outfit && get_is_item_worn(inv_item->getUUID()))
-	{
-		return FALSE;
-	}
-
-	return TRUE;
+    cb1->fire(id);
+    cb2->fire(id);
 }
 
-// Returns true if folder's content can be moved to Current Outfit or any outfit folder.
-static bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit)
-{
-    LLInventoryModel::cat_array_t *cats;
-    LLInventoryModel::item_array_t *items;
-    model->getDirectDescendentsOf(inv_cat->getUUID(), cats, items);
-
-    if (items->size() > wear_limit)
-    {
-        return false;
-    }
-
-    if (items->size() == 0)
-    {
-        // Nothing to move(create)
-        return false;
-    }
-
-    if (cats->size() > 0)
-    {
-        // We do not allow subfolders in outfits of "My Outfits" yet
-        return false;
-    }
-
-    LLInventoryModel::item_array_t::iterator iter = items->begin();
-    LLInventoryModel::item_array_t::iterator end = items->end();
-
-    while (iter != end)
-    {
-        LLViewerInventoryItem *item = *iter;
-        if (!can_move_to_outfit(item, false))
-        {
-            return false;
-        }
-        iter++;
-    }
-
-    return true;
-}
-
-// Returns TRUE if item is a landmark or a link to a landmark
-// and can be moved to Favorites or Landmarks folder.
-static BOOL can_move_to_landmarks(LLInventoryItem* inv_item)
-{
-	// Need to get the linked item to know its type because LLInventoryItem::getType()
-	// returns actual type AT_LINK for links, not the asset type of a linked item.
-	if (LLAssetType::AT_LINK == inv_item->getType())
-	{
-		LLInventoryItem* linked_item = gInventory.getItem(inv_item->getLinkedUUID());
-		if (linked_item)
-		{
-			return LLAssetType::AT_LANDMARK == linked_item->getType();
-		}
-	}
-
-	return LLAssetType::AT_LANDMARK == inv_item->getType();
-}
-
-void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item)
+void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item, LLPointer<LLInventoryCallback> cb)
 {
 	// use callback to rearrange favorite landmarks after adding
 	// to have new one placed before target (on which it was dropped). See EXT-4312.
-	LLPointer<AddFavoriteLandmarkCallback> cb = new AddFavoriteLandmarkCallback();
+	LLPointer<AddFavoriteLandmarkCallback> cb_fav = new AddFavoriteLandmarkCallback();
 	LLInventoryPanel* panel = mInventoryPanel.get();
 	LLFolderViewItem* drag_over_item = panel ? panel->getRootFolder()->getDraggingOverItem() : NULL;
 	LLFolderViewModelItemInventory* view_model = drag_over_item ? static_cast<LLFolderViewModelItemInventory*>(drag_over_item->getViewModelItem()) : NULL;
 	if (view_model)
 	{
-		cb.get()->setTargetLandmarkId(view_model->getUUID());
+		cb_fav.get()->setTargetLandmarkId(view_model->getUUID());
 	}
 
+    LLPointer <LLInventoryCallback> callback = cb_fav;
+    if (cb)
+    {
+        callback = new LLBoostFuncInventoryCallback(boost::bind(drop_to_favorites_cb, _1, cb, cb_fav));
+    }
+
 	copy_inventory_item(
 		gAgent.getID(),
 		inv_item->getPermissions().getOwner(),
 		inv_item->getUUID(),
 		mUUID,
 		std::string(),
-		cb);
+        callback);
 }
 
-void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit)
+void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit, LLPointer<LLInventoryCallback> cb)
 {
 	if((inv_item->getInventoryType() == LLInventoryType::IT_TEXTURE) || (inv_item->getInventoryType() == LLInventoryType::IT_SNAPSHOT))
 	{
-		const LLUUID &my_outifts_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+		const LLUUID &my_outifts_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
 		if(mUUID != my_outifts_id)
 		{
-			LLFloaterOutfitPhotoPreview* photo_preview  = LLFloaterReg::showTypedInstance<LLFloaterOutfitPhotoPreview>("outfit_photo_preview", inv_item->getUUID());
-			if(photo_preview)
-			{
-				photo_preview->setOutfitID(mUUID);
-			}
+            // Legacy: prior to thumbnails images in outfits were used for outfit gallery.
+            LLNotificationsUtil::add("ThumbnailOutfitPhoto");
 		}
 		return;
 	}
@@ -5212,21 +5344,22 @@ void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_c
 	}
 }
 
-void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat)
+void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer<LLInventoryCallback> cb)
 {
     // make a folder in the My Outfits directory.
     const LLUUID dest_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
 
     // Note: creation will take time, so passing folder id to callback is slightly unreliable,
     // but so is collecting and passing descendants' ids
-    inventory_func_type func = boost::bind(&LLFolderBridge::outfitFolderCreatedCallback, this, inv_cat->getUUID(), _1);
+    inventory_func_type func = boost::bind(&LLFolderBridge::outfitFolderCreatedCallback, this, inv_cat->getUUID(), _1, cb);
     gInventory.createNewCategory(dest_id,
                                  LLFolderType::FT_OUTFIT,
                                  inv_cat->getName(),
-                                 func);
+                                 func,
+                                 inv_cat->getThumbnailUUID());
 }
 
-void LLFolderBridge::outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id)
+void LLFolderBridge::outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id, LLPointer<LLInventoryCallback> cb)
 {
     LLInventoryModel::cat_array_t* categories;
     LLInventoryModel::item_array_t* items;
@@ -5257,7 +5390,6 @@ void LLFolderBridge::outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID ca
 
     if (!link_array.empty())
     {
-        LLPointer<LLInventoryCallback> cb = NULL;
         link_inventory_array(cat_dest_id, link_array, cb);
     }
 }
@@ -5290,7 +5422,8 @@ void LLFolderBridge::callback_dropCategoryIntoFolder(const LLSD& notification, c
 BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 										BOOL drop,
 										std::string& tooltip_msg,
-                                        BOOL user_confirm)
+                                        BOOL user_confirm,
+                                        LLPointer<LLInventoryCallback> cb)
 {
 	LLInventoryModel* model = getInventoryModel();
 
@@ -5304,11 +5437,11 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 	LLInventoryFilter* filter = getInventoryFilter();
 	if (!filter) return false;
 
-	const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
-	const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false);
-	const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false);
-	const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
-	const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+	const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+	const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+	const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
+	const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+	const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
     const LLUUID from_folder_uuid = inv_item->getParentUUID();
 
 	const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
@@ -5328,7 +5461,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 	LLViewerObject* object = NULL;
 	if(LLToolDragAndDrop::SOURCE_AGENT == source)
 	{
-		const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false);
+		const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
 
 		const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
 		const BOOL move_is_outof_current_outfit = LLAppearanceMgr::instance().getIsInCOF(inv_item->getUUID());
@@ -5488,26 +5621,27 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 			// (copy the item)
 			else if (move_is_into_favorites)
 			{
-				dropToFavorites(inv_item);
+				dropToFavorites(inv_item, cb);
 			}
 			// CURRENT OUTFIT or OUTFIT folder
 			// (link the item)
 			else if (move_is_into_current_outfit || move_is_into_outfit)
 			{
-				dropToOutfit(inv_item, move_is_into_current_outfit);
+				dropToOutfit(inv_item, move_is_into_current_outfit, cb);
 			}
             // MARKETPLACE LISTINGS folder
             // Move the item
             else if (move_is_into_marketplacelistings)
             {
                 move_item_to_marketplacelistings(inv_item, mUUID);
+                if (cb) cb->fire(inv_item->getUUID());
             }
 			// NORMAL or TRASH folder
 			// (move the item, restamp if into trash)
 			else
 			{
 				// set up observer to select item once drag and drop from inbox is complete 
-				if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false)))
+				if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX)))
 				{
 					set_dad_inbox_object(inv_item->getUUID());
 				}
@@ -5517,6 +5651,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 					(LLViewerInventoryItem*)inv_item,
 					mUUID,
 					move_is_into_trash);
+                if (cb) cb->fire(inv_item->getUUID());
 			}
             
             if (move_is_from_marketplacelistings)
@@ -5525,11 +5660,15 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
                 LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
                 if (version_folder_id.notNull())
                 {
-                    LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id);
-                    if (!validate_marketplacelistings(cat,NULL))
+                    LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+                        version_folder_id,
+                        [version_folder_id](bool result)
                     {
-                        LLMarketplaceData::instance().activateListing(version_folder_id,false);
-                    }
+                        if (!result)
+                        {
+                            LLMarketplaceData::instance().activateListing(version_folder_id, false);
+                        }
+                    });
                 }
             }
 
@@ -5597,11 +5736,16 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 
 		if (accept && drop)
 		{
+            LLUUID item_id = inv_item->getUUID();
             auto move_inv = std::make_shared<LLMoveInv>();
 			move_inv->mObjectID = inv_item->getParentUUID();
-			two_uuids_t item_pair(mUUID, inv_item->getUUID());
+			two_uuids_t item_pair(mUUID, item_id);
 			move_inv->mMoveList.push_back(item_pair);
-			move_inv->mCallback = NULL;
+            if (cb)
+            {
+                move_inv->mCallback = [item_id, cb](S32, void*, const LLMoveInv* move_inv) mutable
+                    { cb->fire(item_id); };
+            }
 			move_inv->mUserData = NULL;
 			if(is_move)
 			{
@@ -5693,13 +5837,13 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 				// (copy the item)
 				if (move_is_into_favorites)
 				{
-					dropToFavorites(inv_item);
+					dropToFavorites(inv_item, cb);
 				}
 				// CURRENT OUTFIT or OUTFIT folder
 				// (link the item)
 				else if (move_is_into_current_outfit || move_is_into_outfit)
 				{
-					dropToOutfit(inv_item, move_is_into_current_outfit);
+					dropToOutfit(inv_item, move_is_into_current_outfit, cb);
 				}
 				else
 				{
@@ -5709,7 +5853,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 						inv_item->getUUID(),
 						mUUID,
 						std::string(),
-						LLPointer<LLInventoryCallback>(NULL));
+						cb);
 				}
 			}
 		}
@@ -6303,7 +6447,7 @@ std::string LLCallingCardBridge::getLabelSuffix() const
 	LLViewerInventoryItem* item = getItem();
 	if( item && LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()) )
 	{
-		return LLItemBridge::getLabelSuffix() + " (online)";
+		return LLItemBridge::getLabelSuffix() + "  online";
 	}
 	else
 	{
@@ -8111,16 +8255,26 @@ class LLObjectBridgeAction: public LLInvFVBridgeAction
 public:
 	virtual void doIt()
 	{
-		/*
-		  LLFloaterReg::showInstance("properties", mUUID);
-		*/
-		LLInvFVBridgeAction::doIt();
+        attachOrDetach();
 	}
 	virtual ~LLObjectBridgeAction(){}
 protected:
 	LLObjectBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
+    void attachOrDetach();
 };
 
+void LLObjectBridgeAction::attachOrDetach()
+{
+    if (get_is_item_worn(mUUID))
+    {
+        LLAppearanceMgr::instance().removeItemFromAvatar(mUUID);
+    }
+    else
+    {
+        LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, false); // Don't replace if adding.
+    }
+}
+
 class LLLSLTextBridgeAction: public LLInvFVBridgeAction
 {
 	friend class LLInvFVBridgeAction;
@@ -8179,7 +8333,17 @@ void LLWearableBridgeAction::wearOnAvatar()
 	LLViewerInventoryItem* item = getItem();
 	if(item)
 	{
-		LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true);
+        if (get_is_item_worn(mUUID))
+        {
+            if(item->getType() != LLAssetType::AT_BODYPART)
+            {
+                LLAppearanceMgr::instance().removeItemFromAvatar(item->getUUID());
+            }
+        }
+        else
+        {
+            LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true);
+        }
 	}
 }
 
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 44f4373420ec8f7bd6de6f58050236fe0ad3bbd5..302a68ce899474fb8e443e08c68296fb6e6fe845 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -28,7 +28,6 @@
 #define LL_LLINVENTORYBRIDGE_H
 
 #include "llcallingcard.h"
-#include "llfloaterproperties.h"
 #include "llfolderviewmodel.h"
 #include "llinventorymodel.h"
 #include "llinventoryobserver.h"
@@ -47,9 +46,11 @@ class LLMenuGL;
 class LLCallingCardObserver;
 class LLViewerJointAttachment;
 class LLFolderView;
+struct LLMoveInv;
 
 typedef std::vector<std::string> menuentry_vec_t;
-
+typedef std::pair<LLUUID, LLUUID> two_uuids_t;
+typedef std::list<two_uuids_t> two_uuids_list_t;
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLInvFVBridge
 //
@@ -84,6 +85,7 @@ class LLInvFVBridge : public LLFolderViewModelItemInventory
 	// LLInvFVBridge functionality
 	//--------------------------------------------------------------------
 	virtual const LLUUID& getUUID() const { return mUUID; }
+    virtual const LLUUID& getThumbnailUUID() const { return LLUUID::null; }
 	virtual void clearDisplayName() { mDisplayName.clear(); }
 	virtual void restoreItem() {}
 	virtual void restoreToWorld() {}
@@ -107,6 +109,7 @@ class LLInvFVBridge : public LLFolderViewModelItemInventory
 	virtual std::string getLabelSuffix() const { return LLStringUtil::null; }
 	virtual void openItem() {}
 	virtual void closeItem() {}
+    virtual void navigateToFolder(bool new_window = false, bool change_mode = false);
 	virtual void showProperties();
 	virtual BOOL isItemRenameable() const { return TRUE; }
 	virtual BOOL isMultiPreviewAllowed() { return TRUE; }
@@ -114,6 +117,7 @@ class LLInvFVBridge : public LLFolderViewModelItemInventory
 	virtual BOOL isItemRemovable() const;
 	virtual BOOL isItemMovable() const;
 	virtual BOOL isItemInTrash() const;
+    virtual bool isItemInOutfits() const;
 	virtual BOOL isLink() const;
 	virtual BOOL isLibraryItem() const;
 	//virtual BOOL removeItem() = 0;
@@ -261,6 +265,7 @@ class LLItemBridge : public LLInvFVBridge
 	virtual LLUIImagePtr getIconOverlay() const;
 
 	LLViewerInventoryItem* getItem() const;
+    virtual const LLUUID& getThumbnailUUID() const;
 
 protected:
 	BOOL confirmRemoveItem(const LLSD& notification, const LLSD& response);
@@ -285,8 +290,8 @@ class LLFolderBridge : public LLInvFVBridge
 		mShowDescendantsCount(false)
 	{}
 		
-	BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE);
-	BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL is_link = FALSE, BOOL user_confirm = TRUE);
+	BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE, LLPointer<LLInventoryCallback> cb = NULL);
+	BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL is_link = FALSE, BOOL user_confirm = TRUE, LLPointer<LLInventoryCallback> cb = NULL);
     void callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item);
     void callback_dropCategoryIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryCategory* inv_category);
 
@@ -306,6 +311,7 @@ class LLFolderBridge : public LLInvFVBridge
 	static LLUIImagePtr getIcon(LLFolderType::EType preferred_type);
 	virtual std::string getLabelSuffix() const;
 	virtual LLFontGL::StyleFlags getLabelStyle() const;
+    virtual const LLUUID& getThumbnailUUID() const;
 
 	void setShowDescendantsCount(bool show_count) {mShowDescendantsCount = show_count;}
 
@@ -348,6 +354,7 @@ class LLFolderBridge : public LLInvFVBridge
 protected:
 	void buildContextMenuOptions(U32 flags, menuentry_vec_t& items,   menuentry_vec_t& disabled_items);
 	void buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& items,   menuentry_vec_t& disabled_items);
+    void addOpenFolderMenuOptions(U32 flags, menuentry_vec_t& items);
 
 	//--------------------------------------------------------------------
 	// Menu callbacks
@@ -373,9 +380,9 @@ class LLFolderBridge : public LLInvFVBridge
 	void copyOutfitToClipboard();
 	void determineFolderType();
 
-	void dropToFavorites(LLInventoryItem* inv_item);
-	void dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit);
-	void dropToMyOutfits(LLInventoryCategory* inv_cat);
+	void dropToFavorites(LLInventoryItem* inv_item, LLPointer<LLInventoryCallback> cb = NULL);
+	void dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit, LLPointer<LLInventoryCallback> cb = NULL);
+	void dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer<LLInventoryCallback> cb = NULL);
 
 	//--------------------------------------------------------------------
 	// Messy hacks for handling folder options
@@ -385,7 +392,7 @@ class LLFolderBridge : public LLInvFVBridge
 	static void staticFolderOptionsMenu();
 
 protected:
-    void outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id);
+    void outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id, LLPointer<LLInventoryCallback> cb);
     void callback_pasteFromClipboard(const LLSD& notification, const LLSD& response);
     void perform_pasteFromClipboard();
     void gatherMessage(std::string& message, S32 depth, LLError::ELevel log_level);
@@ -790,7 +797,7 @@ void rez_attachment(LLViewerInventoryItem* item,
 BOOL move_inv_category_world_to_agent(const LLUUID& object_id, 
 									  const LLUUID& category_id,
 									  BOOL drop,
-									  void (*callback)(S32, void*) = NULL,
+									  std::function<void(S32, void*, const LLMoveInv *)> callback = NULL,
 									  void* user_data = NULL,
 									  LLInventoryFilter* filter = NULL);
 
@@ -816,4 +823,16 @@ class LLFolderViewGroupedItemBridge: public LLFolderViewGroupedItemModel
     bool canWearSelected(const uuid_vec_t& item_ids) const;
 };
 
+struct LLMoveInv
+{
+    LLUUID mObjectID;
+    LLUUID mCategoryID;
+    two_uuids_list_t mMoveList;
+    std::function<void(S32, void*, const LLMoveInv*)> mCallback;
+    void* mUserData;
+};
+
+void warn_move_inventory(LLViewerObject* object, std::shared_ptr<LLMoveInv> move_inv);
+bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, std::shared_ptr<LLMoveInv>);
+
 #endif // LL_LLINVENTORYBRIDGE_H
diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index c38185cd5487a09afd6de0ef8a241efea43b18f4..423896f3116219b2ccec3d9eca6da05c62a081e0 100644
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -64,6 +64,7 @@ LLInventoryFilter::FilterOps::FilterOps(const Params& p)
 	mFilterTypes(p.types),
 	mFilterUUID(p.uuid),
 	mFilterLinks(p.links),
+    mFilterThumbnails(p.thumbnails),
 	mSearchVisibility(p.search_visibility)
 {
 }
@@ -82,7 +83,8 @@ LLInventoryFilter::LLInventoryFilter(const Params& p)
 	mCurrentGeneration(0),
 	mFirstRequiredGeneration(0),
 	mFirstSuccessGeneration(0),
-	mSearchType(SEARCHTYPE_NAME)
+	mSearchType(SEARCHTYPE_NAME),
+    mSingleFolderMode(false)
 {
 	// copy mFilterOps into mDefaultFilterOps
 	markDefault();
@@ -161,6 +163,8 @@ bool LLInventoryFilter::check(const LLFolderViewModelItem* item)
 	passed = passed && checkAgainstCreator(listener);
 	passed = passed && checkAgainstSearchVisibility(listener);
 
+    passed = passed && checkAgainstFilterThumbnails(listener->getUUID());
+
 	return passed;
 }
 
@@ -198,17 +202,23 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
 	// when applying a filter, matching folders get their contents downloaded first
 	// but make sure we are not interfering with pre-download
 	if (isNotDefault()
-		&& LLStartUp::getStartupState() > STATE_WEARABLES_WAIT)
+		&& LLStartUp::getStartupState() > STATE_WEARABLES_WAIT
+        && !LLInventoryModelBackgroundFetch::instance().inventoryFetchInProgress())
     {
         LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id);
-        if (!cat || (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN))
+        if ((!cat && folder_id.notNull()) || (cat && cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN))
         {
             // At the moment background fetch only cares about VERSION_UNKNOWN,
             // so do not check isCategoryComplete that compares descendant count
-            LLInventoryModelBackgroundFetch::instance().start(folder_id);
+            LLInventoryModelBackgroundFetch::instance().start(folder_id, false);
         }
 	}
 
+    if (!checkAgainstFilterThumbnails(folder_id))
+    {
+        return false;
+    }
+
 	// Marketplace folder filtering
     const U32 filterTypes = mFilterOps.mFilterTypes;
     const U32 marketplace_filter = FILTERTYPE_MARKETPLACE_ACTIVE | FILTERTYPE_MARKETPLACE_INACTIVE |
@@ -573,6 +583,19 @@ bool LLInventoryFilter::checkAgainstFilterLinks(const LLFolderViewModelItemInven
 	return TRUE;
 }
 
+bool LLInventoryFilter::checkAgainstFilterThumbnails(const LLUUID& object_id) const
+{
+    const LLInventoryObject *object = gInventory.getObject(object_id);
+    if (!object) return true;
+
+    const bool is_thumbnail = object->getThumbnailUUID().notNull();
+    if (is_thumbnail && (mFilterOps.mFilterThumbnails == FILTER_EXCLUDE_THUMBNAILS))
+        return false;
+    if (!is_thumbnail && (mFilterOps.mFilterThumbnails == FILTER_ONLY_THUMBNAILS))
+        return false;
+    return true;
+}
+
 bool LLInventoryFilter::checkAgainstCreator(const LLFolderViewModelItemInventory* listener) const
 {
 	if (!listener) return TRUE;
@@ -603,6 +626,9 @@ bool LLInventoryFilter::checkAgainstSearchVisibility(const LLFolderViewModelItem
 	if (is_link && ((mFilterOps.mSearchVisibility & VISIBILITY_LINKS) == 0))
 		return FALSE;
 
+    if (listener->isItemInOutfits() && ((mFilterOps.mSearchVisibility & VISIBILITY_OUTFITS) == 0))
+        return FALSE;
+
 	if (listener->isItemInTrash() && ((mFilterOps.mSearchVisibility & VISIBILITY_TRASH) == 0))
 		return FALSE;
 
@@ -741,6 +767,32 @@ void LLInventoryFilter::setFilterSettingsTypes(U64 types)
     mFilterOps.mFilterTypes |= FILTERTYPE_SETTINGS;
 }
 
+void LLInventoryFilter::setFilterThumbnails(U64 filter_thumbnails)
+{
+    if (mFilterOps.mFilterThumbnails != filter_thumbnails)
+    {
+        if (mFilterOps.mFilterThumbnails == FILTER_EXCLUDE_THUMBNAILS
+            && filter_thumbnails == FILTER_ONLY_THUMBNAILS)
+        {
+            setModified(FILTER_RESTART);
+        }
+        else if (mFilterOps.mFilterThumbnails == FILTER_ONLY_THUMBNAILS
+            && filter_thumbnails == FILTER_EXCLUDE_THUMBNAILS)
+        {
+            setModified(FILTER_RESTART);
+        }
+        else if (mFilterOps.mFilterThumbnails == FILTER_INCLUDE_THUMBNAILS)
+        {
+            setModified(FILTER_MORE_RESTRICTIVE);
+        }
+        else
+        {
+            setModified(FILTER_LESS_RESTRICTIVE);
+        }
+    }
+    mFilterOps.mFilterThumbnails = filter_thumbnails;
+}
+
 void LLInventoryFilter::setFilterEmptySystemFolders()
 {
 	mFilterOps.mFilterTypes |= FILTERTYPE_EMPTYFOLDERS;
@@ -799,6 +851,24 @@ void LLInventoryFilter::toggleSearchVisibilityLinks()
 	}
 }
 
+void LLInventoryFilter::toggleSearchVisibilityOutfits()
+{
+    bool hide_outfits = mFilterOps.mSearchVisibility & VISIBILITY_OUTFITS;
+    if (hide_outfits)
+    {
+        mFilterOps.mSearchVisibility &= ~VISIBILITY_OUTFITS;
+    }
+    else
+    {
+        mFilterOps.mSearchVisibility |= VISIBILITY_OUTFITS;
+    }
+
+    if (hasFilterString())
+    {
+        setModified(hide_outfits ? FILTER_MORE_RESTRICTIVE : FILTER_LESS_RESTRICTIVE);
+    }
+}
+
 void LLInventoryFilter::toggleSearchVisibilityTrash()
 {
 	bool hide_trash = mFilterOps.mSearchVisibility & VISIBILITY_TRASH;
@@ -1539,6 +1609,11 @@ U64 LLInventoryFilter::getSearchVisibilityTypes() const
 	return mFilterOps.mSearchVisibility;
 }
 
+U64 LLInventoryFilter::getFilterThumbnails() const
+{
+    return mFilterOps.mFilterThumbnails;
+}
+
 bool LLInventoryFilter::hasFilterString() const
 {
 	return mFilterSubString.size() > 0;
@@ -1616,9 +1691,9 @@ void LLInventoryFilter::setDefaultEmptyLookupMessage(const std::string& message)
 	mDefaultEmptyLookupMessage = LLTrans::getString(message);
 }
 
-std::string LLInventoryFilter::getEmptyLookupMessage() const
+std::string LLInventoryFilter::getEmptyLookupMessage(bool is_empty_folder) const
 {
-	if (isDefault() && !mDefaultEmptyLookupMessage.empty())
+	if ((isDefault() || is_empty_folder) && !mDefaultEmptyLookupMessage.empty())
 	{
 		return mDefaultEmptyLookupMessage;
 	}
@@ -1639,7 +1714,7 @@ bool LLInventoryFilter::areDateLimitsSet()
 
 bool LLInventoryFilter::showAllResults() const
 {
-	return hasFilterString();
+	return hasFilterString() && !mSingleFolderMode;
 }
 
 
diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h
index 05734a6f27b86f727a6b4b1112f051447d8f1dd8..1f03abe89523123b4a970881cf25ab539e87c61a 100644
--- a/indra/newview/llinventoryfilter.h
+++ b/indra/newview/llinventoryfilter.h
@@ -75,6 +75,13 @@ class LLInventoryFilter : public LLFolderViewFilter
 		FILTERLINK_ONLY_LINKS		// only show links
 	};
 
+    enum EFilterThumbnail
+    {
+        FILTER_INCLUDE_THUMBNAILS,
+        FILTER_EXCLUDE_THUMBNAILS,
+        FILTER_ONLY_THUMBNAILS
+    };
+
 	enum ESortOrderType
 	{
 		SO_NAME = 0,						// Sort inventory by name
@@ -104,7 +111,8 @@ class LLInventoryFilter : public LLFolderViewFilter
 		VISIBILITY_NONE = 0,
 		VISIBILITY_TRASH = 0x1 << 0,
 		VISIBILITY_LIBRARY = 0x1 << 1,
-		VISIBILITY_LINKS	= 0x1 << 2
+		VISIBILITY_LINKS	= 0x1 << 2,
+        VISIBILITY_OUTFITS    = 0x1 << 3
 	};
 
 	struct FilterOps
@@ -139,12 +147,14 @@ class LLInventoryFilter : public LLFolderViewFilter
 			Optional<EFolderShow>		show_folder_state;
 			Optional<PermissionMask>	permissions;
 			Optional<EFilterCreatorType> creator_type;
+            Optional<EFilterThumbnail> thumbnails;
 
 			Params()
 			:	types("filter_types", FILTERTYPE_OBJECT),
 				object_types("object_types", 0xffffFFFFffffFFFFULL),
 				wearable_types("wearable_types", 0xffffFFFFffffFFFFULL),
                 settings_types("settings_types", 0xffffFFFFffffFFFFULL),
+                thumbnails("thumbnails", FILTER_INCLUDE_THUMBNAILS),
 				category_types("category_types", 0xffffFFFFffffFFFFULL),
 				links("links", FILTERLINK_INCLUDE_LINKS),
 				search_visibility("search_visibility", 0xFFFFFFFF),
@@ -165,6 +175,7 @@ class LLInventoryFilter : public LLFolderViewFilter
 		U64				mFilterObjectTypes,   // For _OBJECT
 						mFilterWearableTypes,
                         mFilterSettingsTypes, // for _SETTINGS
+                        mFilterThumbnails,
 						mFilterLinks,
 						mFilterCategoryTypes; // For _CATEGORY
 		LLUUID      	mFilterUUID; 		  // for UUID
@@ -207,6 +218,7 @@ class LLInventoryFilter : public LLFolderViewFilter
 	U64					getFilterWearableTypes() const;
 	U64					getFilterSettingsTypes() const;
 	U64					getSearchVisibilityTypes() const;
+    U64                 getFilterThumbnails() const;
 
 	bool 				isFilterObjectTypesWith(LLInventoryType::EType t) const;
 	void 				setFilterObjectTypes(U64 types);
@@ -221,6 +233,7 @@ class LLInventoryFilter : public LLFolderViewFilter
 	void				setFilterMarketplaceUnassociatedFolders();
     void                setFilterMarketplaceListingFolders(bool select_only_listing_folders);
     void                setFilterNoMarketplaceFolder();
+    void                setFilterThumbnails(U64 filter_thumbnails);
 	void				updateFilterTypes(U64 types, U64& current_types);
 	void 				setSearchType(ESearchType type);
 	ESearchType			getSearchType() { return mSearchType; }
@@ -228,6 +241,7 @@ class LLInventoryFilter : public LLFolderViewFilter
 
 	void				toggleSearchVisibilityLinks();
 	void				toggleSearchVisibilityTrash();
+    void                toggleSearchVisibilityOutfits();
 	void				toggleSearchVisibilityLibrary();
 	void 				setSearchVisibilityTypes(U32 types);
 	void 				setSearchVisibilityTypes(const Params& params);
@@ -237,6 +251,8 @@ class LLInventoryFilter : public LLFolderViewFilter
 	const std::string& 	getFilterSubStringOrig() const { return mFilterSubStringOrig; } 
 	bool 				hasFilterString() const;
 
+    void                setSingleFolderMode(bool is_single_folder) { mSingleFolderMode = is_single_folder; }
+
 	void 				setFilterPermissions(PermissionMask perms);
 	PermissionMask 		getFilterPermissions() const;
 
@@ -277,7 +293,7 @@ class LLInventoryFilter : public LLFolderViewFilter
 
 	void 				setEmptyLookupMessage(const std::string& message);
 	void				setDefaultEmptyLookupMessage(const std::string& message);
-	std::string			getEmptyLookupMessage() const;
+	std::string			getEmptyLookupMessage(bool is_empty_folder = false) const;
 
 	// +-------------------------------------------------------------------+
 	// + Status
@@ -321,6 +337,8 @@ class LLInventoryFilter : public LLFolderViewFilter
 
 	LLInventoryFilter& operator =(const LLInventoryFilter& other);
 
+    bool checkAgainstFilterThumbnails(const LLUUID& object_id) const;
+
 private:
 	bool				areDateLimitsSet();
 	bool 				checkAgainstFilterType(const class LLFolderViewModelItemInventory* listener) const;
@@ -359,6 +377,8 @@ class LLInventoryFilter : public LLFolderViewFilter
 
 	std::vector<std::string> mFilterTokens;
 	std::string				 mExactToken;
+
+    bool mSingleFolderMode;
 };
 
 #endif
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 1d706ead68c2a747c2ae2c6a81a2796d2164cdb4..4581ba6eb544189b8b386c99db6009fe56986f63 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -46,13 +46,16 @@
 #include "llappearancemgr.h"
 #include "llappviewer.h"
 #include "llavataractions.h"
+#include "llavatarnamecache.h"
 #include "llclipboard.h"
 #include "lldirpicker.h"
 #include "lldonotdisturbnotificationstorage.h"
+#include "llfloatermarketplacelistings.h"
 #include "llfloatersidepanelcontainer.h"
 #include "llfocusmgr.h"
 #include "llfolderview.h"
 #include "llgesturemgr.h"
+#include "llgiveinventory.h"
 #include "lliconctrl.h"
 #include "llimview.h"
 #include "llinventorybridge.h"
@@ -95,6 +98,7 @@
 BOOL LLInventoryState::sWearNewClothing = FALSE;
 LLUUID LLInventoryState::sWearNewClothingTransactionID;
 std::list<LLUUID> LLInventoryAction::sMarketplaceFolders;
+bool LLInventoryAction::sDeleteConfirmationDisplayed = false;
 
 // Helper function : callback to update a folder after inventory action happened in the background
 void update_folder_cb(const LLUUID& dest_folder)
@@ -402,7 +406,7 @@ void update_all_marketplace_count(const LLUUID& cat_id)
 void update_all_marketplace_count()
 {
     // Get the marketplace root and launch the recursive exploration
-    const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+    const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
     if (!marketplace_listings_uuid.isNull())
     {
         update_all_marketplace_count(marketplace_listings_uuid);
@@ -434,14 +438,36 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s
 }
 
 void copy_inventory_category(LLInventoryModel* model,
-							 LLViewerInventoryCategory* cat,
-							 const LLUUID& parent_id,
-							 const LLUUID& root_copy_id,
-							 bool move_no_copy_items )
+                             LLViewerInventoryCategory* cat,
+                             const LLUUID& parent_id,
+                             const LLUUID& root_copy_id,
+                             bool move_no_copy_items)
+{
+    // Create the initial folder
+    inventory_func_type func = [model, cat, root_copy_id, move_no_copy_items](const LLUUID& new_id)
+    {
+        copy_inventory_category_content(new_id, model, cat, root_copy_id, move_no_copy_items);
+    };
+    gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID());
+}
+
+void copy_inventory_category(LLInventoryModel* model,
+                             LLViewerInventoryCategory* cat,
+                             const LLUUID& parent_id,
+                             const LLUUID& root_copy_id,
+                             bool move_no_copy_items,
+                             inventory_func_type callback)
 {
 	// Create the initial folder
-	inventory_func_type func = boost::bind(&copy_inventory_category_content, _1, model, cat, root_copy_id, move_no_copy_items);
-	gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func);
+    inventory_func_type func = [model, cat, root_copy_id, move_no_copy_items, callback](const LLUUID &new_id)
+    {
+        copy_inventory_category_content(new_id, model, cat, root_copy_id, move_no_copy_items);
+        if (callback)
+        {
+            callback(new_id);
+        }
+    };
+	gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID());
 }
 
 void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& root_copy_id, bool move_no_copy_items)
@@ -566,11 +592,12 @@ BOOL get_is_item_worn(const LLUUID& id)
 	const LLViewerInventoryItem* item = gInventory.getItem(id);
 	if (!item)
 		return FALSE;
-    
+
     if (item->getIsLinkType() && !gInventory.getItem(item->getLinkedUUID()))
     {
         return FALSE;
     }
+
 	// Consider the item as worn if it has links in COF.
 // [SL:KB] - The code below causes problems across the board so it really just needs to go
 //	if (LLAppearanceMgr::instance().isLinkedInCOF(id))
@@ -862,24 +889,37 @@ BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id)
 
 void show_task_item_profile(const LLUUID& item_uuid, const LLUUID& object_id)
 {
-	if (gSavedSettings.getBOOL("ShowPropertiesFloaters"))
-		LLFloaterReg::showInstance("properties", LLSD().with("item_id", item_uuid).with("object_id", object_id));
-	else
-		LLFloaterSidePanelContainer::showPanel("inventory", LLSD().with("id", item_uuid).with("object", object_id));
+    LLSD params;
+    params["id"] = item_uuid;
+    params["object"] = object_id;
+    
+    LLFloaterReg::showInstance("item_properties", params);
 }
 
 void show_item_profile(const LLUUID& item_uuid)
 {
 	LLUUID linked_uuid = gInventory.getLinkedItemID(item_uuid);
-	if (gSavedSettings.getBOOL("ShowPropertiesFloaters"))
-		LLFloaterReg::showInstance("properties", LLSD().with("item_id", item_uuid));
-	else
-		LLFloaterSidePanelContainer::showPanel("inventory", LLSD().with("id", linked_uuid));
+    LLFloaterReg::showInstance("item_properties", LLSD().with("id", linked_uuid));
 }
 
 void show_item_original(const LLUUID& item_uuid)
 {
-    LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
+    static LLUICachedControl<bool> find_original_new_floater("FindOriginalOpenWindow", false);
+
+    //show in a new single-folder window
+    if(find_original_new_floater)
+    {
+        const LLUUID& linked_item_uuid = gInventory.getLinkedItemID(item_uuid);
+        const LLInventoryObject *obj = gInventory.getObject(linked_item_uuid);
+        if (obj && obj->getParentUUID().notNull())
+        {
+            LLPanelMainInventory::newFolderWindow(obj->getParentUUID(), linked_item_uuid);
+        }
+    }
+    //show in main Inventory
+    else
+    {
+        LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
     if (!floater_inventory)
     {
         LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL;
@@ -891,6 +931,10 @@ void show_item_original(const LLUUID& item_uuid)
         LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
         if (main_inventory)
         {
+            if(main_inventory->isSingleFolderMode())
+            {
+                main_inventory->toggleViewMode();
+            }
             main_inventory->resetAllItemsFilters();
         }
         reset_inventory_filter();
@@ -899,7 +943,6 @@ void show_item_original(const LLUUID& item_uuid)
         {
             LLFloaterReg::toggleInstanceOrBringToFront("inventory");
         }
-        sidepanel_inventory->showInventoryPanel();
 
         const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
         if (gInventory.isObjectDescendentOf(gInventory.getLinkedItemID(item_uuid), inbox_id))
@@ -919,6 +962,7 @@ void show_item_original(const LLUUID& item_uuid)
             }
         }
     }
+    }
 }
 
 
@@ -940,22 +984,6 @@ void open_marketplace_listings()
 	LLFloaterReg::showInstance("marketplace_listings");
 }
 
-// Create a new folder in destFolderId with the same name as the item name and return the uuid of the new folder
-// Note: this is used locally in various situation where we need to wrap an item into a special folder
-LLUUID create_folder_for_item(LLInventoryItem* item, const LLUUID& destFolderId)
-{
-	llassert(item);
-	llassert(destFolderId.notNull());
-
-	LLUUID created_folder_id = gInventory.createNewCategory(destFolderId, LLFolderType::FT_NONE, item->getName());
-	gInventory.notifyObservers();
-    
-    // *TODO : Create different notifications for the various cases
-	LLNotificationsUtil::add("OutboxFolderCreated");
-
-	return created_folder_id;
-}
-
 ///----------------------------------------------------------------------------
 // Marketplace functions
 //
@@ -970,7 +998,7 @@ S32 depth_nesting_in_marketplace(LLUUID cur_uuid)
     // Todo: findCategoryUUIDForType is somewhat expensive with large
     // flat root folders yet we use depth_nesting_in_marketplace at
     // every turn, find a way to correctly cache this id.
-    const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+    const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
     if (marketplace_listings_uuid.isNull())
     {
         return -1;
@@ -1442,6 +1470,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn
     return accept;
 }
 
+// Can happen asynhroneously!!!
 bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_folder, bool copy)
 {
     // Get the marketplace listings depth of the destination folder, exit with error if not under marketplace
@@ -1481,54 +1510,119 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol
         if (can_move_to_marketplace(inv_item, error_msg, true))
         {
             // When moving an isolated item, we might need to create the folder structure to support it
+
+            LLUUID item_id = inv_item->getUUID();
+            std::function<void(const LLUUID&)> callback_create_stock = [copy, item_id](const LLUUID& new_cat_id)
+            {
+                if (new_cat_id.isNull())
+                {
+                    LL_WARNS() << "Failed to create category" << LL_ENDL;
+                    LLSD subs;
+                    subs["[ERROR_CODE]"] =
+                        LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Accepted");
+                    LLNotificationsUtil::add("MerchantPasteFailed", subs);
+                    return;
+                }
+
+                // Verify we can have this item in that destination category
+                LLViewerInventoryCategory* dest_cat = gInventory.getCategory(new_cat_id);
+                LLViewerInventoryItem * viewer_inv_item = gInventory.getItem(item_id);
+                if (!dest_cat || !viewer_inv_item)
+                {
+                    LL_WARNS() << "Move to marketplace: item or folder do not exist" << LL_ENDL;
+
+                    LLSD subs;
+                    subs["[ERROR_CODE]"] =
+                        LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Accepted");
+                    LLNotificationsUtil::add("MerchantPasteFailed", subs);
+                    return;
+                }
+                if (!dest_cat->acceptItem(viewer_inv_item))
+                {
+                    LLSD subs;
+                    subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Accepted");
+                    LLNotificationsUtil::add("MerchantPasteFailed", subs);
+                }
+
+                if (copy)
+                {
+                    // Copy the item
+                    LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_id));
+                    copy_inventory_item(
+                        gAgent.getID(),
+                        viewer_inv_item->getPermissions().getOwner(),
+                        viewer_inv_item->getUUID(),
+                        new_cat_id,
+                        std::string(),
+                        cb);
+                }
+                else
+                {
+                    // Reparent the item
+                    gInventory.changeItemParent(viewer_inv_item, new_cat_id, true);
+                }
+            };
+
+            std::function<void(const LLUUID&)> callback_dest_create = [item_id, callback_create_stock](const LLUUID& new_cat_id)
+            {
+                if (new_cat_id.isNull())
+                {
+                    LL_WARNS() << "Failed to create category" << LL_ENDL;
+                    LLSD subs;
+                    subs["[ERROR_CODE]"] =
+                        LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Accepted");
+                    LLNotificationsUtil::add("MerchantPasteFailed", subs);
+                    return;
+                }
+
+                LLViewerInventoryCategory* dest_cat = gInventory.getCategory(new_cat_id);
+                LLViewerInventoryItem * viewer_inv_item = gInventory.getItem(item_id);
+                if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) &&
+                    (dest_cat->getPreferredType() != LLFolderType::FT_MARKETPLACE_STOCK))
+                {
+                    // We need to create a stock folder to move a no copy item
+                    gInventory.createNewCategory(new_cat_id, LLFolderType::FT_MARKETPLACE_STOCK, viewer_inv_item->getName(), callback_create_stock);
+                }
+                else
+                {
+                    callback_create_stock(new_cat_id);
+                }
+            };
+
             if (depth == 0)
             {
                 // We need a listing folder
-                dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName());
-                depth++;
+               gInventory.createNewCategory(dest_folder,
+                                            LLFolderType::FT_NONE,
+                                            viewer_inv_item->getName(),
+                                            [callback_dest_create](const LLUUID &new_cat_id)
+                                            {
+                                                if (new_cat_id.isNull())
+                                                {
+                                                    LL_WARNS() << "Failed to create listing folder for marketpace" << LL_ENDL;
+                                                    return;
+                                                }
+                                                LLViewerInventoryCategory *dest_cat = gInventory.getCategory(new_cat_id);
+                                                if (!dest_cat)
+                                                {
+                                                    LL_WARNS() << "Failed to find freshly created listing folder" << LL_ENDL;
+                                                    return;
+                                                }
+                                                // version folder
+                                                gInventory.createNewCategory(new_cat_id,
+                                                                             LLFolderType::FT_NONE,
+                                                                             dest_cat->getName(),
+                                                                             callback_dest_create);
+                                            });
             }
-            if (depth == 1)
+            else if (depth == 1)
             {
                 // We need a version folder
-                dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName());
-                depth++;
-            }
-			LLViewerInventoryCategory* dest_cat = gInventory.getCategory(dest_folder);
-            if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) &&
-                (dest_cat->getPreferredType() != LLFolderType::FT_MARKETPLACE_STOCK))
-            {
-                // We need to create a stock folder to move a no copy item
-                dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_MARKETPLACE_STOCK, viewer_inv_item->getName());
-                dest_cat = gInventory.getCategory(dest_folder);
-                depth++;
-            }
-            
-            // Verify we can have this item in that destination category
-            if (!dest_cat->acceptItem(viewer_inv_item))
-            {
-                LLSD subs;
-                subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Accepted");
-                LLNotificationsUtil::add("MerchantPasteFailed", subs);
-                return false;
-            }
-            if (copy)
-            {
-                // Copy the item
-                LL_INFOS("SLM") << "Copy item '" << make_info(viewer_inv_item) << "' to '" << make_inventory_path(dest_folder) << "'" << LL_ENDL;
-                LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, dest_folder));
-                copy_inventory_item(
-                                    gAgent.getID(),
-                                    viewer_inv_item->getPermissions().getOwner(),
-                                    viewer_inv_item->getUUID(),
-                                    dest_folder,
-                                    std::string(),
-                                    cb);
+                gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName(), callback_dest_create);
             }
             else
             {
-                LL_INFOS("SLM") << "Move item '" << make_info(viewer_inv_item) << "' to '" << make_inventory_path(dest_folder) << "'" << LL_ENDL;
-                // Reparent the item
-                gInventory.changeItemParent(viewer_inv_item, dest_folder, true);
+                callback_dest_create(dest_folder);
             }
         }
         else
@@ -1577,7 +1671,7 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU
             // Reparent the folder
             gInventory.changeCategoryParent(viewer_inv_cat, dest_folder, false);
             // Check the destination folder recursively for no copy items and promote the including folders if any
-            validate_marketplacelistings(dest_cat);
+            LLMarketplaceValidator::getInstance()->validateMarketplaceListings(dest_folder);
         }
 
         // Update the modified folders
@@ -1602,32 +1696,23 @@ bool sort_alpha(const LLViewerInventoryCategory* cat1, const LLViewerInventoryCa
 	return cat1->getName().compare(cat2->getName()) < 0;
 }
 
-void dump_trace(std::string& message, S32 depth, LLError::ELevel log_level)
-{
-    LL_INFOS() << "validate_marketplacelistings : error = "<< log_level << ", depth = " << depth << ", message = " << message <<  LL_ENDL;
-}
-
 // Make all relevant business logic checks on the marketplace listings starting with the folder as argument.
 // This function does no deletion of listings but a mere audit and raises issues to the user (through the
-// optional callback cb). It also returns a boolean, true if things validate, false if issues are raised.
+// optional callback cb).
 // The only inventory changes that are done is to move and sort folders containing no-copy items to stock folders.
-bool validate_marketplacelistings(
+// @pending_callbacks - how many callbacks we are waiting for, must be inited before use
+// @result - true if things validate, false if issues are raised, must be inited before use
+typedef boost::function<void(S32 pending_callbacks, bool result)> validation_result_callback_t;
+void validate_marketplacelistings(
     LLInventoryCategory* cat,
-    validation_callback_t cb,
+    validation_result_callback_t cb_result,
+    LLMarketplaceValidator::validation_msg_callback_t cb_msg,
     bool fix_hierarchy,
     S32 depth,
-    bool notify_observers)
+    bool notify_observers,
+    S32 &pending_callbacks,
+    bool &result)
 {
-#if 0
-    // Used only for debug
-    if (!cb)
-    {
-        cb =  boost::bind(&dump_trace, _1, _2, _3);
-    }
-#endif
-    // Folder is valid unless issue is raised
-    bool result = true;
-    
     // Get the type and the depth of the folder
     LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *) (cat);
 	const LLFolderType::EType folder_type = cat->getPreferredType();
@@ -1659,10 +1744,10 @@ bool validate_marketplacelistings(
         if (!can_move_folder_to_marketplace(cat, cat, cat, message, 0, fix_hierarchy))
         {
             result = false;
-            if (cb)
+            if (cb_msg)
             {
                 message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + message;
-                cb(message,depth,LLError::LEVEL_ERROR);
+                cb_msg(message,depth,LLError::LEVEL_ERROR);
             }
         }
     }
@@ -1672,26 +1757,46 @@ bool validate_marketplacelistings(
     {
         if (fix_hierarchy)
         {
-            if (cb)
+            if (cb_msg)
             {
                 std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning") + " " + LLTrans::getString("Marketplace Validation Warning Stock");
-                cb(message,depth,LLError::LEVEL_WARN);
+                cb_msg(message,depth,LLError::LEVEL_WARN);
             }
+
             // Nest the stock folder one level deeper in a normal folder and restart from there
+            pending_callbacks++;
             LLUUID parent_uuid = cat->getParentUUID();
-            LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, LLFolderType::FT_NONE, cat->getName());
-            LLInventoryCategory* new_cat = gInventory.getCategory(folder_uuid);
-            gInventory.changeCategoryParent(viewer_cat, folder_uuid, false);
-            result &= validate_marketplacelistings(new_cat, cb, fix_hierarchy, depth + 1, notify_observers);
-            return result;
+            LLUUID cat_uuid = cat->getUUID();
+            gInventory.createNewCategory(parent_uuid,
+                LLFolderType::FT_NONE,
+                cat->getName(),
+                [cat_uuid, cb_result, cb_msg, fix_hierarchy, depth](const LLUUID &new_cat_id)
+            {
+                if (new_cat_id.isNull())
+                {
+                    cb_result(0, false);
+                    return;
+                }
+                LLInventoryCategory * move_cat = gInventory.getCategory(cat_uuid);
+                LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *)(move_cat);
+                LLInventoryCategory * new_cat = gInventory.getCategory(new_cat_id);
+                gInventory.changeCategoryParent(viewer_cat, new_cat_id, false);
+                S32 pending = 0;
+                bool result = true;
+                validate_marketplacelistings(new_cat, cb_result, cb_msg, fix_hierarchy, depth + 1, true, pending, result);
+                cb_result(pending, result);
+            }
+            );
+            result = false;
+            return;
         }
         else
         {
             result = false;
-            if (cb)
+            if (cb_msg)
             {
                 std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + LLTrans::getString("Marketplace Validation Warning Stock");
-                cb(message,depth,LLError::LEVEL_ERROR);
+                cb_msg(message,depth,LLError::LEVEL_ERROR);
             }
         }
     }
@@ -1722,10 +1827,10 @@ bool validate_marketplacelistings(
         if (!can_move_to_marketplace(item, error_msg, false))
         {
             has_bad_items = true;
-            if (cb && fix_hierarchy)
+            if (cb_msg && fix_hierarchy)
             {
                 std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg;
-                cb(message,depth,LLError::LEVEL_ERROR);
+                cb_msg(message,depth,LLError::LEVEL_ERROR);
             }
             continue;
         }
@@ -1756,35 +1861,35 @@ bool validate_marketplacelistings(
             if (depth == 2)
             {
                 // If this is an empty version folder, warn only (listing won't be delivered by AIS, but only AIS should unlist)
-                if (cb)
+                if (cb_msg)
                 {
                     std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Version");
-                    cb(message,depth,LLError::LEVEL_WARN);
+                    cb_msg(message,depth,LLError::LEVEL_WARN);
                 }
             }
             else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2))
             {
                 // If this is a legit but empty stock folder, warn only (listing must stay searchable when out of stock)
-                if (cb)
+                if (cb_msg)
                 {
                     std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Stock");
-                    cb(message,depth,LLError::LEVEL_WARN);
+                    cb_msg(message,depth,LLError::LEVEL_WARN);
                 }
             }
-            else if (cb)
+            else if (cb_msg)
             {
                 // We warn if there's nothing in a regular folder (may be it's an under construction listing)
                 std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning Empty");
-                cb(message,depth,LLError::LEVEL_WARN);
+                cb_msg(message,depth,LLError::LEVEL_WARN);
             }
         }
         else
         {
             // Done with that folder : Print out the folder name unless we already found an error here
-            if (cb && result && (depth >= 1))
+            if (cb_msg && result && (depth >= 1))
             {
                 std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
-                cb(message,depth,LLError::LEVEL_INFO);
+                cb_msg(message,depth,LLError::LEVEL_INFO);
             }
         }
     }
@@ -1792,10 +1897,10 @@ bool validate_marketplacelistings(
     else if ((count == 1) && !has_bad_items && (((unique_key == default_key) && (depth > 1)) || ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2) && (cat_array->size() == 0))))
     {
         // Done with that folder : Print out the folder name unless we already found an error here
-        if (cb && result && (depth >= 1))
+        if (cb_msg && result && (depth >= 1))
         {
             std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
-            cb(message,depth,LLError::LEVEL_INFO);
+            cb_msg(message,depth,LLError::LEVEL_INFO);
         }
     }
     else
@@ -1817,11 +1922,12 @@ bool validate_marketplacelistings(
                 while (items_vector_it != items_vector.end())
                 {
                     // Create a new folder
-                    LLUUID parent_uuid = (depth > 2 ? viewer_cat->getParentUUID() : viewer_cat->getUUID());
+                    const LLUUID parent_uuid = (depth > 2 ? viewer_cat->getParentUUID() : viewer_cat->getUUID());
+                    const LLUUID origin_uuid = viewer_cat->getUUID();
                     LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(items_vector_it->second.back());
                     std::string folder_name = (depth >= 1 ? viewer_cat->getName() : viewer_inv_item->getName());
                     LLFolderType::EType new_folder_type = (items_vector_it->first == default_key ? LLFolderType::FT_NONE : LLFolderType::FT_MARKETPLACE_STOCK);
-                    if (cb)
+                    if (cb_msg)
                     {
                         std::string message = "";
                         if (new_folder_type == LLFolderType::FT_MARKETPLACE_STOCK)
@@ -1832,30 +1938,71 @@ bool validate_marketplacelistings(
                         {
                             message = indent + folder_name + LLTrans::getString("Marketplace Validation Warning Create Version");
                         }
-                        cb(message,depth,LLError::LEVEL_WARN);
+                        cb_msg(message,depth,LLError::LEVEL_WARN);
                     }
-                    LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, new_folder_type, folder_name);
-                    
-                    // Move each item to the new folder
-                    while (!items_vector_it->second.empty())
+
+                    pending_callbacks++;
+                    std::vector<LLUUID> uuid_vector = items_vector_it->second; // needs to be a copy for lambda
+                    gInventory.createNewCategory(
+                        parent_uuid,
+                        new_folder_type,
+                        folder_name,
+                        [uuid_vector, cb_result, cb_msg, depth, parent_uuid, origin_uuid, notify_observers](const LLUUID &new_category_id)
                     {
-                        LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(items_vector_it->second.back());
-                        if (cb)
+                        // Move each item to the new folder
+                        std::vector<LLUUID>::const_reverse_iterator iter = uuid_vector.rbegin();
+                        while (iter != uuid_vector.rend())
                         {
-                            std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Move");
-                            cb(message,depth,LLError::LEVEL_WARN);
+                            LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(*iter);
+                            if (cb_msg)
+                            {
+                                std::string indent;
+                                for (int i = 1; i < depth; i++)
+                                {
+                                    indent += "    ";
+                                }
+                                std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Move");
+                                cb_msg(message, depth, LLError::LEVEL_WARN);
+                            }
+                            gInventory.changeItemParent(viewer_inv_item, new_category_id, true);
+                            iter++;
                         }
-                        gInventory.changeItemParent(viewer_inv_item, folder_uuid, true);
-                        items_vector_it->second.pop_back();
-                    }
-                    
-                    // Next type
-                    update_marketplace_category(parent_uuid);
-                    update_marketplace_category(folder_uuid);
-                    if (notify_observers)
-                    {
-                        gInventory.notifyObservers();
+
+                        if (origin_uuid != parent_uuid)
+                        {
+                            // We might have moved last item from a folder, check if it needs to be removed
+                            LLViewerInventoryCategory* cat = gInventory.getCategory(origin_uuid);
+                            if (cat->getDescendentCount() == 0)
+                            {
+                                // Remove previous folder if it ends up empty
+                                if (cb_msg)
+                                {
+                                    std::string indent;
+                                    for (int i = 1; i < depth; i++)
+                                    {
+                                        indent += "    ";
+                                    }
+                                    std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning Delete");
+                                    cb_msg(message, depth, LLError::LEVEL_WARN);
+                                }
+                                gInventory.removeCategory(cat->getUUID());
+                                if (notify_observers)
+                                {
+                                    gInventory.notifyObservers();
+                                }
+                            }
+                        }
+
+                        // Next type
+                        update_marketplace_category(parent_uuid);
+                        update_marketplace_category(new_category_id);
+                        if (notify_observers)
+                        {
+                            gInventory.notifyObservers();
+                        }
+                        cb_result(0, true);
                     }
+                    );
                     items_vector_it++;
                 }
             }
@@ -1869,11 +2016,11 @@ bool validate_marketplacelistings(
                 {
                     LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *) (*iter);
                     gInventory.changeCategoryParent(viewer_cat, parent_uuid, false);
-                    result &= validate_marketplacelistings(viewer_cat, cb, fix_hierarchy, depth, false);
+                    validate_marketplacelistings(viewer_cat, cb_result, cb_msg, fix_hierarchy, depth, false, pending_callbacks, result);
                 }
             }
         }
-        else if (cb)
+        else if (cb_msg)
         {
             // We are not fixing the hierarchy but reporting problems, report everything we can find
             // Print the folder name
@@ -1884,20 +2031,20 @@ bool validate_marketplacelistings(
                     // Report if a stock folder contains a mix of items
                     result = false;
                     std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Mixed Stock");
-                    cb(message,depth,LLError::LEVEL_ERROR);
+                    cb_msg(message,depth,LLError::LEVEL_ERROR);
                 }
                 else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (cat_array->size() != 0))
                 {
                     // Report if a stock folder contains subfolders
                     result = false;
                     std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Subfolder In Stock");
-                    cb(message,depth,LLError::LEVEL_ERROR);
+                    cb_msg(message,depth,LLError::LEVEL_ERROR);
                 }
                 else
                 {
                     // Simply print the folder name
                     std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
-                    cb(message,depth,LLError::LEVEL_INFO);
+                    cb_msg(message,depth,LLError::LEVEL_INFO);
                 }
             }
             // Scan each item and report if there's a problem
@@ -1912,21 +2059,21 @@ bool validate_marketplacelistings(
                     // Report items that shouldn't be there to start with
                     result = false;
                     std::string message = indent + "    " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg;
-                    cb(message,depth,LLError::LEVEL_ERROR);
+                    cb_msg(message,depth,LLError::LEVEL_ERROR);
                 }
                 else if ((!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) && (folder_type != LLFolderType::FT_MARKETPLACE_STOCK))
                 {
                     // Report stock items that are misplaced
                     result = false;
                     std::string message = indent + "    " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error Stock Item");
-                    cb(message,depth,LLError::LEVEL_ERROR);
+                    cb_msg(message,depth,LLError::LEVEL_ERROR);
                 }
                 else if (depth == 1)
                 {
                     // Report items not wrapped in version folder
                     result = false;
                     std::string message = indent + "    " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Unwrapped Item");
-                    cb(message,depth,LLError::LEVEL_ERROR);
+                    cb_msg(message,depth,LLError::LEVEL_ERROR);
                 }
             }
         }
@@ -1935,17 +2082,18 @@ bool validate_marketplacelistings(
         if (viewer_cat->getDescendentCount() == 0)
         {
             // Remove the current folder if it ends up empty
-            if (cb)
+            if (cb_msg)
             {
                 std::string message = indent + viewer_cat->getName() + LLTrans::getString("Marketplace Validation Warning Delete");
-                cb(message,depth,LLError::LEVEL_WARN);
+                cb_msg(message,depth,LLError::LEVEL_WARN);
             }
             gInventory.removeCategory(cat->getUUID());
             if (notify_observers)
             {
                 gInventory.notifyObservers();
             }
-            return result && !has_bad_items;
+            result &=!has_bad_items;
+            return;
         }
     }
 
@@ -1958,15 +2106,15 @@ bool validate_marketplacelistings(
 	for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
 	{
 		LLInventoryCategory* category = *iter;
-		result &= validate_marketplacelistings(category, cb, fix_hierarchy, depth + 1, false);
+		validate_marketplacelistings(category, cb_result, cb_msg, fix_hierarchy, depth + 1, false, pending_callbacks, result);
 	}
-    
+
     update_marketplace_category(cat->getUUID(), true, true);
     if (notify_observers)
     {
         gInventory.notifyObservers();
     }
-    return result && !has_bad_items;
+    result &= !has_bad_items;
 }
 
 void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id)
@@ -2066,9 +2214,346 @@ void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::st
 
     inventory_func_type func = boost::bind(&move_items_to_folder, _1, selected_uuids);
     gInventory.createNewCategory(first_item->getParentUUID(), LLFolderType::FT_NONE, folder_name, func);
+}
+
+// Returns true if the item can be moved to Current Outfit or any outfit folder.
+bool can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit)
+{
+    LLInventoryType::EType inv_type = inv_item->getInventoryType();
+    if ((inv_type != LLInventoryType::IT_WEARABLE) &&
+        (inv_type != LLInventoryType::IT_GESTURE) &&
+        (inv_type != LLInventoryType::IT_ATTACHMENT) &&
+        (inv_type != LLInventoryType::IT_OBJECT) &&
+        (inv_type != LLInventoryType::IT_SNAPSHOT) &&
+        (inv_type != LLInventoryType::IT_TEXTURE))
+    {
+        return false;
+    }
+
+    U32 flags = inv_item->getFlags();
+    if(flags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS)
+    {
+        return false;
+    }
 
+    if((inv_type == LLInventoryType::IT_TEXTURE) || (inv_type == LLInventoryType::IT_SNAPSHOT))
+    {
+        return !move_is_into_current_outfit;
+    }
+
+    if (move_is_into_current_outfit && get_is_item_worn(inv_item->getUUID()))
+    {
+        return false;
+    }
+
+    return true;
+}
+
+// Returns TRUE if item is a landmark or a link to a landmark
+// and can be moved to Favorites or Landmarks folder.
+bool can_move_to_landmarks(LLInventoryItem* inv_item)
+{
+    // Need to get the linked item to know its type because LLInventoryItem::getType()
+    // returns actual type AT_LINK for links, not the asset type of a linked item.
+    if (LLAssetType::AT_LINK == inv_item->getType())
+    {
+        LLInventoryItem* linked_item = gInventory.getItem(inv_item->getLinkedUUID());
+        if (linked_item)
+        {
+            return LLAssetType::AT_LANDMARK == linked_item->getType();
+        }
+    }
+
+    return LLAssetType::AT_LANDMARK == inv_item->getType();
 }
 
+// Returns true if folder's content can be moved to Current Outfit or any outfit folder.
+bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit)
+{
+    LLInventoryModel::cat_array_t *cats;
+    LLInventoryModel::item_array_t *items;
+    model->getDirectDescendentsOf(inv_cat->getUUID(), cats, items);
+
+    if (items->size() > wear_limit)
+    {
+        return false;
+    }
+
+    if (items->size() == 0)
+    {
+        // Nothing to move(create)
+        return false;
+    }
+
+    if (cats->size() > 0)
+    {
+        // We do not allow subfolders in outfits of "My Outfits" yet
+        return false;
+    }
+
+    LLInventoryModel::item_array_t::iterator iter = items->begin();
+    LLInventoryModel::item_array_t::iterator end = items->end();
+
+    while (iter != end)
+    {
+        LLViewerInventoryItem *item = *iter;
+        if (!can_move_to_outfit(item, false))
+        {
+            return false;
+        }
+        iter++;
+    }
+
+    return true;
+}
+
+std::string get_localized_folder_name(LLUUID cat_uuid)
+{
+    std::string localized_root_name;
+    const LLViewerInventoryCategory* cat = gInventory.getCategory(cat_uuid);
+    if (cat)
+    {
+        LLFolderType::EType preferred_type = cat->getPreferredType();
+
+        // Translation of Accessories folder in Library inventory folder
+        bool accessories = false;
+        if(cat->getName() == "Accessories")
+        {
+            const LLUUID& parent_folder_id = cat->getParentUUID();
+            accessories = (parent_folder_id == gInventory.getLibraryRootFolderID());
+        }
+
+        //"Accessories" inventory category has folder type FT_NONE. So, this folder
+        //can not be detected as protected with LLFolderType::lookupIsProtectedType
+        localized_root_name.assign(cat->getName());
+        if (accessories || LLFolderType::lookupIsProtectedType(preferred_type))
+        {
+            LLTrans::findString(localized_root_name, std::string("InvFolder ") + cat->getName(), LLSD());
+        }
+    }
+    
+    return localized_root_name;
+}
+
+void new_folder_window(const LLUUID& folder_id)
+{
+    LLPanelMainInventory::newFolderWindow(folder_id);
+}
+
+void ungroup_folder_items(const LLUUID& folder_id)
+{
+    LLInventoryCategory* inv_cat = gInventory.getCategory(folder_id);
+    if (!inv_cat || LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
+    {
+        return;
+    }
+    const LLUUID &new_cat_uuid = inv_cat->getParentUUID();
+    LLInventoryModel::cat_array_t* cat_array;
+    LLInventoryModel::item_array_t* item_array;
+    gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cat_array, item_array);
+    LLInventoryModel::cat_array_t cats = *cat_array;
+    LLInventoryModel::item_array_t items = *item_array;
+
+    for (LLInventoryModel::cat_array_t::const_iterator cat_iter = cats.begin(); cat_iter != cats.end(); ++cat_iter)
+    {
+        LLViewerInventoryCategory* cat = *cat_iter;
+        if (cat)
+        {
+            gInventory.changeCategoryParent(cat, new_cat_uuid, false);
+        }
+    }
+    for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter)
+    {
+        LLViewerInventoryItem* item = *item_iter;
+        if(item)
+        {
+            gInventory.changeItemParent(item, new_cat_uuid, false);
+        }
+    }
+    gInventory.removeCategory(inv_cat->getUUID());
+    gInventory.notifyObservers();
+}
+
+std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id)
+{
+    if (model)
+    {
+        const LLInventoryItem *item = model->getItem(item_id);
+        if(item)
+        {
+            std::string desc = item->getDescription();
+            LLStringUtil::toUpper(desc);
+            return desc;
+        }
+    }
+    return LLStringUtil::null;
+}
+
+std::string get_searchable_creator_name(LLInventoryModel* model, const LLUUID& item_id)
+{
+    if (model)
+    {
+        const LLInventoryItem *item = model->getItem(item_id);
+        if(item)
+        {
+            LLAvatarName av_name;
+            if (LLAvatarNameCache::get(item->getCreatorUUID(), &av_name))
+            {
+                std::string username = av_name.getUserName();
+                LLStringUtil::toUpper(username);
+                return username;
+            }
+        }
+    }
+    return LLStringUtil::null;
+}
+
+std::string get_searchable_UUID(LLInventoryModel* model, const LLUUID& item_id)
+{
+    if (model)
+    {
+        const LLViewerInventoryItem *item = model->getItem(item_id);
+        if(item && (item->getIsFullPerm() || gAgent.isGodlikeWithoutAdminMenuFakery()))
+        {
+            std::string uuid = item->getAssetUUID().asString();
+            LLStringUtil::toUpper(uuid);
+            return uuid;
+        }
+    }
+    return LLStringUtil::null;
+}
+
+bool can_share_item(const LLUUID& item_id)
+{
+    bool can_share = false;
+
+    if (gInventory.isObjectDescendentOf(item_id, gInventory.getRootFolderID()))
+    {
+            const LLViewerInventoryItem *item = gInventory.getItem(item_id);
+            if (item)
+            {
+                if (LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item))
+                {
+                    can_share = LLGiveInventory::isInventoryGiveAcceptable(item);
+                }
+            }
+            else
+            {
+                can_share = (gInventory.getCategory(item_id) != NULL);
+            }
+
+            const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+            if ((item_id == trash_id) || gInventory.isObjectDescendentOf(item_id, trash_id))
+            {
+                can_share = false;
+            }
+    }
+
+    return can_share;
+}
+///----------------------------------------------------------------------------
+/// LLMarketplaceValidator implementations
+///----------------------------------------------------------------------------
+
+
+LLMarketplaceValidator::LLMarketplaceValidator()
+    : mPendingCallbacks(0)
+    , mValidationInProgress(false)
+{
+}
+
+LLMarketplaceValidator::~LLMarketplaceValidator()
+{
+}
+
+void LLMarketplaceValidator::validateMarketplaceListings(
+    const LLUUID &category_id,
+    LLMarketplaceValidator::validation_done_callback_t cb_done,
+    LLMarketplaceValidator::validation_msg_callback_t cb_msg,
+    bool fix_hierarchy,
+    S32 depth)
+{
+
+    mValidationQueue.emplace(category_id, cb_done, cb_msg, fix_hierarchy, depth);
+    if (!mValidationInProgress)
+    {
+        start();
+    }
+}
+
+void LLMarketplaceValidator::start()
+{
+    if (mValidationQueue.empty())
+    {
+        mValidationInProgress = false;
+        return;
+    }
+    mValidationInProgress = true;
+
+    const ValidationRequest &first = mValidationQueue.front();
+    LLViewerInventoryCategory* cat = gInventory.getCategory(first.mCategoryId);
+    if (!cat)
+    {
+        LL_WARNS() << "Tried to validate a folder that doesn't exist" << LL_ENDL;
+        if (first.mCbDone)
+        {
+            first.mCbDone(false);
+        }
+        mValidationQueue.pop();
+        start();
+        return;
+    }
+
+    validation_result_callback_t result_callback = [](S32 pending, bool result)
+    {
+        LLMarketplaceValidator* validator = LLMarketplaceValidator::getInstance();
+        validator->mPendingCallbacks--; // we just got a callback
+        validator->mPendingCallbacks += pending;
+        validator->mPendingResult &= result;
+        if (validator->mPendingCallbacks <= 0)
+        {
+            llassert(validator->mPendingCallbacks == 0); // shouldn't be below 0
+            const ValidationRequest &first = validator->mValidationQueue.front();
+            if (first.mCbDone)
+            {
+                first.mCbDone(validator->mPendingResult);
+            }
+            validator->mValidationQueue.pop(); // done;
+            validator->start();
+        }
+    };
+
+    mPendingResult = true;
+    mPendingCallbacks = 1; // do '1' in case something decides to callback immediately
+
+    S32 pending_calbacks = 0;
+    bool result = true;
+    validate_marketplacelistings(
+        cat,
+        result_callback,
+        first.mCbMsg,
+        first.mFixHierarchy,
+        first.mDepth,
+        true,
+        pending_calbacks,
+        result);
+
+    result_callback(pending_calbacks, result);
+}
+
+LLMarketplaceValidator::ValidationRequest::ValidationRequest(
+    LLUUID category_id,
+    validation_done_callback_t cb_done,
+    validation_msg_callback_t cb_msg,
+    bool fix_hierarchy,
+    S32 depth)
+: mCategoryId(category_id)
+, mCbDone(cb_done)
+, mCbMsg(cb_msg)
+, mFixHierarchy(fix_hierarchy)
+, mDepth(depth)
+{}
+
 ///----------------------------------------------------------------------------
 /// LLInventoryCollectFunctor implementations
 ///----------------------------------------------------------------------------
@@ -2252,6 +2737,19 @@ bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat,
 	}
 }
 
+bool LLFindBrokenLinks::operator()(LLInventoryCategory* cat,
+    LLInventoryItem* item)
+{
+    // only for broken links getType will be a link
+    // otherwise it's supposed to have the type of an item
+    // it is linked too
+    if (item && LLAssetType::lookupIsLinkType(item->getType()))
+    {
+        return TRUE;
+    }
+    return FALSE;
+}
+
 bool LLFindWearables::operator()(LLInventoryCategory* cat,
 								 LLInventoryItem* item)
 {
@@ -2317,6 +2815,11 @@ void LLFindWearablesOfType::setType(LLWearableType::EType type)
 	mWearableType = type;
 }
 
+bool LLIsTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+    return item && (item->getType() == LLAssetType::AT_TEXTURE);
+}
+
 bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 {
 	if (item)
@@ -2584,8 +3087,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
     
 	if ("delete" == action)
 	{
-		static bool sDisplayedAtSession = false;
-		const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+		const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
 		bool marketplacelistings_item = false;
 		LLAllDescendentsPassedFilter f;
 		for (std::set<LLFolderViewItem*>::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it)
@@ -2608,10 +3110,10 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
 		}
 		else
 		{
-			if (!sDisplayedAtSession) // ask for the confirmation at least once per session
+			if (!sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session
 			{
 				LLNotifications::instance().setIgnored("DeleteItems", false);
-				sDisplayedAtSession = true;
+				sDeleteConfirmationDisplayed = true;
 			}
 
 			LLSD args;
@@ -2663,7 +3165,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
 
 
 	LLMultiPreview* multi_previewp = NULL;
-	LLMultiProperties* multi_propertiesp = NULL;
+	LLMultiItemProperties* multi_itempropertiesp = nullptr;
 
 	if (("task_open" == action  || "open" == action) && selected_items.size() > 1)
 	{
@@ -2695,13 +3197,11 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
 		}
 
 	}
-	else if ( ("task_properties" == action || "properties" == action) && (selected_items.size() > 1) && 
-	          (gSavedSettings.getBOOL("ShowPropertiesFloaters")) )
+	else if (("task_properties" == action || "properties" == action) && selected_items.size() > 1)
 	{
-		multi_propertiesp = new LLMultiProperties();
-		gFloaterView->addChild(multi_propertiesp);
-
-		LLFloater::setFloaterHost(multi_propertiesp);
+		multi_itempropertiesp = new LLMultiItemProperties("item_properties");
+		gFloaterView->addChild(multi_itempropertiesp);
+		LLFloater::setFloaterHost(multi_itempropertiesp);
 	}
 
 	std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs();
@@ -2711,7 +3211,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
     if (action == "wear" || action == "wear_add")
     {
         const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
-        const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+        const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
         std::copy_if(selected_uuid_set.begin(),
             selected_uuid_set.end(),
             std::back_inserter(ids),
@@ -2826,36 +3326,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
     {
         if (ids.size() == 1)
         {
-            LLInventoryCategory* inv_cat = gInventory.getCategory(*ids.begin());
-            if (!inv_cat || LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
-            {
-                return;
-            }
-            const LLUUID &new_cat_uuid = inv_cat->getParentUUID();
-            LLInventoryModel::cat_array_t* cat_array;
-            LLInventoryModel::item_array_t* item_array;
-            gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cat_array, item_array);
-            LLInventoryModel::cat_array_t cats = *cat_array;
-            LLInventoryModel::item_array_t items = *item_array;
-
-            for (LLInventoryModel::cat_array_t::const_iterator cat_iter = cats.begin(); cat_iter != cats.end(); ++cat_iter)
-            {
-                LLViewerInventoryCategory* cat = *cat_iter;
-                if (cat)
-                {
-                    gInventory.changeCategoryParent(cat, new_cat_uuid, false);
-                }
-            }
-            for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter)
-            {
-                LLViewerInventoryItem* item = *item_iter;
-                if(item)
-                {
-                    gInventory.changeItemParent(item, new_cat_uuid, false);
-                }
-            }
-            gInventory.removeCategory(inv_cat->getUUID());
-            gInventory.notifyObservers();
+            ungroup_folder_items(*ids.begin());
         }
     }
     else
@@ -2869,6 +3340,14 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
             if(!bridge) continue;
             bridge->performAction(model, action);
         }
+        if(root->isSingleFolderMode() && selected_items.empty())
+        {
+            LLInvFVBridge* bridge = (LLInvFVBridge*)root->getViewModelItem();
+            if(bridge)
+            {
+                bridge->performAction(model, action);
+            }
+        }
     }
 
     // Update the marketplace listings that have been affected by the operation
@@ -2879,9 +3358,9 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
 	{
 		multi_previewp->openFloater(LLSD());
 	}
-	else if (multi_propertiesp)
+	else if (multi_itempropertiesp)
 	{
-		multi_propertiesp->openFloater(LLSD());
+		multi_itempropertiesp->openFloater(LLSD());
 	}
 }
 
@@ -2969,7 +3448,7 @@ void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root)
     // target listing *and* the original listing. So we need to keep track of both.
     // Note: do not however put the marketplace listings root itself in this list or the whole marketplace data will be rebuilt.
     sMarketplaceFolders.clear();
-    const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+    const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
     if (marketplacelistings_id.isNull())
     {
     	return;
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 1650b636739f097ab7375f6578c5ae6ed8a0416a..a818d981c0c57d088f689d0e87b2c9495165324f 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -85,6 +85,7 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s
 //void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name);
 
 void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id = LLUUID::null, bool move_no_copy_items = false);
+void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id, bool move_no_copy_items, inventory_func_type callback);
 
 void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& root_copy_id, bool move_no_copy_items);
 
@@ -101,13 +102,11 @@ std::string make_info(const LLInventoryObject* object);
 // Generates a string containing the path name and id of the object specified by id.
 std::string make_inventory_info(const LLUUID& id);
 
-typedef boost::function<void(std::string& validation_message, S32 depth, LLError::ELevel log_level)> validation_callback_t;
-
 bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryItem* inv_item, std::string& tooltip_msg, S32 bundle_size = 1, bool from_paste = false);
 bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryCategory* inv_cat, std::string& tooltip_msg, S32 bundle_size = 1, bool check_items = true, bool from_paste = false);
 bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_folder, bool copy = false);
 bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, bool copy = false, bool move_no_copy_items = false);
-bool validate_marketplacelistings(LLInventoryCategory* inv_cat, validation_callback_t cb = NULL, bool fix_hierarchy = true, S32 depth = -1, bool notify_observers = true);
+
 S32  depth_nesting_in_marketplace(LLUUID cur_uuid);
 LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth);
 S32 compute_stock_count(LLUUID cat_uuid, bool force_count = false);
@@ -118,10 +117,65 @@ void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected
 bool is_only_cats_selected(const uuid_vec_t& selected_uuids);
 bool is_only_items_selected(const uuid_vec_t& selected_uuids);
 
+bool can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit);
+bool can_move_to_landmarks(LLInventoryItem* inv_item);
+bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit);
+std::string get_localized_folder_name(LLUUID cat_uuid);
+void new_folder_window(const LLUUID& folder_id);
+void ungroup_folder_items(const LLUUID& folder_id);
+std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id);
+std::string get_searchable_creator_name(LLInventoryModel* model, const LLUUID& item_id);
+std::string get_searchable_UUID(LLInventoryModel* model, const LLUUID& item_id);
+bool can_share_item(const LLUUID& item_id);
+
 /**                    Miscellaneous global functions
  **                                                                            **
  *******************************************************************************/
 
+class LLMarketplaceValidator: public LLSingleton<LLMarketplaceValidator>
+{
+    LLSINGLETON(LLMarketplaceValidator);
+    ~LLMarketplaceValidator();
+    LOG_CLASS(LLMarketplaceValidator);
+public:
+
+    typedef boost::function<void(std::string& validation_message, S32 depth, LLError::ELevel log_level)> validation_msg_callback_t;
+    typedef boost::function<void(bool result)> validation_done_callback_t;
+
+    void validateMarketplaceListings(
+        const LLUUID &category_id,
+        validation_done_callback_t cb_done = NULL,
+        validation_msg_callback_t cb_msg = NULL,
+        bool fix_hierarchy = true,
+        S32 depth = -1);
+
+private:
+    void start();
+
+    class ValidationRequest
+    {
+    public:
+        ValidationRequest(
+            LLUUID category_id,
+            validation_done_callback_t cb_done,
+            validation_msg_callback_t cb_msg,
+            bool fix_hierarchy,
+            S32 depth);
+        LLUUID mCategoryId;
+        validation_done_callback_t mCbDone;
+        validation_msg_callback_t  mCbMsg;
+        bool mFixHierarchy;
+        S32 mDepth;
+    };
+
+    bool mValidationInProgress;
+    S32 mPendingCallbacks;
+    bool mPendingResult;
+    // todo: might be a good idea to memorize requests by id and
+    // filter out ones that got multiple validation requests
+    std::queue<ValidationRequest> mValidationQueue;
+};
+
 /********************************************************************************
  **                                                                            **
  **                    INVENTORY COLLECTOR FUNCTIONS
@@ -337,6 +391,20 @@ class LLFindCOFValidItems : public LLInventoryCollectFunctor
 	
 };
 
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLFindBrokenLinks
+//
+// Collects broken links
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLFindBrokenLinks : public LLInventoryCollectFunctor
+{
+public:
+    LLFindBrokenLinks() {}
+    virtual ~LLFindBrokenLinks() {}
+    virtual bool operator()(LLInventoryCategory* cat,
+        LLInventoryItem* item);
+};
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLFindByMask
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -435,6 +503,15 @@ class LLFindWearablesOfType : public LLInventoryCollectFunctor
 	LLWearableType::EType mWearableType;
 };
 
+class LLIsTextureType : public LLInventoryCollectFunctor
+{
+public:
+    LLIsTextureType() {}
+    virtual ~LLIsTextureType() {}
+    virtual bool operator()(LLInventoryCategory* cat,
+        LLInventoryItem* item);
+};
+
 /** Filter out wearables-links */
 class LLFindActualWearablesOfType : public LLFindWearablesOfType
 {
@@ -494,7 +571,7 @@ struct LLInventoryAction
 
     static void saveMultipleTextures(const std::vector<std::string>& filenames, std::set<LLFolderViewItem*> selected_items, LLInventoryModel* model);
 
-	static const int sConfirmOnDeleteItemsNumber;
+    static bool sDeleteConfirmationDisplayed;
 
 private:
 	static void buildMarketplaceFolders(LLFolderView* root);
diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b11b37e0077e7d109f8fadb48e76e08af948baa5
--- /dev/null
+++ b/indra/newview/llinventorygallery.cpp
@@ -0,0 +1,3824 @@
+/**
+ * @file llinventorygallery.cpp
+ * @brief LLInventoryGallery class implementation
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llinventorygallery.h"
+#include "llinventorygallerymenu.h"
+
+#include "llclipboard.h"
+#include "llcommonutils.h"
+#include "lliconctrl.h"
+#include "llinventorybridge.h"
+#include "llinventoryfunctions.h"
+#include "llinventoryicon.h"
+#include "llinventorymodel.h"
+#include "llinventorymodelbackgroundfetch.h"
+#include "llthumbnailctrl.h"
+#include "lltextbox.h"
+#include "llviewerfoldertype.h"
+
+#include "llagent.h"
+#include "llappearancemgr.h"
+#include "llenvironment.h"
+#include "llfriendcard.h"
+#include "llgesturemgr.h"
+#include "llmarketplacefunctions.h"
+#include "llnotificationsutil.h"
+#include "lloutfitobserver.h"
+#include "lltrans.h"
+#include "llviewerassettype.h"
+#include "llviewermessage.h"
+#include "llviewerobjectlist.h"
+#include "llvoavatarself.h"
+
+static LLPanelInjector<LLInventoryGallery> t_inventory_gallery("inventory_gallery");
+
+const S32 GALLERY_ITEMS_PER_ROW_MIN = 2;
+
+// Helper dnd functions
+BOOL dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, BOOL drop, std::string& tooltip_msg, BOOL is_link);
+BOOL dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm);
+void dropToMyOutfits(LLInventoryCategory* inv_cat);
+
+class LLGalleryPanel: public LLPanel
+{
+public:
+
+    BOOL canFocusChildren() const override
+    {
+        // Tell Tab to not focus children
+        return FALSE;
+    }
+
+protected:
+
+    LLGalleryPanel(const LLPanel::Params& params): LLPanel(params)
+    {
+    };
+
+    friend class LLUICtrlFactory;
+};
+
+//-----------------------------
+// LLInventoryGallery
+//-----------------------------
+
+LLInventoryGallery::LLInventoryGallery(const LLInventoryGallery::Params& p)
+    : LLPanel(),
+      mScrollPanel(NULL),
+      mGalleryPanel(NULL),
+      mLastRowPanel(NULL),
+      mGalleryCreated(false),
+      mRowCount(0),
+      mItemsAddedCount(0),
+      mRowPanelHeight(p.row_panel_height),
+      mVerticalGap(p.vertical_gap),
+      mHorizontalGap(p.horizontal_gap),
+      mItemWidth(p.item_width),
+      mItemHeight(p.item_height),
+      mItemHorizontalGap(p.item_horizontal_gap),
+      mItemsInRow(p.items_in_row),
+      mRowPanWidthFactor(p.row_panel_width_factor),
+      mGalleryWidthFactor(p.gallery_width_factor),
+      mIsInitialized(false),
+      mRootDirty(false),
+      mNeedsArrange(false),
+      mSearchType(LLInventoryFilter::SEARCHTYPE_NAME),
+      mSortOrder(LLInventoryFilter::SO_DATE)
+{
+    updateGalleryWidth();
+    mFilter = new LLInventoryFilter();
+    mCategoriesObserver = new LLInventoryCategoriesObserver();
+    mThumbnailsObserver = new LLThumbnailsObserver();
+    gInventory.addObserver(mThumbnailsObserver);
+
+    mGestureObserver = new LLGalleryGestureObserver(this);
+    LLGestureMgr::instance().addObserver(mGestureObserver);
+
+    mUsername = gAgentUsername;
+    LLStringUtil::toUpper(mUsername);
+}
+
+LLInventoryGallery::Params::Params()
+    : row_panel_height("row_panel_height", 180),
+      vertical_gap("vertical_gap", 10),
+      horizontal_gap("horizontal_gap", 10),
+      item_width("item_width", 150),
+      item_height("item_height", 175),
+      item_horizontal_gap("item_horizontal_gap", 16),
+      items_in_row("items_in_row", GALLERY_ITEMS_PER_ROW_MIN),
+      row_panel_width_factor("row_panel_width_factor", 166),
+      gallery_width_factor("gallery_width_factor", 163)
+{
+    addSynonym(row_panel_height, "row_height");
+}
+
+const LLInventoryGallery::Params& LLInventoryGallery::getDefaultParams()
+{
+    return LLUICtrlFactory::getDefaultParams<LLInventoryGallery>();
+}
+
+BOOL LLInventoryGallery::postBuild()
+{
+    mScrollPanel = getChild<LLScrollContainer>("gallery_scroll_panel");
+    LLPanel::Params params = LLPanel::getDefaultParams();
+    mGalleryPanel = LLUICtrlFactory::create<LLPanel>(params);
+    mMessageTextBox = getChild<LLTextBox>("empty_txt");
+    mInventoryGalleryMenu = new LLInventoryGalleryContextMenu(this);
+    mRootGalleryMenu = new LLInventoryGalleryContextMenu(this);
+    mRootGalleryMenu->setRootFolder(true);
+    return TRUE;
+}
+
+LLInventoryGallery::~LLInventoryGallery()
+{
+    if (gEditMenuHandler == this)
+    {
+        gEditMenuHandler = NULL;
+    }
+
+    delete mInventoryGalleryMenu;
+    delete mRootGalleryMenu;
+    delete mFilter;
+
+    gIdleCallbacks.deleteFunction(onIdle, (void*)this);
+
+    while (!mUnusedRowPanels.empty())
+    {
+        LLPanel* panelp = mUnusedRowPanels.back();
+        mUnusedRowPanels.pop_back();
+        panelp->die();
+    }
+    while (!mUnusedItemPanels.empty())
+    {
+        LLPanel* panelp = mUnusedItemPanels.back();
+        mUnusedItemPanels.pop_back();
+        panelp->die();
+    }
+    while (!mHiddenItems.empty())
+    {
+        LLPanel* panelp = mHiddenItems.back();
+        mHiddenItems.pop_back();
+        panelp->die();
+    }
+    
+
+    if (gInventory.containsObserver(mCategoriesObserver))
+    {
+        gInventory.removeObserver(mCategoriesObserver);
+    }
+    delete mCategoriesObserver;
+
+    if (gInventory.containsObserver(mThumbnailsObserver))
+    {
+        gInventory.removeObserver(mThumbnailsObserver);
+    }
+    delete mThumbnailsObserver;
+    
+    LLGestureMgr::instance().removeObserver(mGestureObserver);
+    delete mGestureObserver;
+}
+
+void LLInventoryGallery::setRootFolder(const LLUUID cat_id)
+{
+    LLViewerInventoryCategory* category = gInventory.getCategory(cat_id);
+    if(!category || (mFolderID == cat_id))
+    {
+        return;
+    }
+    if(mFolderID.notNull())
+    {
+        mBackwardFolders.push_back(mFolderID);
+    }
+
+    gIdleCallbacks.deleteFunction(onIdle, (void*)this);
+
+    for (const LLUUID& id : mSelectedItemIDs)
+    {
+        if (mItemMap[id])
+        {
+            mItemMap[id]->setSelected(FALSE);
+        }
+    }
+
+    mFolderID = cat_id;
+    mItemsToSelect.clear();
+    mSelectedItemIDs.clear();
+    mItemBuildQuery.clear();
+    mNeedsArrange = false;
+    dirtyRootFolder();
+}
+
+void LLInventoryGallery::dirtyRootFolder()
+{
+    if (getVisible())
+    {
+        updateRootFolder();
+    }
+    else
+    {
+        mRootDirty = true;
+    }
+}
+
+void LLInventoryGallery::updateRootFolder()
+{
+    llassert(mFolderID.notNull());
+    if (mIsInitialized && mFolderID.notNull())
+    {
+        S32 count = mItemsAddedCount;
+        for (S32 i = count - 1; i >= 0; i--)
+        {
+            updateRemovedItem(mItems[i]->getUUID());
+        }
+        S32 hidden_count = mHiddenItems.size();
+        for (S32 i = hidden_count - 1; i >= 0; i--)
+        {
+            updateRemovedItem(mHiddenItems[i]->getUUID());
+        }
+        mItemBuildQuery.clear();
+        
+        if (gInventory.containsObserver(mCategoriesObserver))
+        {
+            gInventory.removeObserver(mCategoriesObserver);
+        }
+        delete mCategoriesObserver;
+
+        mCategoriesObserver = new LLInventoryCategoriesObserver();
+
+        if (gInventory.containsObserver(mThumbnailsObserver))
+        {
+            gInventory.removeObserver(mThumbnailsObserver);
+        }
+        delete mThumbnailsObserver;
+        mThumbnailsObserver = new LLThumbnailsObserver();
+        gInventory.addObserver(mThumbnailsObserver);
+    }
+    {
+        mRootChangedSignal();
+
+        gInventory.addObserver(mCategoriesObserver);
+        
+        // Start observing changes in selected category.
+        mCategoriesObserver->addCategory(mFolderID,
+            boost::bind(&LLInventoryGallery::refreshList, this, mFolderID));
+
+        LLViewerInventoryCategory* category = gInventory.getCategory(mFolderID);
+        //If not all items are fetched now
+        // the observer will refresh the list as soon as the new items
+        // arrive.
+        category->fetch();
+        
+        //refreshList(cat_id);
+        LLInventoryModel::cat_array_t* cat_array;
+        LLInventoryModel::item_array_t* item_array;
+
+        gInventory.getDirectDescendentsOf(mFolderID, cat_array, item_array);
+
+        // Creating a vector of newly collected sub-categories UUIDs.
+        for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array->begin();
+            iter != cat_array->end();
+            iter++)
+        {
+            mItemBuildQuery.insert((*iter)->getUUID());
+        }
+        
+        for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin();
+            iter != item_array->end();
+            iter++)
+        {
+            mItemBuildQuery.insert((*iter)->getUUID());
+        }
+        mIsInitialized = true;
+        mRootDirty = false;
+
+        if (mScrollPanel)
+        {
+            mScrollPanel->goToTop();
+        }
+    }
+
+    LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLInventoryGallery::onCOFChanged, this));
+
+    if (!mGalleryCreated)
+    {
+        initGallery();
+    }
+
+    if (!mItemBuildQuery.empty())
+    {
+        gIdleCallbacks.addFunction(onIdle, (void*)this);
+    }
+}
+
+void LLInventoryGallery::initGallery()
+{
+    if (!mGalleryCreated)
+    {
+        uuid_vec_t cats;
+        getCurrentCategories(cats);
+        int n = cats.size();
+        buildGalleryPanel(n);
+        mScrollPanel->addChild(mGalleryPanel);
+        for (int i = 0; i < n; i++)
+        {
+            addToGallery(mItemMap[cats[i]]);
+        }
+        reArrangeRows();
+        mGalleryCreated = true;
+    }
+}
+
+void LLInventoryGallery::draw()
+{
+    LLPanel::draw();
+    if (mGalleryCreated)
+    {
+        if(!updateRowsIfNeeded())
+        {
+            handleModifiedFilter();
+        }
+    }
+}
+
+void LLInventoryGallery::onVisibilityChange(BOOL new_visibility)
+{
+    if (new_visibility)
+    {
+        if (mRootDirty)
+        {
+            updateRootFolder();
+        }
+        else if (mNeedsArrange)
+        {
+            gIdleCallbacks.addFunction(onIdle, (void*)this);
+        }
+    }
+    LLPanel::onVisibilityChange(new_visibility);
+}
+
+bool LLInventoryGallery::updateRowsIfNeeded()
+{
+    S32 scroll_content_width = mScrollPanel ? mScrollPanel->getVisibleContentRect().getWidth() : getRect().getWidth();
+    if(((scroll_content_width - mRowPanelWidth) > mItemWidth)
+       && mRowCount > 1)
+    {
+        reArrangeRows(1);
+        return true;
+    }
+    else if((mRowPanelWidth > (scroll_content_width + mItemHorizontalGap))
+            && mItemsInRow > GALLERY_ITEMS_PER_ROW_MIN)
+    {
+        reArrangeRows(-1);
+        return true;
+    }
+    return false;
+}
+
+bool compareGalleryItem(LLInventoryGalleryItem* item1, LLInventoryGalleryItem* item2, bool sort_by_date, bool sort_folders_by_name)
+{
+    if (item1->getSortGroup() != item2->getSortGroup())
+    {
+        return (item1->getSortGroup() < item2->getSortGroup());
+    }
+
+    if(sort_folders_by_name && (item1->getSortGroup() != LLInventoryGalleryItem::SG_ITEM))
+    {
+        std::string name1 = item1->getItemName();
+        std::string name2 = item2->getItemName();
+
+        return (LLStringUtil::compareDict(name1, name2) < 0);
+    }
+
+    if(((item1->isDefaultImage() && item2->isDefaultImage()) || (!item1->isDefaultImage() && !item2->isDefaultImage())))
+    {
+        if(sort_by_date)
+        {
+            return item1->getCreationDate() > item2->getCreationDate();
+        }
+        else
+        {
+            std::string name1 = item1->getItemName();
+            std::string name2 = item2->getItemName();
+
+            return (LLStringUtil::compareDict(name1, name2) < 0);
+        }
+    }
+    else
+    {
+        return item2->isDefaultImage();
+    }
+}
+
+void LLInventoryGallery::reArrangeRows(S32 row_diff)
+{
+    std::vector<LLInventoryGalleryItem*> buf_items = mItems;
+    for (std::vector<LLInventoryGalleryItem*>::const_reverse_iterator it = buf_items.rbegin(); it != buf_items.rend(); ++it)
+    {
+        removeFromGalleryLast(*it, false);
+    }
+    for (std::vector<LLInventoryGalleryItem*>::const_reverse_iterator it = mHiddenItems.rbegin(); it != mHiddenItems.rend(); ++it)
+    {
+        buf_items.push_back(*it);
+    }
+    mHiddenItems.clear();
+    
+    mItemsInRow+= row_diff;
+    updateGalleryWidth();
+
+    bool sort_by_date = (mSortOrder & LLInventoryFilter::SO_DATE);
+    bool sort_folders_by_name = (mSortOrder & LLInventoryFilter::SO_FOLDERS_BY_NAME);
+    std::sort(buf_items.begin(), buf_items.end(), [sort_by_date, sort_folders_by_name](LLInventoryGalleryItem* item1, LLInventoryGalleryItem* item2)
+    {
+        return compareGalleryItem(item1, item2, sort_by_date, sort_folders_by_name);
+    });
+    
+    for (std::vector<LLInventoryGalleryItem*>::const_iterator it = buf_items.begin(); it != buf_items.end(); ++it)
+    {
+        (*it)->setHidden(false);
+        applyFilter(*it, mFilterSubString);
+        addToGallery(*it);
+    }
+    mFilter->clearModified();
+    updateMessageVisibility();
+}
+
+void LLInventoryGallery::updateGalleryWidth()
+{
+    mRowPanelWidth = mRowPanWidthFactor * mItemsInRow - mItemHorizontalGap;
+    mGalleryWidth = mGalleryWidthFactor * mItemsInRow - mItemHorizontalGap;
+}
+
+LLPanel* LLInventoryGallery::addLastRow()
+{
+    mRowCount++;
+    int row = 0;
+    int vgap = mVerticalGap * row;
+    LLPanel* result = buildRowPanel(0, row * mRowPanelHeight + vgap);
+    mGalleryPanel->addChild(result);
+    return result;
+}
+
+void LLInventoryGallery::moveRowUp(int row)
+{
+    moveRow(row, mRowCount - 1 - row + 1);
+}
+
+void LLInventoryGallery::moveRowDown(int row)
+{
+    moveRow(row, mRowCount - 1 - row - 1);
+}
+
+void LLInventoryGallery::moveRow(int row, int pos)
+{
+    int vgap = mVerticalGap * pos;
+    moveRowPanel(mRowPanels[row], 0, pos * mRowPanelHeight + vgap);
+}
+
+void LLInventoryGallery::removeLastRow()
+{
+    mRowCount--;
+    mGalleryPanel->removeChild(mLastRowPanel);
+    mUnusedRowPanels.push_back(mLastRowPanel);
+    mRowPanels.pop_back();
+    if (mRowPanels.size() > 0)
+    {
+        // Just removed last row
+        mLastRowPanel = mRowPanels.back();
+    }
+    else
+    {
+        mLastRowPanel = NULL;
+    }
+}
+
+LLPanel* LLInventoryGallery::addToRow(LLPanel* row_stack, LLInventoryGalleryItem* item, int pos, int hgap)
+{
+    LLPanel* lpanel = buildItemPanel(pos * mItemWidth + hgap);
+    lpanel->addChild(item);
+    row_stack->addChild(lpanel);
+    mItemPanels.push_back(lpanel);
+    return lpanel;
+}
+
+void LLInventoryGallery::addToGallery(LLInventoryGalleryItem* item)
+{
+    if(item->isHidden())
+    {
+        mHiddenItems.push_back(item);
+        return;
+    }
+    mItemIndexMap[item] = mItemsAddedCount;
+    mIndexToItemMap[mItemsAddedCount] = item;
+    mItemsAddedCount++;
+    int n = mItemsAddedCount;
+    int row_count = (n % mItemsInRow) == 0 ? n / mItemsInRow : n / mItemsInRow + 1;
+    int n_prev = n - 1;
+    int row_count_prev = (n_prev % mItemsInRow) == 0 ? n_prev / mItemsInRow : n_prev / mItemsInRow + 1;
+
+    bool add_row = row_count != row_count_prev;
+    int pos = 0;
+    if (add_row)
+    {
+        for (int i = 0; i < row_count_prev; i++)
+        {
+            moveRowUp(i);
+        }
+        mLastRowPanel = addLastRow();
+        mRowPanels.push_back(mLastRowPanel);
+    }
+    pos = (n - 1) % mItemsInRow;
+    mItems.push_back(item);
+    addToRow(mLastRowPanel, item, pos, mHorizontalGap * pos);
+    reshapeGalleryPanel(row_count);
+}
+
+
+void LLInventoryGallery::removeFromGalleryLast(LLInventoryGalleryItem* item, bool needs_reshape)
+{
+    if(item->isHidden())
+    {
+        mHiddenItems.pop_back();
+        // Note: item still exists!!!
+        return;
+    }
+    int n_prev = mItemsAddedCount;
+    int n = mItemsAddedCount - 1;
+    int row_count = (n % mItemsInRow) == 0 ? n / mItemsInRow : n / mItemsInRow + 1;
+    int row_count_prev = (n_prev % mItemsInRow) == 0 ? n_prev / mItemsInRow : n_prev / mItemsInRow + 1;
+    mItemsAddedCount--;
+    mIndexToItemMap.erase(mItemsAddedCount);
+
+    bool remove_row = row_count != row_count_prev;
+    removeFromLastRow(mItems[mItemsAddedCount]);
+    mItems.pop_back();
+    if (remove_row)
+    {
+        for (int i = 0; i < row_count_prev - 1; i++)
+        {
+            moveRowDown(i);
+        }
+        removeLastRow();
+    }
+    if (needs_reshape)
+    {
+        reshapeGalleryPanel(row_count);
+    }
+}
+
+
+void LLInventoryGallery::removeFromGalleryMiddle(LLInventoryGalleryItem* item)
+{
+    if(item->isHidden())
+    {
+        mHiddenItems.erase(std::remove(mHiddenItems.begin(), mHiddenItems.end(), item), mHiddenItems.end());
+        // item still exists and needs to be deleted or used!!!
+        return;
+    }
+    int n = mItemIndexMap[item];
+    mItemIndexMap.erase(item);
+    mIndexToItemMap.erase(n);
+    std::vector<LLInventoryGalleryItem*> saved;
+    for (int i = mItemsAddedCount - 1; i > n; i--)
+    {
+        saved.push_back(mItems[i]);
+        removeFromGalleryLast(mItems[i]);
+    }
+    removeFromGalleryLast(mItems[n]);
+    int saved_count = saved.size();
+    for (int i = 0; i < saved_count; i++)
+    {
+        addToGallery(saved.back());
+        saved.pop_back();
+    }
+}
+
+void LLInventoryGallery::removeFromLastRow(LLInventoryGalleryItem* item)
+{
+    mItemPanels.back()->removeChild(item);
+    mLastRowPanel->removeChild(mItemPanels.back());
+    mUnusedItemPanels.push_back(mItemPanels.back());
+    mItemPanels.pop_back();
+}
+
+LLInventoryGalleryItem* LLInventoryGallery::buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, time_t creation_date, bool is_link, bool is_worn)
+{
+    LLInventoryGalleryItem::Params giparams;
+    giparams.visible = true;
+    giparams.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
+    giparams.rect(LLRect(0,mItemHeight, mItemWidth, 0));
+    LLInventoryGalleryItem* gitem = LLUICtrlFactory::create<LLInventoryGalleryItem>(giparams);
+    gitem->setItemName(name);
+    gitem->setUUID(item_id);
+    gitem->setGallery(this);
+    gitem->setType(type, inventory_type, flags, is_link);
+    gitem->setThumbnail(thumbnail_id);
+    gitem->setWorn(is_worn);
+    gitem->setCreatorName(get_searchable_creator_name(&gInventory, item_id));
+    gitem->setDescription(get_searchable_description(&gInventory, item_id));
+    gitem->setAssetIDStr(get_searchable_UUID(&gInventory, item_id));
+    gitem->setCreationDate(creation_date);
+    return gitem;
+}
+
+void LLInventoryGallery::buildGalleryPanel(int row_count)
+{
+    LLPanel::Params params;
+    params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
+    params.visible = true;
+    params.use_bounding_rect = false;
+    mGalleryPanel = LLUICtrlFactory::create<LLGalleryPanel>(params);
+    reshapeGalleryPanel(row_count);
+}
+
+void LLInventoryGallery::reshapeGalleryPanel(int row_count)
+{
+    int bottom = 0;
+    int left = 0;
+    int height = row_count * (mRowPanelHeight + mVerticalGap);
+    LLRect rect = LLRect(left, bottom + height, left + mGalleryWidth, bottom);
+    mGalleryPanel->setRect(rect);
+    mGalleryPanel->reshape(mGalleryWidth, height);
+}
+
+LLPanel* LLInventoryGallery::buildItemPanel(int left)
+{
+    int top = 0;
+    LLPanel* lpanel = NULL;
+    if(mUnusedItemPanels.empty())
+    {
+        LLPanel::Params lpparams;
+        lpparams.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
+        lpparams.visible = true;
+        lpparams.rect(LLRect(left, top + mItemHeight, left + mItemWidth + mItemHorizontalGap, top));
+        lpparams.use_bounding_rect = false;
+        lpparams.focus_root = false;
+        //lpparams.tab_stop = false;
+        lpanel = LLUICtrlFactory::create<LLPanel>(lpparams);
+    }
+    else
+    {
+        lpanel = mUnusedItemPanels.back();
+        mUnusedItemPanels.pop_back();
+
+        LLRect rect = LLRect(left, top + mItemHeight, left + mItemWidth + mItemHorizontalGap, top);
+        lpanel->setShape(rect, false);
+    }
+    return lpanel;
+}
+
+LLPanel* LLInventoryGallery::buildRowPanel(int left, int bottom)
+{
+    LLPanel* stack = NULL;
+    if(mUnusedRowPanels.empty())
+    {
+        LLPanel::Params sparams;
+        sparams.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
+        sparams.use_bounding_rect = false;
+        sparams.visible = true;
+        sparams.focus_root = false;
+        //sparams.tab_stop = false;
+        stack = LLUICtrlFactory::create<LLPanel>(sparams);
+    }
+    else
+    {
+        stack = mUnusedRowPanels.back();
+        mUnusedRowPanels.pop_back();
+    }
+    moveRowPanel(stack, left, bottom);
+    return stack;
+}
+
+void LLInventoryGallery::moveRowPanel(LLPanel* stack, int left, int bottom)
+{
+    LLRect rect = LLRect(left, bottom + mRowPanelHeight, left + mRowPanelWidth, bottom);
+    stack->setRect(rect);
+    stack->reshape(mRowPanelWidth, mRowPanelHeight);
+}
+
+void LLInventoryGallery::setFilterSubString(const std::string& string)
+{
+    mFilterSubString = string;
+    mFilter->setFilterSubString(string);
+    
+    //reArrangeRows();
+}
+
+bool LLInventoryGallery::applyFilter(LLInventoryGalleryItem* item, const std::string& filter_substring)
+{
+    if(item)
+    {
+        bool visible = checkAgainstFilters(item, filter_substring);
+        item->setHidden(!visible);
+        return visible;
+    }
+    return false;
+}
+
+bool LLInventoryGallery::checkAgainstFilters(LLInventoryGalleryItem* item, const std::string& filter_substring)
+{
+    if (!item) return false;
+
+    if (item->isFolder() && (mFilter->getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS))
+    {
+        return true;
+    }
+
+    if(item->isLink() && ((mFilter->getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_LINKS) == 0) && !filter_substring.empty())
+    {
+        return false;
+    }
+    
+    bool hidden = false;
+
+    if(mFilter->getFilterCreatorType() == LLInventoryFilter::FILTERCREATOR_SELF)
+    {
+        hidden = (item->getCreatorName() == mUsername) || item->isFolder();
+    }
+    else if(mFilter->getFilterCreatorType() == LLInventoryFilter::FILTERCREATOR_OTHERS)
+    {
+        hidden = (item->getCreatorName() != mUsername) || item->isFolder();
+    }
+    if(hidden)
+    {
+        return false;
+    }
+
+    if(!mFilter->checkAgainstFilterThumbnails(item->getUUID()))
+    {
+        return false;
+    }
+
+    if(!checkAgainstFilterType(item->getUUID()))
+    {
+        return false;
+    }
+
+    std::string desc;
+    switch(mSearchType)
+    {
+        case LLInventoryFilter::SEARCHTYPE_CREATOR:
+            desc = item->getCreatorName();
+            break;
+        case LLInventoryFilter::SEARCHTYPE_DESCRIPTION:
+            desc = item->getDescription();
+            break;
+        case LLInventoryFilter::SEARCHTYPE_UUID:
+            desc = item->getAssetIDStr();
+            break;
+        case LLInventoryFilter::SEARCHTYPE_NAME:
+        default:
+            desc = item->getItemName() + item->getItemNameSuffix();
+            break;
+    }
+    
+    LLStringUtil::toUpper(desc);
+
+    std::string cur_filter = filter_substring;
+    LLStringUtil::toUpper(cur_filter);
+
+    hidden = (std::string::npos == desc.find(cur_filter));
+    return !hidden;
+}
+
+void LLInventoryGallery::onIdle(void* userdata)
+{
+    LLInventoryGallery* self = (LLInventoryGallery*)userdata;
+
+    if (!self->mIsInitialized || !self->mGalleryCreated)
+    {
+        self->mNeedsArrange = false;
+        return;
+    }
+
+    bool visible = self->getVisible(); // In visible chain?
+    const F64 MAX_TIME_VISIBLE = 0.020f;
+    const F64 MAX_TIME_HIDDEN = 0.001f; // take it slow
+    const F64 max_time = visible ? MAX_TIME_VISIBLE : MAX_TIME_HIDDEN;
+    F64 curent_time = LLTimer::getTotalSeconds();
+    const F64 end_time = curent_time + max_time;
+
+    while (!self->mItemBuildQuery.empty() && end_time > curent_time)
+    {
+        uuid_set_t::iterator iter = self->mItemBuildQuery.begin();
+        LLUUID item_id = *iter;
+        self->mNeedsArrange |= self->updateAddedItem(item_id);
+        self->mItemBuildQuery.erase(iter);
+        curent_time = LLTimer::getTotalSeconds();
+    }
+
+    if (self->mNeedsArrange && visible)
+    {
+        self->mNeedsArrange = false;
+        self->reArrangeRows();
+        self->updateMessageVisibility();
+    }
+
+    if (!self->mItemsToSelect.empty() && !self->mNeedsArrange)
+    {
+        selection_deque selection_list(self->mItemsToSelect);
+        self->mItemsToSelect.clear();
+        for (LLUUID & item_to_select : selection_list)
+        {
+            self->addItemSelection(item_to_select, true);
+        }
+    }
+
+    if (self->mItemsToSelect.empty() && self->mItemBuildQuery.empty())
+    {
+        gIdleCallbacks.deleteFunction(onIdle, (void*)self);
+    }
+}
+
+void LLInventoryGallery::setSearchType(LLInventoryFilter::ESearchType type)
+{
+    if(mSearchType != type)
+    {
+        mSearchType = type;
+        if(!mFilterSubString.empty())
+        {
+            reArrangeRows();
+        }
+    }
+}
+
+void LLInventoryGallery::getCurrentCategories(uuid_vec_t& vcur)
+{
+    for (gallery_item_map_t::const_iterator iter = mItemMap.begin();
+        iter != mItemMap.end();
+        iter++)
+    {
+        if ((*iter).second != NULL)
+        {
+            vcur.push_back((*iter).first);
+        }
+    }
+}
+
+bool LLInventoryGallery::updateAddedItem(LLUUID item_id)
+{
+    LLInventoryObject* obj = gInventory.getObject(item_id);
+    if (!obj)
+    {
+        LL_WARNS("InventoryGallery") << "Failed to find item: " << item_id << LL_ENDL;
+        return false;
+    }
+
+    std::string name = obj->getName();
+    LLUUID thumbnail_id = obj->getThumbnailUUID();;
+    LLInventoryType::EType inventory_type(LLInventoryType::IT_CATEGORY);
+    U32 misc_flags = 0;
+    bool is_worn = false;
+    LLInventoryItem* inv_item = gInventory.getItem(item_id);
+    if (inv_item)
+    {
+        inventory_type = inv_item->getInventoryType();
+        misc_flags = inv_item->getFlags();
+        if (LLAssetType::AT_GESTURE == obj->getType())
+        {
+            is_worn = LLGestureMgr::instance().isGestureActive(item_id);
+        }
+        else
+        {
+            is_worn = LLAppearanceMgr::instance().isLinkedInCOF(item_id);
+        }
+    }
+    else if (LLAssetType::AT_CATEGORY == obj->getType())
+    {
+        name = get_localized_folder_name(item_id);
+        if(thumbnail_id.isNull())
+        {
+            thumbnail_id = getOutfitImageID(item_id);
+        }
+    }
+
+    bool res = false;
+
+    LLInventoryGalleryItem* item = buildGalleryItem(name, item_id, obj->getType(), thumbnail_id, inventory_type, misc_flags, obj->getCreationDate(), obj->getIsLinkType(), is_worn);
+    mItemMap.insert(LLInventoryGallery::gallery_item_map_t::value_type(item_id, item));
+    if (mGalleryCreated)
+    {
+        res = applyFilter(item, mFilterSubString);
+        addToGallery(item);
+    }
+
+    mThumbnailsObserver->addItem(item_id,
+        boost::bind(&LLInventoryGallery::updateItemThumbnail, this, item_id));
+    return res;
+}
+
+void LLInventoryGallery::updateRemovedItem(LLUUID item_id)
+{
+    gallery_item_map_t::iterator item_iter = mItemMap.find(item_id);
+    if (item_iter != mItemMap.end())
+    {
+        mThumbnailsObserver->removeItem(item_id);
+
+        LLInventoryGalleryItem* item = item_iter->second;
+
+        deselectItem(item_id);
+        mItemMap.erase(item_iter);
+        removeFromGalleryMiddle(item);
+
+        // kill removed item
+        if (item != NULL)
+        {
+            // Todo: instead of deleting, store somewhere to reuse later
+            item->die();
+        }
+    }
+
+    mItemBuildQuery.erase(item_id);
+}
+
+void LLInventoryGallery::updateChangedItemName(LLUUID item_id, std::string name)
+{
+    gallery_item_map_t::iterator iter = mItemMap.find(item_id);
+    if (iter != mItemMap.end())
+    {
+        LLInventoryGalleryItem* item = iter->second;
+        if (item)
+        {
+            item->setItemName(name);
+        }
+    }
+}
+
+void LLInventoryGallery::updateWornItem(LLUUID item_id, bool is_worn)
+{
+    gallery_item_map_t::iterator iter = mItemMap.find(item_id);
+    if (iter != mItemMap.end())
+    {
+        LLInventoryGalleryItem* item = iter->second;
+        if (item)
+        {
+            item->setWorn(is_worn);
+        }
+    }
+}
+
+void LLInventoryGallery::updateItemThumbnail(LLUUID item_id)
+{
+    LLInventoryObject* obj = gInventory.getObject(item_id);
+    if (!obj)
+    {
+        return;
+    }
+    LLUUID thumbnail_id = obj->getThumbnailUUID();
+
+    if ((LLAssetType::AT_CATEGORY == obj->getType()) && thumbnail_id.isNull())
+    {
+        thumbnail_id = getOutfitImageID(item_id);
+    }
+
+    if (mItemMap[item_id])
+    {
+        mItemMap[item_id]->setThumbnail(thumbnail_id);
+
+        bool passes_filter = checkAgainstFilters(mItemMap[item_id], mFilterSubString);
+        if((mItemMap[item_id]->isHidden() && passes_filter)
+           || (!mItemMap[item_id]->isHidden() && !passes_filter))
+        {
+            reArrangeRows();
+        }
+    }
+}
+
+BOOL LLInventoryGallery::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+    if (mSelectedItemIDs.size() > 0)
+    {
+        setFocus(true);
+    }
+    mLastInteractedUUID = LLUUID::null;
+
+    // Scroll is going to always return true
+    BOOL res = LLPanel::handleRightMouseDown(x, y, mask);
+
+    if (mLastInteractedUUID.isNull()) // no child were hit
+    {
+        clearSelection();
+        if (mInventoryGalleryMenu && mFolderID.notNull())
+        {
+            uuid_vec_t selected_uuids;
+            selected_uuids.push_back(mFolderID);
+            mRootGalleryMenu->show(this, selected_uuids, x, y);
+            return TRUE;
+        }
+    }
+    return res;
+}
+
+
+BOOL LLInventoryGallery::handleKeyHere(KEY key, MASK mask)
+{
+    BOOL handled = FALSE;
+    switch (key)
+    {
+        case KEY_RETURN:
+            // Open selected items if enter key hit on the inventory panel
+            if (mask == MASK_NONE && mInventoryGalleryMenu && mSelectedItemIDs.size() == 1)
+            {
+                selection_deque::iterator iter = mSelectedItemIDs.begin();
+                LLViewerInventoryCategory* category = gInventory.getCategory(*iter);
+                if (category)
+                {
+                    setRootFolder(*iter);
+                    handled = TRUE;
+                }
+                else
+                {
+                    LLViewerInventoryItem* item = gInventory.getItem(*iter);
+                    if (item)
+                    {
+                        LLInvFVBridgeAction::doAction(item->getType(), *iter, &gInventory);
+                    }
+                }
+            }
+            handled = TRUE;
+            break;
+        case KEY_DELETE:
+#if LL_DARWIN
+        case KEY_BACKSPACE:
+#endif
+            // Delete selected items if delete or backspace key hit on the inventory panel
+            // Note: on Mac laptop keyboards, backspace and delete are one and the same
+            if (canDeleteSelection())
+            {
+                deleteSelection();
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_F2:
+            mFilterSubString.clear();
+            if (mInventoryGalleryMenu && mSelectedItemIDs.size() == 1)
+            {
+                mInventoryGalleryMenu->rename(mSelectedItemIDs.front());
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_PAGE_UP:
+            mFilterSubString.clear();
+            if (mScrollPanel)
+            {
+                mScrollPanel->pageUp(30);
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_PAGE_DOWN:
+            mFilterSubString.clear();
+            if (mScrollPanel)
+            {
+                mScrollPanel->pageDown(30);
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_HOME:
+            mFilterSubString.clear();
+            if (mScrollPanel)
+            {
+                mScrollPanel->goToTop();
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_END:
+            mFilterSubString.clear();
+            if (mScrollPanel)
+            {
+                mScrollPanel->goToBottom();
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_LEFT:
+            moveLeft(mask);
+            handled = TRUE;
+            break;
+
+        case KEY_RIGHT:
+            moveRight(mask);
+            handled = TRUE;
+            break;
+
+        case KEY_UP:
+            moveUp(mask);
+            handled = TRUE;
+            break;
+
+        case KEY_DOWN:
+            moveDown(mask);
+            handled = TRUE;
+            break;
+
+        default:
+            break;
+    }
+
+    if (handled)
+    {
+        mInventoryGalleryMenu->hide();
+    }
+
+    return handled;
+}
+
+void LLInventoryGallery::moveUp(MASK mask)
+{
+    mFilterSubString.clear();
+
+    if (mInventoryGalleryMenu && mSelectedItemIDs.size() > 0 && mItemsAddedCount > 1)
+    {
+        LLInventoryGalleryItem* item = mItemMap[mLastInteractedUUID];
+        if (item)
+        {
+            if (mask == MASK_NONE || mask == MASK_CONTROL)
+            {
+                S32 n = mItemIndexMap[item];
+                n -= mItemsInRow;
+                if (n >= 0)
+                {
+                    item = mIndexToItemMap[n];
+                    LLUUID item_id = item->getUUID();
+                    if (mask == MASK_CONTROL)
+                    {
+                        addItemSelection(item_id, true);
+                    }
+                    else
+                    {
+                        changeItemSelection(item_id, true);
+                    }
+                    item->setFocus(TRUE);
+                    claimEditHandler();
+                }
+            }
+            else if (mask == MASK_SHIFT)
+            {
+                S32 n = mItemIndexMap[item];
+                S32 target  = llmax(0, n - mItemsInRow);
+                if (target != n)
+                {
+                    item = mIndexToItemMap[target];
+                    toggleSelectionRangeFromLast(item->getUUID());
+                    item->setFocus(TRUE);
+                    claimEditHandler();
+                }
+            }
+        }
+    }
+}
+
+void LLInventoryGallery::moveDown(MASK mask)
+{
+    mFilterSubString.clear();
+
+    if (mInventoryGalleryMenu && mSelectedItemIDs.size() > 0 && mItemsAddedCount > 1)
+    {
+        LLInventoryGalleryItem* item = mItemMap[mLastInteractedUUID];
+        if (item)
+        {
+            if (mask == MASK_NONE || mask == MASK_CONTROL)
+            {
+                S32 n = mItemIndexMap[item];
+                n += mItemsInRow;
+                if (n < mItemsAddedCount)
+                {
+                    item = mIndexToItemMap[n];
+                    LLUUID item_id = item->getUUID();
+                    if (mask == MASK_CONTROL)
+                    {
+                        addItemSelection(item_id, true);
+                    }
+                    else
+                    {
+                        changeItemSelection(item_id, true);
+                    }
+                    item->setFocus(TRUE);
+                    claimEditHandler();
+                }
+            }
+            else if (mask == MASK_SHIFT)
+            {
+                S32 n = mItemIndexMap[item];
+                S32 target = llmin(mItemsAddedCount - 1, n + mItemsInRow);
+                if (target != n)
+                {
+                    item = mIndexToItemMap[target];
+                    toggleSelectionRangeFromLast(item->getUUID());
+                    item->setFocus(TRUE);
+                    claimEditHandler();
+                }
+            }
+        }
+    }
+}
+
+void LLInventoryGallery::moveLeft(MASK mask)
+{
+    mFilterSubString.clear();
+
+    if (mInventoryGalleryMenu && mSelectedItemIDs.size() > 0 && mItemsAddedCount > 1)
+    {
+        LLInventoryGalleryItem* item = mItemMap[mLastInteractedUUID];
+        if (mask == MASK_SHIFT)
+        {
+            item = mItemMap[mLastInteractedUUID];
+        }
+        if (item)
+        {
+            // Might be better to get item from panel
+            S32 n = mItemIndexMap[item];
+            n--;
+            if (n < 0)
+            {
+                n = mItemsAddedCount - 1;
+            }
+            item = mIndexToItemMap[n];
+            LLUUID item_id = item->getUUID();
+            if (mask == MASK_CONTROL)
+            {
+                addItemSelection(item_id, true);
+            }
+            else if (mask == MASK_SHIFT)
+            {
+                if (item->isSelected())
+                {
+                    toggleItemSelection(mLastInteractedUUID, true);
+                }
+                else
+                {
+                    toggleItemSelection(item_id, true);
+                }
+                mLastInteractedUUID = item_id;
+            }
+            else
+            {
+                changeItemSelection(item_id, true);
+            }
+            item->setFocus(TRUE);
+            claimEditHandler();
+        }
+    }
+}
+
+void LLInventoryGallery::moveRight(MASK mask)
+{
+    mFilterSubString.clear();
+
+    if (mInventoryGalleryMenu && mSelectedItemIDs.size() > 0 && mItemsAddedCount > 1)
+    {
+        LLInventoryGalleryItem* item = mItemMap[mLastInteractedUUID];
+        if (item)
+        {
+            S32 n = mItemIndexMap[item];
+            n++;
+            if (n == mItemsAddedCount)
+            {
+                n = 0;
+            }
+            item = mIndexToItemMap[n];
+            LLUUID item_id = item->getUUID();
+            if (mask == MASK_CONTROL)
+            {
+                addItemSelection(item_id, true);
+            }
+            else if (mask == MASK_SHIFT)
+            {
+                if (item->isSelected())
+                {
+                    toggleItemSelection(mLastInteractedUUID, true);
+                }
+                else
+                {
+                    toggleItemSelection(item_id, true);
+                }
+                mLastInteractedUUID = item_id;
+            }
+            else
+            {
+                changeItemSelection(item_id, true);
+            }
+            item->setFocus(TRUE);
+            claimEditHandler();
+        }
+    }
+}
+
+void LLInventoryGallery::toggleSelectionRange(S32 start_idx, S32 end_idx)
+{
+    LLInventoryGalleryItem* item = NULL;
+    if (end_idx > start_idx)
+    {
+        for (S32 i = start_idx; i <= end_idx; i++)
+        {
+            item = mIndexToItemMap[i];
+            LLUUID item_id = item->getUUID();
+            toggleItemSelection(item_id, true);
+        }
+    }
+    else
+    {
+        for (S32 i = start_idx; i >= end_idx; i--)
+        {
+            item = mIndexToItemMap[i];
+            LLUUID item_id = item->getUUID();
+            toggleItemSelection(item_id, true);
+        }
+    }
+}
+
+void LLInventoryGallery::toggleSelectionRangeFromLast(const LLUUID target)
+{
+    if (mLastInteractedUUID == target)
+    {
+        return;
+    }
+    LLInventoryGalleryItem* last_item = mItemMap[mLastInteractedUUID];
+    LLInventoryGalleryItem* next_item = mItemMap[target];
+    if (last_item && next_item)
+    {
+        S32 last_idx = mItemIndexMap[last_item];
+        S32 next_idx = mItemIndexMap[next_item];
+        if (next_item->isSelected())
+        {
+            if (last_idx < next_idx)
+            {
+                toggleSelectionRange(last_idx, next_idx - 1);
+            }
+            else
+            {
+                toggleSelectionRange(last_idx, next_idx + 1);
+            }
+        }
+        else
+        {
+            if (last_idx < next_idx)
+            {
+                toggleSelectionRange(last_idx + 1, next_idx);
+            }
+            else
+            {
+                toggleSelectionRange(last_idx - 1, next_idx);
+            }
+        }
+    }
+    mLastInteractedUUID = next_item->getUUID();
+}
+
+void LLInventoryGallery::onFocusLost()
+{
+    // inventory no longer handles cut/copy/paste/delete
+    if (gEditMenuHandler == this)
+    {
+        gEditMenuHandler = NULL;
+    }
+
+    LLPanel::onFocusLost();
+
+    for (const LLUUID& id : mSelectedItemIDs)
+    {
+        if (mItemMap[id])
+        {
+            mItemMap[id]->setSelected(false);
+        }
+    }
+}
+
+void LLInventoryGallery::onFocusReceived()
+{
+    // inventory now handles cut/copy/paste/delete
+    gEditMenuHandler = this;
+
+    // Tab support, when tabbing into this view, select first item
+    if (mSelectedItemIDs.size() > 0)
+    {
+        LLInventoryGalleryItem* focus_item = NULL;
+        for (const LLUUID& id : mSelectedItemIDs)
+        {
+            if (mItemMap[id])
+            {
+                focus_item = mItemMap[id];
+                focus_item->setSelected(true);
+            }
+        }
+        if (focus_item)
+        {
+            focus_item->setFocus(TRUE);
+        }
+    }
+    else if (mIndexToItemMap.size() > 0 && mItemsToSelect.empty())
+    {
+        // choose any items from visible rect
+        S32 vert_offset = mScrollPanel->getDocPosVertical();
+        S32 panel_size = mVerticalGap + mRowPanelHeight;
+        S32 n = llclamp((S32)(vert_offset / panel_size) * mItemsInRow, 0, (S32)(mIndexToItemMap.size() - 1) );
+
+        LLInventoryGalleryItem* focus_item = mIndexToItemMap[n];
+        changeItemSelection(focus_item->getUUID(), true);
+        focus_item->setFocus(TRUE);
+    }
+
+    LLPanel::onFocusReceived();
+}
+
+void LLInventoryGallery::showContextMenu(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& item_id)
+{
+    if (mInventoryGalleryMenu && item_id.notNull())
+    {
+        if (std::find(mSelectedItemIDs.begin(), mSelectedItemIDs.end(), item_id) == mSelectedItemIDs.end())
+        {
+            changeItemSelection(item_id, false);
+        }
+        uuid_vec_t selected_uuids(mSelectedItemIDs.begin(), mSelectedItemIDs.end());
+        mInventoryGalleryMenu->show(ctrl, selected_uuids, x, y);
+    }
+}
+
+void LLInventoryGallery::changeItemSelection(const LLUUID& item_id, bool scroll_to_selection)
+{
+    for (const LLUUID& id : mSelectedItemIDs)
+    {
+        if (mItemMap[id])
+        {
+            mItemMap[id]->setSelected(FALSE);
+        }
+    }
+    mSelectedItemIDs.clear();
+    mItemsToSelect.clear();
+
+    if ((mItemMap.count(item_id) == 0) || mNeedsArrange)
+    {
+        mItemsToSelect.push_back(item_id);
+        return;
+    }
+    if (mSelectedItemIDs.size() == 1
+        && std::find(mSelectedItemIDs.begin(), mSelectedItemIDs.end(), item_id) != mSelectedItemIDs.end())
+    {
+        // Already selected
+        mLastInteractedUUID = item_id;
+        return;
+    }
+
+    if (mItemMap[item_id])
+    {
+        mItemMap[item_id]->setSelected(TRUE);
+    }
+    mSelectedItemIDs.push_back(item_id);
+    signalSelectionItemID(item_id);
+    mLastInteractedUUID = item_id;
+
+    if (scroll_to_selection)
+    {
+        scrollToShowItem(item_id);
+    }
+}
+
+void LLInventoryGallery::addItemSelection(const LLUUID& item_id, bool scroll_to_selection)
+{
+    if ((mItemMap.count(item_id) == 0) || mNeedsArrange)
+    {
+        mItemsToSelect.push_back(item_id);
+        return;
+    }
+    if (std::find(mSelectedItemIDs.begin(), mSelectedItemIDs.end(), item_id) != mSelectedItemIDs.end())
+    {
+        // Already selected
+        mLastInteractedUUID = item_id;
+        return;
+    }
+
+    if (mItemMap[item_id])
+    {
+        mItemMap[item_id]->setSelected(TRUE);
+    }
+    mSelectedItemIDs.push_back(item_id);
+    signalSelectionItemID(item_id);
+    mLastInteractedUUID = item_id;
+
+    if (scroll_to_selection)
+    {
+        scrollToShowItem(item_id);
+    }
+}
+
+bool LLInventoryGallery::toggleItemSelection(const LLUUID& item_id, bool scroll_to_selection)
+{
+    bool result = false;
+    if ((mItemMap.count(item_id) == 0) || mNeedsArrange)
+    {
+        mItemsToSelect.push_back(item_id);
+        return result;
+    }
+    selection_deque::iterator found = std::find(mSelectedItemIDs.begin(), mSelectedItemIDs.end(), item_id);
+    if (found != mSelectedItemIDs.end())
+    {
+        if (mItemMap[item_id])
+        {
+            mItemMap[item_id]->setSelected(FALSE);
+        }
+        mSelectedItemIDs.erase(found);
+        result = false;
+    }
+    else
+    {
+        if (mItemMap[item_id])
+        {
+            mItemMap[item_id]->setSelected(TRUE);
+        }
+        mSelectedItemIDs.push_back(item_id);
+        signalSelectionItemID(item_id);
+        result = true;
+    }
+    mLastInteractedUUID = item_id;
+
+    if (scroll_to_selection)
+    {
+        scrollToShowItem(item_id);
+    }
+    return result;
+}
+
+void LLInventoryGallery::scrollToShowItem(const LLUUID& item_id)
+{
+    LLInventoryGalleryItem* item = mItemMap[item_id];
+    if(item)
+    {
+        const LLRect visible_content_rect = mScrollPanel->getVisibleContentRect();
+
+        LLRect item_rect;
+        item->localRectToOtherView(item->getLocalRect(), &item_rect, mScrollPanel);
+        LLRect overlap_rect(item_rect);
+        overlap_rect.intersectWith(visible_content_rect);
+
+        //Scroll when the selected item is outside the visible area
+        if (overlap_rect.getHeight() + 5 < item->getRect().getHeight())
+        {
+            LLRect content_rect = mScrollPanel->getContentWindowRect();
+            LLRect constraint_rect;
+            constraint_rect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight());
+
+            LLRect item_doc_rect;
+            item->localRectToOtherView(item->getLocalRect(), &item_doc_rect, mGalleryPanel);
+
+            mScrollPanel->scrollToShowRect( item_doc_rect, constraint_rect );
+        }
+    }
+}
+
+LLInventoryGalleryItem* LLInventoryGallery::getFirstSelectedItem()
+{
+    if (mSelectedItemIDs.size() > 0)
+    {
+        selection_deque::iterator iter = mSelectedItemIDs.begin();
+        return mItemMap[*iter];
+    }
+    return NULL;
+}
+
+void LLInventoryGallery::copy()
+{
+    if (!getVisible() || !getEnabled())
+    {
+        return;
+    }
+
+    LLClipboard::instance().reset();
+
+    for (const LLUUID& id : mSelectedItemIDs)
+    {
+        LLClipboard::instance().addToClipboard(id);
+    }
+    mFilterSubString.clear();
+}
+
+BOOL LLInventoryGallery::canCopy() const
+{
+    if (!getVisible() || !getEnabled() || mSelectedItemIDs.empty())
+    {
+        return FALSE;
+    }
+
+    for (const LLUUID& id : mSelectedItemIDs)
+    {
+        if (!isItemCopyable(id))
+        {
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+void LLInventoryGallery::cut()
+{
+    if (!getVisible() || !getEnabled())
+    {
+        return;
+    }
+
+    // clear the inventory clipboard
+    LLClipboard::instance().reset();
+    LLClipboard::instance().setCutMode(true);
+    for (const LLUUID& id : mSelectedItemIDs)
+    {
+        // todo: fade out selected item
+        LLClipboard::instance().addToClipboard(id);
+    }
+
+    mFilterSubString.clear();
+}
+
+BOOL LLInventoryGallery::canCut() const
+{
+    if (!getVisible() || !getEnabled() || mSelectedItemIDs.empty())
+    {
+        return FALSE;
+    }
+
+    for (const LLUUID& id : mSelectedItemIDs)
+    {
+        LLViewerInventoryCategory* cat = gInventory.getCategory(id);
+        if (cat)
+        {
+            if (!get_is_category_removable(&gInventory, id))
+            {
+                return FALSE;
+            }
+        }
+        else if (!get_is_item_removable(&gInventory, id))
+        {
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+void LLInventoryGallery::paste()
+{
+    if (!LLClipboard::instance().hasContents())
+    {
+        return;
+    }
+
+    const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+    if (mSelectedItemIDs.size() == 1 && gInventory.isObjectDescendentOf(*mSelectedItemIDs.begin(), marketplacelistings_id))
+    {
+        return;
+    }
+
+    bool is_cut_mode = LLClipboard::instance().isCutMode();
+    std::vector<LLUUID> objects;
+    LLClipboard::instance().pasteFromClipboard(objects);
+
+    bool paste_into_root = mSelectedItemIDs.empty();
+    for (LLUUID& dest : mSelectedItemIDs)
+    {
+        LLInventoryObject* obj = gInventory.getObject(dest);
+        if (!obj || (obj->getType() != LLAssetType::AT_CATEGORY))
+        {
+            paste_into_root = true;
+            continue;
+        }
+
+        paste(dest, objects, is_cut_mode, marketplacelistings_id);
+        is_cut_mode = false;
+    }
+
+    if (paste_into_root)
+    {
+        for (const LLUUID& id : mSelectedItemIDs)
+        {
+            if (mItemMap[id])
+            {
+                mItemMap[id]->setSelected(FALSE);
+            }
+        }
+        mSelectedItemIDs.clear();
+
+        paste(mFolderID, objects, is_cut_mode, marketplacelistings_id);
+    }
+
+    LLClipboard::instance().setCutMode(false);
+}
+
+void LLInventoryGallery::paste(const LLUUID& dest,
+                               std::vector<LLUUID>& objects,
+                               bool is_cut_mode,
+                               const LLUUID& marketplacelistings_id)
+{
+    LLHandle<LLPanel> handle = getHandle();
+    std::function <void(const LLUUID)> on_copy_callback = NULL;
+    LLPointer<LLInventoryCallback> cb = NULL;
+    if (dest == mFolderID)
+    {
+        on_copy_callback = [handle](const LLUUID& inv_item)
+            {
+                LLInventoryGallery* panel = (LLInventoryGallery*)handle.get();
+                if (panel)
+                {
+                    // Scroll to pasted item and highlight it
+                    // Should it only highlight the last one?
+                    panel->addItemSelection(inv_item, true);
+                }
+            };
+        cb = new LLBoostFuncInventoryCallback(on_copy_callback);
+    }
+
+    for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter)
+    {
+        const LLUUID& item_id = (*iter);
+        if (gInventory.isObjectDescendentOf(item_id, marketplacelistings_id) && (LLMarketplaceData::instance().isInActiveFolder(item_id) ||
+                                                                                 LLMarketplaceData::instance().isListedAndActive(item_id)))
+        {
+            return;
+        }
+        LLViewerInventoryCategory* cat = gInventory.getCategory(item_id);
+        if (cat)
+        {
+            if (is_cut_mode)
+            {
+                gInventory.changeCategoryParent(cat, dest, false);
+                if (dest == mFolderID)
+                {
+                    // Don't select immediately, wait for item to arrive
+                    mItemsToSelect.push_back(item_id);
+                }
+            }
+            else
+            {
+                copy_inventory_category(&gInventory, cat, dest, LLUUID::null, false, on_copy_callback);
+            }
+        }
+        else
+        {
+            LLViewerInventoryItem* item = gInventory.getItem(item_id);
+            if (item)
+            {
+                if (is_cut_mode)
+                {
+                    gInventory.changeItemParent(item, dest, false);
+                    if (dest == mFolderID)
+                    {
+                        // Don't select immediately, wait for item to arrive
+                        mItemsToSelect.push_back(item_id);
+                    }
+                }
+                else
+                {
+                    if (item->getIsLinkType())
+                    {
+                        link_inventory_object(dest, item_id, cb);
+                    }
+                    else
+                    {
+                        copy_inventory_item(
+                            gAgent.getID(),
+                            item->getPermissions().getOwner(),
+                            item->getUUID(),
+                            dest,
+                            std::string(),
+                            cb);
+                    }
+                }
+            }
+        }
+    }
+
+    LLClipboard::instance().setCutMode(false);
+}
+
+BOOL LLInventoryGallery::canPaste() const
+{
+    // Return FALSE on degenerated cases: empty clipboard, no inventory, no agent
+    if (!LLClipboard::instance().hasContents())
+    {
+        return FALSE;
+    }
+
+    // In cut mode, whatever is on the clipboard is always pastable
+    if (LLClipboard::instance().isCutMode())
+    {
+        return TRUE;
+    }
+
+    // In normal mode, we need to check each element of the clipboard to know if we can paste or not
+    std::vector<LLUUID> objects;
+    LLClipboard::instance().pasteFromClipboard(objects);
+    S32 count = objects.size();
+    for (S32 i = 0; i < count; i++)
+    {
+        const LLUUID& item_id = objects.at(i);
+
+        // Each item must be copyable to be pastable
+        if (!isItemCopyable(item_id))
+        {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+void LLInventoryGallery::onDelete(const LLSD& notification, const LLSD& response, const selection_deque selected_ids)
+{
+    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+    if (option == 0)
+    {
+        for (const LLUUID& id : selected_ids)
+        {
+            LLInventoryObject* obj = gInventory.getObject(id);
+            if (!obj)
+            {
+                return;
+            }
+            if (obj->getType() == LLAssetType::AT_CATEGORY)
+            {
+                if (get_is_category_removable(&gInventory, id))
+                {
+                    gInventory.removeCategory(id);
+                }
+            }
+            else
+            {
+                if (get_is_item_removable(&gInventory, id))
+                {
+                    gInventory.removeItem(id);
+                }
+            }
+        }
+    }
+}
+
+void LLInventoryGallery::deleteSelection()
+{
+    if (!LLInventoryAction::sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session
+    {
+        LLNotifications::instance().setIgnored("DeleteItems", false);
+        LLInventoryAction::sDeleteConfirmationDisplayed = true;
+    }
+
+    LLSD args;
+    args["QUESTION"] = LLTrans::getString("DeleteItem");
+    LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryGallery::onDelete, _1, _2, mSelectedItemIDs));
+}
+
+bool LLInventoryGallery::canDeleteSelection()
+{
+    if (mSelectedItemIDs.empty())
+    {
+        return false;
+    }
+
+    const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+    if (mFolderID == trash_id || gInventory.isObjectDescendentOf(mFolderID, trash_id))
+    {
+        return false;
+    }
+
+    for (const LLUUID& id : mSelectedItemIDs)
+    {
+        LLViewerInventoryCategory* cat = gInventory.getCategory(id);
+        if (cat)
+        {
+            if (!get_is_category_removable(&gInventory, id))
+            {
+                return false;
+            }
+        }
+        else if (!get_is_item_removable(&gInventory, id))
+        {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void LLInventoryGallery::pasteAsLink()
+{
+    if (!LLClipboard::instance().hasContents())
+    {
+        return;
+    }
+
+    const LLUUID& current_outfit_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+    const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+    const LLUUID& my_outifts_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+    std::vector<LLUUID> objects;
+    LLClipboard::instance().pasteFromClipboard(objects);
+
+    bool paste_into_root = mSelectedItemIDs.empty();
+    for (LLUUID& dest : mSelectedItemIDs)
+    {
+        LLInventoryObject* obj = gInventory.getObject(dest);
+        if (!obj || obj->getType() != LLAssetType::AT_CATEGORY)
+        {
+            paste_into_root = true;
+            continue;
+        }
+
+        pasteAsLink(dest, objects, current_outfit_id, marketplacelistings_id, my_outifts_id);
+    }
+
+    if (paste_into_root)
+    {
+        for (const LLUUID& id : mSelectedItemIDs)
+        {
+            if (mItemMap[id])
+            {
+                mItemMap[id]->setSelected(FALSE);
+            }
+        }
+        mSelectedItemIDs.clear();
+
+        pasteAsLink(mFolderID, objects, current_outfit_id, marketplacelistings_id, my_outifts_id);
+    }
+
+    LLClipboard::instance().setCutMode(false);
+}
+
+void LLInventoryGallery::pasteAsLink(const LLUUID& dest,
+                                     std::vector<LLUUID>& objects,
+                                     const LLUUID& current_outfit_id,
+                                     const LLUUID& marketplacelistings_id,
+                                     const LLUUID& my_outifts_id)
+{
+    const BOOL move_is_into_current_outfit = (dest == current_outfit_id);
+    const BOOL move_is_into_my_outfits = (dest == my_outifts_id) || gInventory.isObjectDescendentOf(dest, my_outifts_id);
+    const BOOL move_is_into_marketplacelistings = gInventory.isObjectDescendentOf(dest, marketplacelistings_id);
+
+    if (move_is_into_marketplacelistings || move_is_into_current_outfit || move_is_into_my_outfits)
+    {
+        return;
+    }
+
+    LLPointer<LLInventoryCallback> cb = NULL;
+    if (dest == mFolderID)
+    {
+        LLHandle<LLPanel> handle = getHandle();
+        std::function <void(const LLUUID)> on_link_callback = [handle](const LLUUID& inv_item)
+            {
+                LLInventoryGallery* panel = (LLInventoryGallery*)handle.get();
+                if (panel)
+                {
+                    // Scroll to pasted item and highlight it
+                    // Should it only highlight the last one?
+                    panel->addItemSelection(inv_item, true);
+                }
+            };
+        cb = new LLBoostFuncInventoryCallback(on_link_callback);
+    }
+
+    for (std::vector<LLUUID>::const_iterator iter = objects.begin();
+         iter != objects.end();
+         ++iter)
+    {
+        const LLUUID& object_id = (*iter);
+        if (LLConstPointer<LLInventoryObject> link_obj = gInventory.getObject(object_id))
+        {
+            link_inventory_object(dest, link_obj, cb);
+        }
+    }
+}
+
+void LLInventoryGallery::claimEditHandler()
+{
+    gEditMenuHandler = this;
+}
+
+void LLInventoryGallery::resetEditHandler()
+{
+    if (gEditMenuHandler == this)
+    {
+        gEditMenuHandler = NULL;
+    }
+}
+
+bool LLInventoryGallery::isItemCopyable(const LLUUID & item_id)
+{
+    const LLInventoryCategory* cat = gInventory.getCategory(item_id);
+    if (cat)
+    {
+        // Folders are copyable if items in them are, recursively, copyable.
+        // Get the content of the folder
+        LLInventoryModel::cat_array_t* cat_array;
+        LLInventoryModel::item_array_t* item_array;
+        gInventory.getDirectDescendentsOf(item_id, cat_array, item_array);
+
+        // Check the items
+        LLInventoryModel::item_array_t item_array_copy = *item_array;
+        for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++)
+        {
+            LLInventoryItem* item = *iter;
+            if (!isItemCopyable(item->getUUID()))
+            {
+                return false;
+            }
+        }
+
+        // Check the folders
+        LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
+        for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
+        {
+            LLViewerInventoryCategory* category = *iter;
+            if (!isItemCopyable(category->getUUID()))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    LLViewerInventoryItem* item = gInventory.getItem(item_id);
+    if (item)
+    {
+        // Can't copy worn objects.
+        // Worn objects are tied to their inworld conterparts
+        // Copy of modified worn object will return object with obsolete asset and inventory
+        if (get_is_item_worn(item_id))
+        {
+            return false;
+        }
+
+        static LLCachedControl<bool> inventory_linking(gSavedSettings, "InventoryLinking", true);
+        return (item->getIsLinkType() && inventory_linking)
+            || item->getPermissions().allowCopyBy(gAgent.getID());
+    }
+
+    return false;
+}
+
+void LLInventoryGallery::updateMessageVisibility()
+{
+
+    mMessageTextBox->setVisible(mItems.empty());
+    if(mItems.empty())
+    {
+        mMessageTextBox->setText(hasDescendents(mFolderID) ? LLTrans::getString("InventorySingleFolderEmpty") : LLTrans::getString("InventorySingleFolderNoMatches"));
+    }
+
+    mScrollPanel->setVisible(!mItems.empty());
+}
+
+void LLInventoryGallery::refreshList(const LLUUID& category_id)
+{
+    LLInventoryModel::cat_array_t* cat_array;
+    LLInventoryModel::item_array_t* item_array;
+
+    gInventory.getDirectDescendentsOf(category_id, cat_array, item_array);
+    uuid_vec_t vadded;
+    uuid_vec_t vremoved;
+
+    // Create added and removed items vectors.
+    computeDifference(*cat_array, *item_array, vadded, vremoved);
+
+    // Handle added tabs.
+    for (uuid_vec_t::const_iterator iter = vadded.begin();
+        iter != vadded.end();
+        ++iter)
+    {
+        const LLUUID cat_id = (*iter);
+        updateAddedItem(cat_id);
+        mNeedsArrange = true;
+    }
+
+    // Handle removed tabs.
+    for (uuid_vec_t::const_iterator iter = vremoved.begin(); iter != vremoved.end(); ++iter)
+    {
+        const LLUUID cat_id = (*iter);
+        updateRemovedItem(cat_id);
+    }
+
+    const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs();
+    for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin();
+        items_iter != changed_items.end();
+        ++items_iter)
+    {
+        LLInventoryObject* obj = gInventory.getObject(*items_iter);
+        if(!obj)
+        {
+            return;
+        }
+
+        updateChangedItemName(*items_iter, obj->getName());
+        mNeedsArrange = true;
+    }
+
+    if(mNeedsArrange || !mItemsToSelect.empty())
+    {
+        // Don't scroll to target/arrange immediately
+        // since more updates might be pending
+        gIdleCallbacks.addFunction(onIdle, (void*)this);
+    }
+    updateMessageVisibility();
+}
+
+void LLInventoryGallery::computeDifference(
+    const LLInventoryModel::cat_array_t vcats,
+    const LLInventoryModel::item_array_t vitems,
+    uuid_vec_t& vadded,
+    uuid_vec_t& vremoved)
+{
+    uuid_vec_t vnew;
+    // Creating a vector of newly collected UUIDs.
+    for (LLInventoryModel::cat_array_t::const_iterator iter = vcats.begin();
+        iter != vcats.end();
+        iter++)
+    {
+        vnew.push_back((*iter)->getUUID());
+    }
+    for (LLInventoryModel::item_array_t::const_iterator iter = vitems.begin();
+        iter != vitems.end();
+        iter++)
+    {
+        vnew.push_back((*iter)->getUUID());
+    }
+
+    uuid_vec_t vcur;
+    getCurrentCategories(vcur);
+    std::copy(mItemBuildQuery.begin(), mItemBuildQuery.end(), std::back_inserter(vcur));
+
+    LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved);
+}
+
+void LLInventoryGallery::onCOFChanged()
+{
+    LLInventoryModel::cat_array_t cat_array;
+    LLInventoryModel::item_array_t item_array;
+
+    gInventory.collectDescendents(
+        LLAppearanceMgr::instance().getCOF(),
+        cat_array,
+        item_array,
+        LLInventoryModel::EXCLUDE_TRASH);
+
+    uuid_vec_t vnew;
+    uuid_vec_t vadded;
+    uuid_vec_t vremoved;
+
+    for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
+        iter != item_array.end();
+        ++iter)
+    {
+        vnew.push_back((*iter)->getLinkedUUID());
+    }
+
+    // We need to update only items that were added or removed from COF.
+    LLCommonUtils::computeDifference(vnew, mCOFLinkedItems, vadded, vremoved);
+
+    mCOFLinkedItems = vnew;
+    
+    for (uuid_vec_t::const_iterator iter = vadded.begin();
+        iter != vadded.end();
+        ++iter)
+    {
+        updateWornItem(*iter, true);
+    }
+
+    for (uuid_vec_t::const_iterator iter = vremoved.begin(); iter != vremoved.end(); ++iter)
+    {
+        updateWornItem(*iter, false);
+    }
+}
+
+void LLInventoryGallery::onGesturesChanged()
+{
+    uuid_vec_t vnew;
+    uuid_vec_t vadded;
+    uuid_vec_t vremoved;
+
+    const LLGestureMgr::item_map_t& active_gestures = LLGestureMgr::instance().getActiveGestures();
+    for (LLGestureMgr::item_map_t::const_iterator iter = active_gestures.begin();
+        iter != active_gestures.end();
+        ++iter)
+    {
+        vnew.push_back(iter->first);
+    }
+
+    LLCommonUtils::computeDifference(vnew, mActiveGestures, vadded, vremoved);
+
+    mActiveGestures = vnew;
+    
+    for (uuid_vec_t::const_iterator iter = vadded.begin();
+        iter != vadded.end();
+        ++iter)
+    {
+        updateWornItem(*iter, true);
+    }
+
+    for (uuid_vec_t::const_iterator iter = vremoved.begin(); iter != vremoved.end(); ++iter)
+    {
+        updateWornItem(*iter, false);
+    }
+}
+
+void LLInventoryGallery::deselectItem(const LLUUID& category_id)
+{
+    // Reset selection if the item is selected.
+    LLInventoryGalleryItem* item = mItemMap[category_id];
+    if (item && item->isSelected())
+    {
+        mItemMap[category_id]->setSelected(FALSE);
+        setFocus(true);
+        // Todo: support multiselect
+        // signalSelectionItemID(LLUUID::null);
+    }
+
+    selection_deque::iterator found = std::find(mSelectedItemIDs.begin(), mSelectedItemIDs.end(), category_id);
+    if (found != mSelectedItemIDs.end())
+    {
+        mSelectedItemIDs.erase(found);
+    }
+}
+
+void LLInventoryGallery::clearSelection()
+{
+    for (const LLUUID& id: mSelectedItemIDs)
+    {
+        if (mItemMap[id])
+        {
+            mItemMap[id]->setSelected(FALSE);
+        }
+    }
+    if (!mSelectedItemIDs.empty())
+    {
+        mSelectedItemIDs.clear();
+        // BUG: wrong, item can be null
+        signalSelectionItemID(LLUUID::null);
+    }
+}
+
+void LLInventoryGallery::signalSelectionItemID(const LLUUID& category_id)
+{
+    mSelectionChangeSignal(category_id);
+}
+
+boost::signals2::connection LLInventoryGallery::setSelectionChangeCallback(selection_change_callback_t cb)
+{
+    return mSelectionChangeSignal.connect(cb);
+}
+
+LLUUID LLInventoryGallery::getFirstSelectedItemID()
+{
+    if (mSelectedItemIDs.size() > 0)
+    {
+        return *mSelectedItemIDs.begin();
+    }
+    return LLUUID::null;
+}
+
+LLUUID LLInventoryGallery::getOutfitImageID(LLUUID outfit_id)
+{
+    LLUUID thumbnail_id;
+    LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id);
+    if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT)
+    {
+        LLInventoryModel::cat_array_t cats;
+        LLInventoryModel::item_array_t items;
+        // Not LLIsOfAssetType, because we allow links
+        LLIsTextureType f;
+        gInventory.getDirectDescendentsOf(outfit_id, cats, items, f);
+
+        // Exactly one texture found => show the texture as thumbnail
+        if (1 == items.size())
+        {
+            LLViewerInventoryItem* item = items.front();
+            if (item && item->getIsLinkType())
+            {
+                item = item->getLinkedItem();
+            }
+            if (item)
+            {
+                thumbnail_id = item->getAssetUUID();
+            }
+        }
+    }
+    return thumbnail_id;
+}
+
+boost::signals2::connection LLInventoryGallery::setRootChangedCallback(callback_t cb)
+{
+    return mRootChangedSignal.connect(cb);
+}
+
+void LLInventoryGallery::onForwardFolder()
+{
+    if(isForwardAvailable())
+    {
+        mBackwardFolders.push_back(mFolderID);
+        mFolderID = mForwardFolders.back();
+        mForwardFolders.pop_back();
+        dirtyRootFolder();
+    }
+}
+
+void LLInventoryGallery::onBackwardFolder()
+{
+    if(isBackwardAvailable())
+    {
+        mForwardFolders.push_back(mFolderID);
+        mFolderID = mBackwardFolders.back();
+        mBackwardFolders.pop_back();
+        dirtyRootFolder();
+    }
+}
+
+void LLInventoryGallery::clearNavigationHistory()
+{
+    mForwardFolders.clear();
+    mBackwardFolders.clear();
+}
+
+bool LLInventoryGallery::isBackwardAvailable()
+{
+    return (!mBackwardFolders.empty() && (mFolderID != mBackwardFolders.back()));
+}
+
+bool LLInventoryGallery::isForwardAvailable()
+{
+    return (!mForwardFolders.empty() && (mFolderID != mForwardFolders.back()));
+}
+
+BOOL LLInventoryGallery::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
+                                           EDragAndDropType cargo_type, void* cargo_data,
+                                           EAcceptance* accept, std::string& tooltip_msg)
+{
+    // have children handle it first
+    BOOL handled = LLView::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data,
+                                            accept, tooltip_msg);
+
+    // when drop is not handled by child, it should be handled by the root folder .
+    if (!handled || (*accept == ACCEPT_NO))
+    {
+        handled = baseHandleDragAndDrop(mFolderID, drop, cargo_type, cargo_data, accept, tooltip_msg);
+    }
+
+    return handled;
+}
+
+void LLInventoryGallery::startDrag()
+{
+    std::vector<EDragAndDropType> types;
+    uuid_vec_t ids;
+    LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_AGENT;
+    for (LLUUID& selected_id : mSelectedItemIDs)
+    {
+        const LLInventoryItem* item = gInventory.getItem(selected_id);
+        if (item)
+        {
+            if (item->getPermissions().getOwner() == ALEXANDRIA_LINDEN_ID)
+            {
+                src = LLToolDragAndDrop::SOURCE_LIBRARY;
+            }
+
+            EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(item->getType());
+            types.push_back(type);
+            ids.push_back(selected_id);
+        }
+
+        const LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id);        
+        if (cat && gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID())
+            && !LLFolderType::lookupIsProtectedType((cat)->getPreferredType()))
+        {
+            if (cat->getOwnerID() == ALEXANDRIA_LINDEN_ID)
+            {
+                src = LLToolDragAndDrop::SOURCE_LIBRARY;
+            }
+
+            EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(cat->getType());
+            types.push_back(type);
+            ids.push_back(selected_id);
+        }
+    }
+    LLToolDragAndDrop::getInstance()->beginMultiDrag(types, ids, LLToolDragAndDrop::SOURCE_AGENT);
+}
+
+bool LLInventoryGallery::areViewsInitialized()
+{
+    return mGalleryCreated && mItemBuildQuery.empty();
+}
+
+bool LLInventoryGallery::hasDescendents(const LLUUID& cat_id)
+{
+    LLInventoryModel::cat_array_t* cats;
+    LLInventoryModel::item_array_t* items;
+    gInventory.getDirectDescendentsOf(cat_id, cats, items);
+
+    return (cats->empty() && items->empty());
+}
+
+bool LLInventoryGallery::checkAgainstFilterType(const LLUUID& object_id)
+{
+    const LLInventoryObject *object = gInventory.getObject(object_id);
+    if(!object) return false;
+
+    LLInventoryType::EType object_type = LLInventoryType::IT_CATEGORY;
+    LLInventoryItem* inv_item = gInventory.getItem(object_id);
+    if (inv_item)
+    {
+        object_type = inv_item->getInventoryType();
+    }
+    const U32 filterTypes = mFilter->getFilterTypes();
+
+    if ((filterTypes & LLInventoryFilter::FILTERTYPE_OBJECT) && inv_item)
+    {
+        switch (object_type)
+        {
+        case LLInventoryType::IT_NONE:
+            // If it has no type, pass it, unless it's a link.
+            if (object && object->getIsLinkType())
+            {
+                return false;
+            }
+            break;
+        case LLInventoryType::IT_UNKNOWN:
+            {
+                // Unknows are only shown when we show every type.
+                // Unknows are 255 and won't fit in 64 bits.
+                if (mFilter->getFilterObjectTypes() != 0xffffffffffffffffULL)
+                {
+                    return false;
+                }
+                break;
+            }
+        default:
+            if ((1LL << object_type & mFilter->getFilterObjectTypes()) == U64(0))
+            {
+                return false;
+            }
+            break;
+        }
+    }
+    
+    if (filterTypes & LLInventoryFilter::FILTERTYPE_DATE)
+    {
+        const U16 HOURS_TO_SECONDS = 3600;
+        time_t earliest = time_corrected() - mFilter->getHoursAgo() * HOURS_TO_SECONDS;
+
+        if (mFilter->getMinDate() > time_min() && mFilter->getMinDate() < earliest)
+        {
+            earliest = mFilter->getMinDate();
+        }
+        else if (!mFilter->getHoursAgo())
+        {
+            earliest = 0;
+        }
+
+        if (LLInventoryFilter::FILTERDATEDIRECTION_NEWER == mFilter->getDateSearchDirection() || mFilter->isSinceLogoff())
+        {
+            if (object->getCreationDate() < earliest ||
+                object->getCreationDate() > mFilter->getMaxDate())
+                return false;
+        }
+        else
+        {
+            if (object->getCreationDate() > earliest ||
+                object->getCreationDate() > mFilter->getMaxDate())
+                return false;
+        }
+    }
+    return true;
+}
+
+bool LLInventoryGallery::hasVisibleItems()
+{
+    return mItemsAddedCount > 0;
+}
+
+void LLInventoryGallery::handleModifiedFilter()
+{
+    if(mFilter->isModified())
+    {
+        reArrangeRows();
+    }
+}
+
+void LLInventoryGallery::setSortOrder(U32 order, bool update)
+{
+    bool dirty = (mSortOrder != order);
+
+    mSortOrder = order;
+    if(update && dirty)
+    {
+        mNeedsArrange = true;
+        gIdleCallbacks.addFunction(onIdle, (void*)this);
+    }
+}
+//-----------------------------
+// LLInventoryGalleryItem
+//-----------------------------
+
+static LLDefaultChildRegistry::Register<LLInventoryGalleryItem> r("inventory_gallery_item");
+
+LLInventoryGalleryItem::LLInventoryGalleryItem(const Params& p)
+    : LLPanel(p),
+    mSelected(false),
+    mDefaultImage(true),
+    mItemName(""),
+    mWornSuffix(""),
+    mPermSuffix(""),
+    mUUID(LLUUID()),
+    mIsFolder(true),
+    mIsLink(false),
+    mHidden(false),
+    mGallery(NULL),
+    mType(LLAssetType::AT_NONE),
+    mSortGroup(SG_ITEM),
+    mCutGeneration(0),
+    mSelectedForCut(false)
+{
+    buildFromFile("panel_inventory_gallery_item.xml");
+}
+
+LLInventoryGalleryItem::~LLInventoryGalleryItem()
+{
+}
+
+BOOL LLInventoryGalleryItem::postBuild()
+{
+    mNameText = getChild<LLTextBox>("item_name");
+    mTextBgPanel = getChild<LLPanel>("text_bg_panel");
+
+    return TRUE;
+}
+
+void LLInventoryGalleryItem::setType(LLAssetType::EType type, LLInventoryType::EType inventory_type, U32 flags, bool is_link)
+{
+    mType = type;
+    mIsFolder = (mType == LLAssetType::AT_CATEGORY);
+    mIsLink = is_link;
+
+    std::string icon_name = LLInventoryIcon::getIconName(mType, inventory_type, flags);
+    if(mIsFolder)
+    {
+        mSortGroup = SG_NORMAL_FOLDER;
+        LLUUID folder_id = mUUID;
+        if(mIsLink)
+        {
+            LLInventoryObject* obj = gInventory.getObject(mUUID);
+            if (obj)
+            {
+                folder_id = obj->getLinkedUUID();
+            }
+        }
+        LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id);
+        if (cat)
+        {
+            LLFolderType::EType preferred_type = cat->getPreferredType();
+            icon_name = LLViewerFolderType::lookupIconName(preferred_type);
+
+            if (preferred_type == LLFolderType::FT_TRASH)
+            {
+                mSortGroup = SG_TRASH_FOLDER;
+            }
+            else if(LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
+            {
+                mSortGroup = SG_SYSTEM_FOLDER;
+            }
+        }
+    }
+    else
+    {
+        const LLInventoryItem *item = gInventory.getItem(mUUID);
+        if(item && (LLAssetType::AT_CALLINGCARD != item->getType()) && !mIsLink)
+        {
+            std::string delim(" --");
+            bool copy = item->getPermissions().allowCopyBy(gAgent.getID());
+            if (!copy)
+            {
+                mPermSuffix += delim;
+                mPermSuffix += LLTrans::getString("no_copy_lbl");
+            }
+            bool mod = item->getPermissions().allowModifyBy(gAgent.getID());
+            if (!mod)
+            {
+                mPermSuffix += mPermSuffix.empty() ? delim : ",";
+                mPermSuffix += LLTrans::getString("no_modify_lbl");
+            }
+            bool xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID());
+            if (!xfer)
+            {
+                mPermSuffix += mPermSuffix.empty() ? delim : ",";
+                mPermSuffix += LLTrans::getString("no_transfer_lbl");
+            }
+        }
+    }
+
+    getChild<LLIconCtrl>("item_type")->setValue(icon_name);
+    getChild<LLIconCtrl>("link_overlay")->setVisible(is_link);
+}
+
+void LLInventoryGalleryItem::setThumbnail(LLUUID id)
+{
+    mDefaultImage = id.isNull();
+    if(mDefaultImage)
+    {
+        getChild<LLThumbnailCtrl>("preview_thumbnail")->clearTexture();
+    }
+    else
+    {
+        getChild<LLThumbnailCtrl>("preview_thumbnail")->setValue(id);
+    }
+}
+
+void LLInventoryGalleryItem::draw()
+{
+    if (isFadeItem())
+    {
+        // Fade out to indicate it's being cut
+        LLViewDrawContext context(0.5f);
+        LLPanel::draw();
+    }
+    else
+    {
+        LLPanel::draw();
+
+        // Draw border
+        LLUIColor border_color = LLUIColorTable::instance().getColor(mSelected ? "MenuItemHighlightBgColor" : "TextFgTentativeColor", LLColor4::white);
+        LLRect border = getChildView("preview_thumbnail")->getRect();
+        border.mRight = border.mRight + 1;
+        border.mTop = border.mTop + 1;
+        gl_rect_2d(border, border_color.get(), FALSE);
+    }
+}
+
+void LLInventoryGalleryItem::setItemName(std::string name)
+{
+    mItemName = name;
+    updateNameText();
+}
+
+void LLInventoryGalleryItem::setSelected(bool value)
+{
+    mSelected = value;
+    mTextBgPanel->setBackgroundVisible(value);
+
+    if(mSelected)
+    {
+        LLViewerInventoryItem* item = gInventory.getItem(mUUID);
+        if(item && !item->isFinished())
+        {
+            LLInventoryModelBackgroundFetch::instance().start(mUUID, false);
+        }
+    }
+}
+
+BOOL LLInventoryGalleryItem::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+    // call changeItemSelection directly, before setFocus
+    // to avoid autoscroll from LLInventoryGallery::onFocusReceived()
+    if (mask == MASK_CONTROL)
+    {
+        mGallery->addItemSelection(mUUID, false);
+    }
+    else if (mask == MASK_SHIFT)
+    {
+        mGallery->toggleSelectionRangeFromLast(mUUID);
+    }
+    else
+    {
+        mGallery->changeItemSelection(mUUID, false);
+    }
+    setFocus(TRUE);
+    mGallery->claimEditHandler();
+
+    gFocusMgr.setMouseCapture(this);
+    S32 screen_x;
+    S32 screen_y;
+    localPointToScreen(x, y, &screen_x, &screen_y );
+    LLToolDragAndDrop::getInstance()->setDragStart(screen_x, screen_y);
+    return TRUE;
+}
+
+BOOL LLInventoryGalleryItem::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+    if (!isSelected())
+    {
+        mGallery->changeItemSelection(mUUID, false);
+    }
+    else
+    {
+        // refresh last interacted
+        mGallery->addItemSelection(mUUID, false);
+    }
+    setFocus(TRUE);
+    mGallery->claimEditHandler();
+    mGallery->showContextMenu(this, x, y, mUUID);
+
+    LLUICtrl::handleRightMouseDown(x, y, mask);
+    return TRUE;
+}
+
+BOOL LLInventoryGalleryItem::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+    if(hasMouseCapture())
+    {
+        gFocusMgr.setMouseCapture(NULL);
+        return TRUE;
+    }
+    return LLPanel::handleMouseUp(x, y, mask);
+}
+
+BOOL LLInventoryGalleryItem::handleHover(S32 x, S32 y, MASK mask)
+{
+    if(hasMouseCapture())
+    {
+        S32 screen_x;
+        S32 screen_y;
+        localPointToScreen(x, y, &screen_x, &screen_y );
+
+        if(LLToolDragAndDrop::getInstance()->isOverThreshold(screen_x, screen_y) && mGallery)
+        {
+            mGallery->startDrag();
+            return LLToolDragAndDrop::getInstance()->handleHover(x, y, mask);
+        }
+    }
+    return LLUICtrl::handleHover(x,y,mask);
+}
+
+BOOL LLInventoryGalleryItem::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+    if (mIsFolder && mGallery)
+    {
+        // setRootFolder can destroy this item.
+        // Delay it until handleDoubleClick processing is complete
+        // or make gallery handle doubleclicks.
+        LLHandle<LLPanel> handle = mGallery->getHandle();
+        LLUUID navigate_to = mUUID;
+        doOnIdleOneTime([handle, navigate_to]()
+                        {
+                            LLInventoryGallery* gallery = (LLInventoryGallery*)handle.get();
+                            if (gallery)
+                            {
+                                gallery->setRootFolder(navigate_to);
+                            }
+                        });
+    }
+    else
+    {
+        LLInvFVBridgeAction::doAction(mUUID, &gInventory);
+    }
+
+    return TRUE;
+}
+
+BOOL LLInventoryGalleryItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
+                       EDragAndDropType cargo_type,
+                       void* cargo_data,
+                       EAcceptance* accept,
+                       std::string& tooltip_msg)
+{
+    if (!mIsFolder)
+    {
+        return FALSE;
+    }
+    return mGallery->baseHandleDragAndDrop(mUUID, drop, cargo_type, cargo_data, accept, tooltip_msg);
+}
+
+BOOL LLInventoryGalleryItem::handleKeyHere(KEY key, MASK mask)
+{
+    if (!mGallery)
+    {
+        return FALSE;
+    }
+
+    BOOL handled = FALSE;
+    switch (key)
+    {
+        case KEY_LEFT:
+            mGallery->moveLeft(mask);
+            handled = true;
+            break;
+
+        case KEY_RIGHT:
+            mGallery->moveRight(mask);
+            handled = true;
+            break;
+
+        case KEY_UP:
+            mGallery->moveUp(mask);
+            handled = true;
+            break;
+
+        case KEY_DOWN:
+            mGallery->moveDown(mask);
+            handled = true;
+            break;
+
+        default:
+            break;
+    }
+    return handled;
+}
+
+void LLInventoryGalleryItem::onFocusLost()
+{
+    // inventory no longer handles cut/copy/paste/delete
+    mGallery->resetEditHandler();
+
+    LLPanel::onFocusLost();
+}
+
+void LLInventoryGalleryItem::onFocusReceived()
+{
+    // inventory now handles cut/copy/paste/delete
+    mGallery->claimEditHandler();
+
+    LLPanel::onFocusReceived();
+}
+
+void LLInventoryGalleryItem::setWorn(bool value)
+{
+    mWorn = value;
+
+    if(mWorn)
+    {
+        mWornSuffix = (mType == LLAssetType::AT_GESTURE) ? LLTrans::getString("active") : LLTrans::getString("worn");
+    }
+    else
+    {
+        mWornSuffix = "";
+    }
+
+    updateNameText();
+}
+
+LLFontGL* LLInventoryGalleryItem::getTextFont()
+{
+    if(mWorn)
+    {
+        return LLFontGL::getFontSansSerifSmallBold();
+    }
+    return mIsLink ? LLFontGL::getFontSansSerifSmallItalic() : LLFontGL::getFontSansSerifSmall();
+}
+
+void LLInventoryGalleryItem::updateNameText()
+{
+    mNameText->setFont(getTextFont());
+    mNameText->setText(mItemName + mPermSuffix + mWornSuffix);
+    mNameText->setToolTip(mItemName + mPermSuffix + mWornSuffix);
+    getChild<LLThumbnailCtrl>("preview_thumbnail")->setToolTip(mItemName + mPermSuffix + mWornSuffix);
+}
+
+bool LLInventoryGalleryItem::isFadeItem()
+{
+    LLClipboard& clipboard = LLClipboard::instance();
+    if (mCutGeneration == clipboard.getGeneration())
+    {
+        return mSelectedForCut;
+    }
+
+    mCutGeneration = clipboard.getGeneration();
+    mSelectedForCut = clipboard.isCutMode() && clipboard.isOnClipboard(mUUID);
+    return mSelectedForCut;
+}
+
+//-----------------------------
+// LLThumbnailsObserver
+//-----------------------------
+
+void LLThumbnailsObserver::changed(U32 mask)
+{
+    std::vector<LLUUID> deleted_ids;
+    for (item_map_t::iterator iter = mItemMap.begin();
+         iter != mItemMap.end();
+         ++iter)
+    {
+        const LLUUID& obj_id = (*iter).first;
+        LLItemData& data = (*iter).second;
+        
+        LLInventoryObject* obj = gInventory.getObject(obj_id);
+        if (!obj)
+        {
+            deleted_ids.push_back(obj_id);
+            continue;
+        }
+
+        const LLUUID thumbnail_id = obj->getThumbnailUUID();
+        if (data.mThumbnailID != thumbnail_id)
+        {
+            data.mThumbnailID = thumbnail_id;
+            data.mCallback();
+        }
+    }
+
+    // Remove deleted items from the list
+    for (std::vector<LLUUID>::iterator deleted_id = deleted_ids.begin(); deleted_id != deleted_ids.end(); ++deleted_id)
+    {
+        removeItem(*deleted_id);
+    }
+}
+
+bool LLThumbnailsObserver::addItem(const LLUUID& obj_id, callback_t cb)
+{
+    LLInventoryObject* obj = gInventory.getObject(obj_id);
+    if (obj)
+    {
+        mItemMap.insert(item_map_value_t(obj_id, LLItemData(obj_id, obj->getThumbnailUUID(), cb)));
+        return true;
+    }
+    return false;
+}
+
+void LLThumbnailsObserver::removeItem(const LLUUID& obj_id)
+{
+    mItemMap.erase(obj_id);
+}
+
+//-----------------------------
+// Helper drag&drop functions
+//-----------------------------
+
+BOOL LLInventoryGallery::baseHandleDragAndDrop(LLUUID dest_id, BOOL drop,
+                       EDragAndDropType cargo_type,
+                       void* cargo_data,
+                       EAcceptance* accept,
+                       std::string& tooltip_msg)
+{
+    LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
+
+    if (drop && LLToolDragAndDrop::getInstance()->getCargoIndex() == 0)
+    {
+        clearSelection();
+    }
+
+    BOOL accepted = FALSE;
+    switch(cargo_type)
+    {
+        case DAD_TEXTURE:
+        case DAD_SOUND:
+        case DAD_CALLINGCARD:
+        case DAD_LANDMARK:
+        case DAD_SCRIPT:
+        case DAD_CLOTHING:
+        case DAD_OBJECT:
+        case DAD_NOTECARD:
+        case DAD_BODYPART:
+        case DAD_ANIMATION:
+        case DAD_GESTURE:
+        case DAD_MESH:
+        case DAD_SETTINGS:
+            accepted = dragItemIntoFolder(dest_id, inv_item, drop, tooltip_msg, true);
+            if (accepted && drop)
+            {
+                // Don't select immediately, wait for item to arrive
+                mItemsToSelect.push_back(inv_item->getUUID());
+            }
+            break;
+        case DAD_LINK:
+            // DAD_LINK type might mean one of two asset types: AT_LINK or AT_LINK_FOLDER.
+            // If we have an item of AT_LINK_FOLDER type we should process the linked
+            // category being dragged or dropped into folder.
+            if (inv_item && LLAssetType::AT_LINK_FOLDER == inv_item->getActualType())
+            {
+                LLInventoryCategory* linked_category = gInventory.getCategory(inv_item->getLinkedUUID());
+                if (linked_category)
+                {
+                    accepted = dragCategoryIntoFolder(dest_id, (LLInventoryCategory*)linked_category, drop, tooltip_msg, TRUE);
+                }
+            }
+            else
+            {
+                accepted = dragItemIntoFolder(dest_id, inv_item, drop, tooltip_msg, TRUE);
+            }
+            if (accepted && drop && inv_item)
+            {
+                mItemsToSelect.push_back(inv_item->getUUID());
+            }
+            break;
+        case DAD_CATEGORY:
+            if (LLFriendCardsManager::instance().isAnyFriendCategory(dest_id))
+            {
+                accepted = FALSE;
+            }
+            else
+            {
+                LLInventoryCategory* cat_ptr = (LLInventoryCategory*)cargo_data;
+                accepted = dragCategoryIntoFolder(dest_id, cat_ptr, drop, tooltip_msg, FALSE);
+                if (accepted && drop)
+                {
+                    mItemsToSelect.push_back(cat_ptr->getUUID());
+                }
+            }
+            break;
+        case DAD_ROOT_CATEGORY:
+        case DAD_NONE:
+            break;
+        default:
+            LL_WARNS() << "Unhandled cargo type for drag&drop " << cargo_type << LL_ENDL;
+            break;
+    }
+    if (accepted)
+    {
+        *accept = ACCEPT_YES_MULTI;
+    }
+    else
+    {
+        *accept = ACCEPT_NO;
+    }
+    return accepted;
+}
+
+// copy of LLFolderBridge::dragItemIntoFolder
+BOOL dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm)
+{
+    LLViewerInventoryCategory * cat = gInventory.getCategory(folder_id);
+    if (!cat)
+    {
+        return FALSE;
+    }
+    LLInventoryModel* model = &gInventory;
+
+    if (!model || !inv_item) return FALSE;
+
+    // cannot drag into library
+    if((gInventory.getRootFolderID() != folder_id) && !model->isObjectDescendentOf(folder_id, gInventory.getRootFolderID()))
+    {
+        return FALSE;
+    }
+    if (!isAgentAvatarValid()) return FALSE;
+
+    const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+    const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+    const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
+    const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+    const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+    const BOOL move_is_into_current_outfit = (folder_id == current_outfit_id);
+    const BOOL move_is_into_favorites = (folder_id == favorites_id);
+    const BOOL move_is_into_my_outfits = (folder_id == my_outifts_id) || model->isObjectDescendentOf(folder_id, my_outifts_id);
+    const BOOL move_is_into_outfit = move_is_into_my_outfits || (cat && cat->getPreferredType()==LLFolderType::FT_OUTFIT);
+    const BOOL move_is_into_landmarks = (folder_id == landmarks_id) || model->isObjectDescendentOf(folder_id, landmarks_id);
+    const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(folder_id, marketplacelistings_id);
+    const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(inv_item->getUUID(), marketplacelistings_id);
+
+    LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
+    BOOL accept = FALSE;
+    LLViewerObject* object = NULL;
+    if(LLToolDragAndDrop::SOURCE_AGENT == source)
+    {
+        const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+
+        const BOOL move_is_into_trash = (folder_id == trash_id) || model->isObjectDescendentOf(folder_id, trash_id);
+        const BOOL move_is_outof_current_outfit = LLAppearanceMgr::instance().getIsInCOF(inv_item->getUUID());
+
+        //--------------------------------------------------------------------------------
+        // Determine if item can be moved.
+        //
+
+        BOOL is_movable = TRUE;
+
+        switch (inv_item->getActualType())
+        {
+            case LLAssetType::AT_CATEGORY:
+                is_movable = !LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)inv_item)->getPreferredType());
+                break;
+            default:
+                break;
+        }
+        // Can't explicitly drag things out of the COF.
+        if (move_is_outof_current_outfit)
+        {
+            is_movable = FALSE;
+        }
+        if (move_is_into_trash)
+        {
+            is_movable &= inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID());
+        }
+        if (is_movable)
+        {
+            // Don't allow creating duplicates in the Calling Card/Friends
+            // subfolders, see bug EXT-1599. Check is item direct descendent
+            // of target folder and forbid item's movement if it so.
+            // Note: isItemDirectDescendentOfCategory checks if
+            // passed category is in the Calling Card/Friends folder
+            is_movable &= !LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(inv_item, cat);
+        }
+
+        //
+        //--------------------------------------------------------------------------------
+        
+        //--------------------------------------------------------------------------------
+        // Determine if item can be moved & dropped
+        // Note: if user_confirm is false, we already went through those accept logic test and can skip them
+
+        accept = TRUE;
+
+        if (user_confirm && !is_movable)
+        {
+            accept = FALSE;
+        }
+        else if (user_confirm && (folder_id == inv_item->getParentUUID()) && !move_is_into_favorites)
+        {
+            accept = FALSE;
+        }
+        else if (user_confirm && (move_is_into_current_outfit || move_is_into_outfit))
+        {
+            accept = can_move_to_outfit(inv_item, move_is_into_current_outfit);
+        }
+        else if (user_confirm && (move_is_into_favorites || move_is_into_landmarks))
+        {
+            accept = can_move_to_landmarks(inv_item);
+        }
+        else if (user_confirm && move_is_into_marketplacelistings)
+        {
+            //disable dropping in or out of marketplace for now
+            return FALSE;
+            
+            /*const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, folder_id);
+            LLViewerInventoryCategory * dest_folder = cat;
+            accept = can_move_item_to_marketplace(master_folder, dest_folder, inv_item, tooltip_msg, LLToolDragAndDrop::instance().getCargoCount() - LLToolDragAndDrop::instance().getCargoIndex());*/
+        }
+
+        // Check that the folder can accept this item based on folder/item type compatibility (e.g. stock folder compatibility)
+        if (user_confirm && accept)
+        {
+            LLViewerInventoryCategory * dest_folder = cat;
+            accept = dest_folder->acceptItem(inv_item);
+        }
+        
+        LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
+
+        if (accept && drop)
+        {
+            if (inv_item->getType() == LLAssetType::AT_GESTURE
+                && LLGestureMgr::instance().isGestureActive(inv_item->getUUID()) && move_is_into_trash)
+            {
+                LLGestureMgr::instance().deactivateGesture(inv_item->getUUID());
+            }
+            // If an item is being dragged between windows, unselect everything in the active window
+            // so that we don't follow the selection to its new location (which is very annoying).
+                        // RN: a better solution would be to deselect automatically when an   item is moved
+            // and then select any item that is dropped only in the panel that it   is dropped in
+            if (active_panel)
+            {
+                active_panel->unSelectAll();
+            }
+            // Dropping in or out of marketplace needs (sometimes) confirmation
+            if (user_confirm && (move_is_from_marketplacelistings || move_is_into_marketplacelistings))
+            {
+                //disable dropping in or out of marketplace for now
+                return FALSE;
+            }
+
+            //--------------------------------------------------------------------------------
+            // Destination folder logic
+            //
+
+            // FAVORITES folder
+            // (copy the item)
+            else if (move_is_into_favorites)
+            {
+                copy_inventory_item(
+                    gAgent.getID(),
+                    inv_item->getPermissions().getOwner(),
+                    inv_item->getUUID(),
+                    folder_id,
+                    std::string(),
+                    LLPointer<LLInventoryCallback>(NULL));
+            }
+            // CURRENT OUTFIT or OUTFIT folder
+            // (link the item)
+            else if (move_is_into_current_outfit || move_is_into_outfit)
+            {
+                if (move_is_into_current_outfit)
+                {
+                    LLAppearanceMgr::instance().wearItemOnAvatar(inv_item->getUUID(), true, true);
+                }
+                else
+                {
+                    LLPointer<LLInventoryCallback> cb = NULL;
+                    link_inventory_object(folder_id, LLConstPointer<LLInventoryObject>(inv_item), cb);
+                }
+            }
+            // MARKETPLACE LISTINGS folder
+            // Move the item
+            else if (move_is_into_marketplacelistings)
+            {
+                //move_item_to_marketplacelistings(inv_item, mUUID);
+                return FALSE;
+            }
+            // NORMAL or TRASH folder
+            // (move the item, restamp if into trash)
+            else
+            {
+                // set up observer to select item once drag and drop from inbox is complete
+                if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX)))
+                {
+                    set_dad_inbox_object(inv_item->getUUID());
+                }
+
+                gInventory.changeItemParent((LLViewerInventoryItem*)inv_item, folder_id, move_is_into_trash);
+            }
+            
+            if (move_is_from_marketplacelistings)
+            {
+                // If we move from an active (listed) listing, checks that it's still valid, if not, unlist
+                /*LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
+                if (version_folder_id.notNull())
+                {
+                    LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+                        version_folder_id,
+                        [version_folder_id](bool result)
+                    {
+                        if (!result)
+                        {
+                            LLMarketplaceData::instance().activateListing(version_folder_id, false);
+                        }
+                    });
+                }*/
+                return FALSE;
+            }
+
+            //
+            //--------------------------------------------------------------------------------
+        }
+    }
+    else if (LLToolDragAndDrop::SOURCE_WORLD == source)
+    {
+        // Make sure the object exists. If we allowed dragging from
+        // anonymous objects, it would be possible to bypass
+        // permissions.
+        object = gObjectList.findObject(inv_item->getParentUUID());
+        if (!object)
+        {
+            LL_INFOS() << "Object not found for drop." << LL_ENDL;
+            return FALSE;
+        }
+
+        // coming from a task. Need to figure out if the person can
+        // move/copy this item.
+        LLPermissions perm(inv_item->getPermissions());
+        bool is_move = false;
+        if ((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID())
+            && perm.allowTransferTo(gAgent.getID())))
+            // || gAgent.isGodlike())
+        {
+            accept = TRUE;
+        }
+        else if(object->permYouOwner())
+        {
+            // If the object cannot be copied, but the object the
+            // inventory is owned by the agent, then the item can be
+            // moved from the task to agent inventory.
+            is_move = true;
+            accept = TRUE;
+        }
+
+        // Don't allow placing an original item into Current Outfit or an outfit folder
+        // because they must contain only links to wearable items.
+        if (move_is_into_current_outfit || move_is_into_outfit)
+        {
+            accept = FALSE;
+        }
+        // Don't allow to move a single item to Favorites or Landmarks
+        // if it is not a landmark or a link to a landmark.
+        else if ((move_is_into_favorites || move_is_into_landmarks)
+                 && !can_move_to_landmarks(inv_item))
+        {
+            accept = FALSE;
+        }
+        else if (move_is_into_marketplacelistings)
+        {
+            tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+            accept = FALSE;
+        }
+
+        if (accept && drop)
+        {
+            std::shared_ptr<LLMoveInv> move_inv (new LLMoveInv());
+            move_inv->mObjectID = inv_item->getParentUUID();
+            std::pair<LLUUID, LLUUID> item_pair(folder_id, inv_item->getUUID());
+            move_inv->mMoveList.push_back(item_pair);
+            move_inv->mCallback = NULL;
+            move_inv->mUserData = NULL;
+            if(is_move)
+            {
+                warn_move_inventory(object, move_inv);
+            }
+            else
+            {
+                // store dad inventory item to select added one later. See EXT-4347
+                set_dad_inventory_item(inv_item, folder_id);
+
+                LLNotification::Params params("MoveInventoryFromObject");
+                params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv));
+                LLNotifications::instance().forceResponse(params, 0);
+            }
+        }
+    }
+    else if(LLToolDragAndDrop::SOURCE_NOTECARD == source)
+    {
+        if (move_is_into_marketplacelistings)
+        {
+            tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+            accept = FALSE;
+        }
+        else if ((inv_item->getActualType() == LLAssetType::AT_SETTINGS) && !LLEnvironment::instance().isInventoryEnabled())
+        {
+            tooltip_msg = LLTrans::getString("NoEnvironmentSettings");
+            accept = FALSE;
+        }
+        else
+        {
+            // Don't allow placing an original item from a notecard to Current Outfit or an outfit folder
+            // because they must contain only links to wearable items.
+            accept = !(move_is_into_current_outfit || move_is_into_outfit);
+        }
+
+        if (accept && drop)
+        {
+            copy_inventory_from_notecard(folder_id,  // Drop to the chosen destination folder
+                                         LLToolDragAndDrop::getInstance()->getObjectID(),
+                                         LLToolDragAndDrop::getInstance()->getSourceID(),
+                                         inv_item);
+        }
+    }
+    else if(LLToolDragAndDrop::SOURCE_LIBRARY == source)
+    {
+        LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_item;
+        if(item && item->isFinished())
+        {
+            accept = TRUE;
+
+            if (move_is_into_marketplacelistings)
+            {
+                tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+                accept = FALSE;
+            }
+            else if (move_is_into_current_outfit || move_is_into_outfit)
+            {
+                accept = can_move_to_outfit(inv_item, move_is_into_current_outfit);
+            }
+            // Don't allow to move a single item to Favorites or Landmarks
+            // if it is not a landmark or a link to a landmark.
+            else if (move_is_into_favorites || move_is_into_landmarks)
+            {
+                accept = can_move_to_landmarks(inv_item);
+            }
+
+            if (accept && drop)
+            {
+                // FAVORITES folder
+                // (copy the item)
+                if (move_is_into_favorites)
+                {
+                    copy_inventory_item(
+                        gAgent.getID(),
+                        inv_item->getPermissions().getOwner(),
+                        inv_item->getUUID(),
+                        folder_id,
+                        std::string(),
+                        LLPointer<LLInventoryCallback>(NULL));
+                }
+                // CURRENT OUTFIT or OUTFIT folder
+                // (link the item)
+                else if (move_is_into_current_outfit || move_is_into_outfit)
+                {
+                    if (move_is_into_current_outfit)
+                    {
+                        LLAppearanceMgr::instance().wearItemOnAvatar(inv_item->getUUID(), true, true);
+                    }
+                    else
+                    {
+                        LLPointer<LLInventoryCallback> cb = NULL;
+                        link_inventory_object(folder_id, LLConstPointer<LLInventoryObject>(inv_item), cb);
+                    }
+                }
+                else
+                {
+                    copy_inventory_item(
+                        gAgent.getID(),
+                        inv_item->getPermissions().getOwner(),
+                        inv_item->getUUID(),
+                        folder_id,
+                        std::string(),
+                        LLPointer<LLInventoryCallback>(NULL));
+                }
+            }
+        }
+    }
+    else
+    {
+        LL_WARNS() << "unhandled drag source" << LL_ENDL;
+    }
+    return accept;
+}
+
+// copy of LLFolderBridge::dragCategoryIntoFolder
+BOOL dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,
+                            BOOL drop, std::string& tooltip_msg, BOOL is_link)
+{
+    BOOL user_confirm = TRUE;
+    LLInventoryModel* model = &gInventory;
+    LLViewerInventoryCategory * dest_cat = gInventory.getCategory(dest_id);
+    if (!dest_cat)
+    {
+        return FALSE;
+    }
+
+    if (!inv_cat) return FALSE; // shouldn't happen, but in case item is incorrectly parented in which case inv_cat will be NULL
+
+    if (!isAgentAvatarValid()) return FALSE;
+    // cannot drag into library
+    if((gInventory.getRootFolderID() != dest_id) && !model->isObjectDescendentOf(dest_id, gInventory.getRootFolderID()))
+    {
+        return FALSE;
+    }
+
+    const LLUUID &cat_id = inv_cat->getUUID();
+    const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+    const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+    //const LLUUID from_folder_uuid = inv_cat->getParentUUID();
+    
+    const BOOL move_is_into_current_outfit = (dest_id == current_outfit_id);
+    const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(dest_id, marketplacelistings_id);
+    const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(cat_id, marketplacelistings_id);
+
+    // check to make sure source is agent inventory, and is represented there.
+    LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
+    const BOOL is_agent_inventory = (model->getCategory(cat_id) != NULL)
+        && (LLToolDragAndDrop::SOURCE_AGENT == source);
+
+    BOOL accept = FALSE;
+
+    if (is_agent_inventory)
+    {
+        const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+        const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
+        const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+        const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
+
+        const BOOL move_is_into_trash = (dest_id == trash_id) || model->isObjectDescendentOf(dest_id, trash_id);
+        const BOOL move_is_into_my_outfits = (dest_id == my_outifts_id) || model->isObjectDescendentOf(dest_id, my_outifts_id);
+        const BOOL move_is_into_outfit = move_is_into_my_outfits || (dest_cat && dest_cat->getPreferredType()==LLFolderType::FT_OUTFIT);
+        const BOOL move_is_into_current_outfit = (dest_cat && dest_cat->getPreferredType()==LLFolderType::FT_CURRENT_OUTFIT);
+        const BOOL move_is_into_landmarks = (dest_id == landmarks_id) || model->isObjectDescendentOf(dest_id, landmarks_id);
+        const BOOL move_is_into_lost_and_found = model->isObjectDescendentOf(dest_id, lost_and_found_id);
+
+        //--------------------------------------------------------------------------------
+        // Determine if folder can be moved.
+        //
+
+        BOOL is_movable = TRUE;
+
+        if (is_movable && (marketplacelistings_id == cat_id))
+        {
+            is_movable = FALSE;
+            tooltip_msg = LLTrans::getString("TooltipOutboxCannotMoveRoot");
+        }
+        if (is_movable && move_is_from_marketplacelistings)
+            //&& LLMarketplaceData::instance().getActivationState(cat_id))
+        {
+            // If the incoming folder is listed and active (and is therefore either the listing or the version folder),
+            // then moving is *not* allowed
+            is_movable = FALSE;
+            tooltip_msg = LLTrans::getString("TooltipOutboxDragActive");
+        }
+        if (is_movable && (dest_id == cat_id))
+        {
+            is_movable = FALSE;
+            tooltip_msg = LLTrans::getString("TooltipDragOntoSelf");
+        }
+        if (is_movable && (model->isObjectDescendentOf(dest_id, cat_id)))
+        {
+            is_movable = FALSE;
+            tooltip_msg = LLTrans::getString("TooltipDragOntoOwnChild");
+        }
+        if (is_movable && LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
+        {
+            is_movable = FALSE;
+            // tooltip?
+        }
+
+        U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit");
+        if (is_movable && move_is_into_outfit)
+        {
+            if (dest_id == my_outifts_id)
+            {
+                if (source != LLToolDragAndDrop::SOURCE_AGENT || move_is_from_marketplacelistings)
+                {
+                    tooltip_msg = LLTrans::getString("TooltipOutfitNotInInventory");
+                    is_movable = false;
+                }
+                else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear))
+                {
+                    is_movable = true;
+                }
+                else
+                {
+                    tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit");
+                    is_movable = false;
+                }
+            }
+            else if(dest_cat && dest_cat->getPreferredType() == LLFolderType::FT_NONE)
+            {
+                is_movable = ((inv_cat->getPreferredType() == LLFolderType::FT_NONE) || (inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT));
+            }
+            else
+            {
+                is_movable = false;
+            }
+        }
+        if(is_movable && move_is_into_current_outfit && is_link)
+        {
+            is_movable = FALSE;
+        }
+        if (is_movable && move_is_into_lost_and_found)
+        {
+            is_movable = FALSE;
+        }
+        if (is_movable && (dest_id == model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE)))
+        {
+            is_movable = FALSE;
+            // tooltip?
+        }
+        if (is_movable && (dest_cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK))
+        {
+            // One cannot move a folder into a stock folder
+            is_movable = FALSE;
+            // tooltip?
+        }
+        
+        LLInventoryModel::cat_array_t descendent_categories;
+        LLInventoryModel::item_array_t descendent_items;
+        if (is_movable)
+        {
+            model->collectDescendents(cat_id, descendent_categories, descendent_items, FALSE);
+            for (S32 i=0; i < descendent_categories.size(); ++i)
+            {
+                LLInventoryCategory* category = descendent_categories[i];
+                if(LLFolderType::lookupIsProtectedType(category->getPreferredType()))
+                {
+                    // Can't move "special folders" (e.g. Textures Folder).
+                    is_movable = FALSE;
+                    break;
+                }
+            }
+        }
+        if (is_movable
+            && move_is_into_current_outfit
+            && descendent_items.size() > max_items_to_wear)
+        {
+            LLInventoryModel::cat_array_t cats;
+            LLInventoryModel::item_array_t items;
+            LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false);
+            gInventory.collectDescendentsIf(cat_id,
+                cats,
+                items,
+                LLInventoryModel::EXCLUDE_TRASH,
+                not_worn);
+
+            if (items.size() > max_items_to_wear)
+            {
+                // Can't move 'large' folders into current outfit: MAINT-4086
+                is_movable = FALSE;
+                LLStringUtil::format_map_t args;
+                args["AMOUNT"] = llformat("%d", max_items_to_wear);
+                tooltip_msg = LLTrans::getString("TooltipTooManyWearables",args);
+            }
+        }
+        if (is_movable && move_is_into_trash)
+        {
+            for (S32 i=0; i < descendent_items.size(); ++i)
+            {
+                LLInventoryItem* item = descendent_items[i];
+                if (get_is_item_worn(item->getUUID()))
+                {
+                    is_movable = FALSE;
+                    break; // It's generally movable, but not into the trash.
+                }
+            }
+        }
+        if (is_movable && move_is_into_landmarks)
+        {
+            for (S32 i=0; i < descendent_items.size(); ++i)
+            {
+                LLViewerInventoryItem* item = descendent_items[i];
+
+                // Don't move anything except landmarks and categories into Landmarks folder.
+                // We use getType() instead of getActua;Type() to allow links to landmarks and folders.
+                if (LLAssetType::AT_LANDMARK != item->getType() && LLAssetType::AT_CATEGORY != item->getType())
+                {
+                    is_movable = FALSE;
+                    break; // It's generally movable, but not into Landmarks.
+                }
+            }
+        }
+        
+        if (is_movable && move_is_into_marketplacelistings)
+        {
+            const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, dest_id);
+            LLViewerInventoryCategory * dest_folder = dest_cat;
+            S32 bundle_size = (drop ? 1 : LLToolDragAndDrop::instance().getCargoCount());
+            is_movable = can_move_folder_to_marketplace(master_folder, dest_folder, inv_cat, tooltip_msg, bundle_size);
+        }
+
+        //
+        //--------------------------------------------------------------------------------
+
+        accept = is_movable;
+
+        if (accept && drop)
+        {
+            // Dropping in or out of marketplace needs (sometimes) confirmation
+            if (user_confirm && (move_is_from_marketplacelistings || move_is_into_marketplacelistings))
+            {
+                //disable dropping in or out of marketplace for now
+                return FALSE;
+            }
+            // Look for any gestures and deactivate them
+            if (move_is_into_trash)
+            {
+                for (S32 i=0; i < descendent_items.size(); i++)
+                {
+                    LLInventoryItem* item = descendent_items[i];
+                    if (item->getType() == LLAssetType::AT_GESTURE
+                        && LLGestureMgr::instance().isGestureActive(item->getUUID()))
+                    {
+                        LLGestureMgr::instance().deactivateGesture(item->getUUID());
+                    }
+                }
+            }
+
+            if (dest_id == my_outifts_id)
+            {
+                // Category can contains objects,
+                // create a new folder and populate it with links to original objects
+                dropToMyOutfits(inv_cat);
+            }
+            // if target is current outfit folder we use link
+            else if (move_is_into_current_outfit &&
+                (inv_cat->getPreferredType() == LLFolderType::FT_NONE ||
+                inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT))
+            {
+                // traverse category and add all contents to currently worn.
+                BOOL append = true;
+                LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append);
+            }
+            else if (move_is_into_marketplacelistings)
+            {
+                //move_folder_to_marketplacelistings(inv_cat, dest_id);
+            }
+            else
+            {
+                if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX)))
+                {
+                    set_dad_inbox_object(cat_id);
+                }
+
+                // Reparent the folder and restamp children if it's moving
+                // into trash.
+                gInventory.changeCategoryParent(
+                    (LLViewerInventoryCategory*)inv_cat,
+                    dest_id,
+                    move_is_into_trash);
+            }
+            if (move_is_from_marketplacelistings)
+            {
+                //disable dropping in or out of marketplace for now
+                return FALSE;
+                
+                // If we are moving a folder at the listing folder level (i.e. its parent is the marketplace listings folder)
+                /*if (from_folder_uuid == marketplacelistings_id)
+                {
+                    // Clear the folder from the marketplace in case it is a listing folder
+                    if (LLMarketplaceData::instance().isListed(cat_id))
+                    {
+                        LLMarketplaceData::instance().clearListing(cat_id);
+                    }
+                }
+                else
+                {
+                    // If we move from within an active (listed) listing, checks that it's still valid, if not, unlist
+                    LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
+                    if (version_folder_id.notNull())
+                    {
+                        LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+                            version_folder_id,
+                            [version_folder_id](bool result)
+                        {
+                            if (!result)
+                            {
+                                LLMarketplaceData::instance().activateListing(version_folder_id, false);
+                            }
+                        }
+                        );
+                    }
+                    // In all cases, update the listing we moved from so suffix are updated
+                    update_marketplace_category(from_folder_uuid);
+                }*/
+            }
+        }
+    }
+    else if (LLToolDragAndDrop::SOURCE_WORLD == source)
+    {
+        if (move_is_into_marketplacelistings)
+        {
+            tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+            accept = FALSE;
+        }
+        else
+        {
+            accept = move_inv_category_world_to_agent(cat_id, dest_id, drop);
+        }
+    }
+    else if (LLToolDragAndDrop::SOURCE_LIBRARY == source)
+    {
+        if (move_is_into_marketplacelistings)
+        {
+            tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+            accept = FALSE;
+        }
+        else
+        {
+            // Accept folders that contain complete outfits.
+            accept = move_is_into_current_outfit && LLAppearanceMgr::instance().getCanMakeFolderIntoOutfit(cat_id);
+        }
+
+        if (accept && drop)
+        {
+            LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, true, false);
+        }
+    }
+
+    return accept;
+}
+
+void outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id)
+{
+    LLInventoryModel::cat_array_t* categories;
+    LLInventoryModel::item_array_t* items;
+    gInventory.getDirectDescendentsOf(cat_source_id, categories, items);
+
+    LLInventoryObject::const_object_list_t link_array;
+
+
+    LLInventoryModel::item_array_t::iterator iter = items->begin();
+    LLInventoryModel::item_array_t::iterator end = items->end();
+    while (iter!=end)
+    {
+        const LLViewerInventoryItem* item = (*iter);
+        // By this point everything is supposed to be filtered,
+        // but there was a delay to create folder so something could have changed
+        LLInventoryType::EType inv_type = item->getInventoryType();
+        if ((inv_type == LLInventoryType::IT_WEARABLE) ||
+            (inv_type == LLInventoryType::IT_GESTURE) ||
+            (inv_type == LLInventoryType::IT_ATTACHMENT) ||
+            (inv_type == LLInventoryType::IT_OBJECT) ||
+            (inv_type == LLInventoryType::IT_SNAPSHOT) ||
+            (inv_type == LLInventoryType::IT_TEXTURE))
+        {
+            link_array.push_back(LLConstPointer<LLInventoryObject>(item));
+        }
+        iter++;
+    }
+
+    if (!link_array.empty())
+    {
+        LLPointer<LLInventoryCallback> cb = NULL;
+        link_inventory_array(cat_dest_id, link_array, cb);
+    }
+}
+
+void dropToMyOutfits(LLInventoryCategory* inv_cat)
+{
+    // make a folder in the My Outfits directory.
+    const LLUUID dest_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+    // Note: creation will take time, so passing folder id to callback is slightly unreliable,
+    // but so is collecting and passing descendants' ids
+    inventory_func_type func = boost::bind(&outfitFolderCreatedCallback, inv_cat->getUUID(), _1);
+    gInventory.createNewCategory(dest_id, LLFolderType::FT_OUTFIT, inv_cat->getName(), func, inv_cat->getThumbnailUUID());
+}
+
diff --git a/indra/newview/llinventorygallery.h b/indra/newview/llinventorygallery.h
new file mode 100644
index 0000000000000000000000000000000000000000..9b3f12701fe1d9538cb191b2800477994ad2dd34
--- /dev/null
+++ b/indra/newview/llinventorygallery.h
@@ -0,0 +1,419 @@
+/**
+ * @file llinventorygallery.h
+ * @brief LLInventoryGallery class definition
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLINVENTORYGALLERY_H
+#define LL_LLINVENTORYGALLERY_H
+
+#include "llgesturemgr.h"
+#include "lllistcontextmenu.h"
+#include "llpanel.h"
+#include "llinventoryfilter.h"
+#include "llinventoryobserver.h"
+#include "llinventorymodel.h"
+
+class LLInventoryCategoriesObserver;
+class LLInventoryGalleryItem;
+class LLScrollContainer;
+class LLTextBox;
+class LLThumbnailsObserver;
+class LLGalleryGestureObserver;
+
+class LLInventoryGalleryContextMenu;
+
+typedef boost::function<void()> callback_t;
+
+class LLInventoryGallery : public LLPanel, public LLEditMenuHandler
+{
+public:
+
+    typedef boost::signals2::signal<void(const LLUUID&)> selection_change_signal_t;
+    typedef boost::function<void(const LLUUID&)> selection_change_callback_t;
+    typedef std::deque<LLUUID> selection_deque;
+
+    struct Params
+        : public LLInitParam::Block<Params, LLPanel::Params>
+    {
+        Optional<S32>   row_panel_height;
+        Optional<S32>   row_panel_width_factor;
+        Optional<S32>   gallery_width_factor;
+        Optional<S32>   vertical_gap;
+        Optional<S32>   horizontal_gap;
+        Optional<S32>   item_width;
+        Optional<S32>   item_height;
+        Optional<S32>   item_horizontal_gap;
+        Optional<S32>   items_in_row;
+
+        Params();
+    };
+
+    static const LLInventoryGallery::Params& getDefaultParams();
+
+    LLInventoryGallery(const LLInventoryGallery::Params& params = getDefaultParams());
+    ~LLInventoryGallery();
+
+    BOOL postBuild() override;
+    void initGallery();
+    void draw() override;
+    void onVisibilityChange(BOOL new_visibility) override;
+    BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type,
+                           void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) override;
+    void startDrag();
+    BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override;
+    BOOL handleKeyHere(KEY key, MASK mask) override;
+    void moveUp(MASK mask);
+    void moveDown(MASK mask);
+    void moveLeft(MASK mask);
+    void moveRight(MASK mask);
+    void toggleSelectionRange(S32 start_idx, S32 end_idx);
+    void toggleSelectionRangeFromLast(const LLUUID target);
+
+    void onFocusLost() override;
+    void onFocusReceived() override;
+
+    void setFilterSubString(const std::string& string);
+    std::string getFilterSubString() { return mFilterSubString; }
+    LLInventoryFilter& getFilter() const { return *mFilter; }
+    bool checkAgainstFilterType(const LLUUID& object_id);
+
+    void getCurrentCategories(uuid_vec_t& vcur);
+    bool updateAddedItem(LLUUID item_id); // returns true if added item is visible
+    void updateRemovedItem(LLUUID item_id);
+    void updateChangedItemName(LLUUID item_id, std::string name);
+    void updateItemThumbnail(LLUUID item_id);
+    void updateWornItem(LLUUID item_id, bool is_worn);
+
+    void updateMessageVisibility();
+
+    void setRootFolder(const LLUUID cat_id);
+    void updateRootFolder();
+    LLUUID getRootFolder() { return mFolderID; }
+    bool isRootDirty() { return mRootDirty; }
+    boost::signals2::connection setRootChangedCallback(callback_t cb);
+    void onForwardFolder();
+    void onBackwardFolder();
+    void clearNavigationHistory();
+    bool isBackwardAvailable();
+    bool isForwardAvailable();
+
+    void setNavBackwardList(std::list<LLUUID> backward_list) { mBackwardFolders = backward_list; }
+    void setNavForwardList(std::list<LLUUID> forward_list) { mForwardFolders = forward_list; }
+    std::list<LLUUID> getNavBackwardList() { return mBackwardFolders; }
+    std::list<LLUUID> getNavForwardList() { return mForwardFolders; }
+
+    LLUUID getOutfitImageID(LLUUID outfit_id);
+
+    void refreshList(const LLUUID& category_id);
+    void onCOFChanged();
+    void onGesturesChanged();
+    void computeDifference(const LLInventoryModel::cat_array_t vcats, const LLInventoryModel::item_array_t vitems, uuid_vec_t& vadded, uuid_vec_t& vremoved);
+
+    void deselectItem(const LLUUID& category_id);
+    void clearSelection();
+    void changeItemSelection(const LLUUID& item_id, bool scroll_to_selection = false);
+    void addItemSelection(const LLUUID& item_id, bool scroll_to_selection = false);
+    bool toggleItemSelection(const LLUUID& item_id, bool scroll_to_selection = false);
+    void scrollToShowItem(const LLUUID& item_id);
+    void signalSelectionItemID(const LLUUID& category_id);
+    boost::signals2::connection setSelectionChangeCallback(selection_change_callback_t cb);
+    LLUUID getFirstSelectedItemID();
+
+    void setSearchType(LLInventoryFilter::ESearchType type);
+    LLInventoryFilter::ESearchType getSearchType() { return mSearchType; }
+
+    bool areViewsInitialized();
+    bool hasDescendents(const LLUUID& cat_id);
+    bool hasVisibleItems();
+    void handleModifiedFilter();
+    LLScrollContainer* getScrollableContainer() { return mScrollPanel; }
+    LLInventoryGalleryItem* getFirstSelectedItem();
+
+    // Copy & paste (LLEditMenuHandler)
+    void	copy() override;
+    BOOL	canCopy() const override;
+
+    void	cut() override;
+    BOOL	canCut() const override;
+
+    void paste() override;
+    BOOL canPaste() const override;
+
+    // Copy & paste & delete
+    static void onDelete(const LLSD& notification, const LLSD& response, const selection_deque selected_ids);
+    void deleteSelection();
+    bool canDeleteSelection();
+    void pasteAsLink();
+
+    void setSortOrder(U32 order, bool update = false);
+    U32 getSortOrder() { return mSortOrder; };
+
+    void claimEditHandler();
+    void resetEditHandler();
+    static bool isItemCopyable(const LLUUID & item_id);
+
+    BOOL baseHandleDragAndDrop(LLUUID dest_id, BOOL drop, EDragAndDropType cargo_type,
+                               void* cargo_data, EAcceptance* accept, std::string& tooltip_msg);
+
+    void showContextMenu(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& item_id);
+
+protected:
+    void paste(const LLUUID& dest,
+               std::vector<LLUUID>& objects,
+               bool is_cut_mode,
+               const LLUUID& marketplacelistings_id);
+    void pasteAsLink(const LLUUID& dest,
+                     std::vector<LLUUID>& objects,
+                     const LLUUID& current_outfit_id,
+                     const LLUUID& marketplacelistings_id,
+                     const LLUUID& my_outifts_id);
+
+    bool applyFilter(LLInventoryGalleryItem* item, const std::string& filter_substring);
+    bool checkAgainstFilters(LLInventoryGalleryItem* item, const std::string& filter_substring);
+    static void onIdle(void* userdata);
+    void dirtyRootFolder();
+
+    LLInventoryCategoriesObserver*     mCategoriesObserver;
+    LLThumbnailsObserver*              mThumbnailsObserver;
+    LLGalleryGestureObserver*          mGestureObserver;
+    LLInventoryObserver*               mInventoryObserver;
+    selection_deque                    mSelectedItemIDs;
+    selection_deque                    mItemsToSelect;
+    LLUUID                             mLastInteractedUUID;
+    bool                               mIsInitialized;
+    bool                               mRootDirty;
+
+    selection_change_signal_t        mSelectionChangeSignal;
+    boost::signals2::signal<void()>  mRootChangedSignal;
+    LLUUID mFolderID;
+    std::list<LLUUID> mBackwardFolders;
+    std::list<LLUUID> mForwardFolders;
+
+private:
+    void addToGallery(LLInventoryGalleryItem* item);
+    void removeFromGalleryLast(LLInventoryGalleryItem* item, bool needs_reshape = true);
+    void removeFromGalleryMiddle(LLInventoryGalleryItem* item);
+    LLPanel* addLastRow();
+    void removeLastRow();
+    void moveRowUp(int row);
+    void moveRowDown(int row);
+    void moveRow(int row, int pos);
+    LLPanel* addToRow(LLPanel* row_stack, LLInventoryGalleryItem* item, int pos, int hgap);
+    void removeFromLastRow(LLInventoryGalleryItem* item);
+    void reArrangeRows(S32 row_diff = 0);
+    bool updateRowsIfNeeded();
+    void updateGalleryWidth();
+
+    LLInventoryGalleryItem* buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, time_t creation_date, bool is_link, bool is_worn);
+
+    void buildGalleryPanel(int row_count);
+    void reshapeGalleryPanel(int row_count);
+    LLPanel* buildItemPanel(int left);
+    LLPanel* buildRowPanel(int left, int bottom);
+    void moveRowPanel(LLPanel* stack, int left, int bottom);
+
+    std::vector<LLPanel*> mRowPanels;
+    std::vector<LLPanel*> mItemPanels;
+    std::vector<LLPanel*> mUnusedRowPanels;
+    std::vector<LLPanel*> mUnusedItemPanels;
+    std::vector<LLInventoryGalleryItem*> mItems;
+    std::vector<LLInventoryGalleryItem*> mHiddenItems;
+    LLScrollContainer* mScrollPanel;
+    LLPanel* mGalleryPanel;
+    LLPanel* mLastRowPanel;
+    LLTextBox* mMessageTextBox;
+    int mRowCount;
+    int mItemsAddedCount;
+    bool mGalleryCreated;
+    bool mNeedsArrange;
+
+    /* Params */
+    int mRowPanelHeight;
+    int mVerticalGap;
+    int mHorizontalGap;
+    int mItemWidth;
+    int mItemHeight;
+    int mItemHorizontalGap;
+    int mItemsInRow;
+    int mRowPanelWidth;
+    int mGalleryWidth;
+    int mRowPanWidthFactor;
+    int mGalleryWidthFactor;
+
+    LLInventoryGalleryContextMenu* mInventoryGalleryMenu;
+    LLInventoryGalleryContextMenu* mRootGalleryMenu;
+    std::string mFilterSubString;
+    LLInventoryFilter* mFilter;
+    U32 mSortOrder;
+
+    typedef std::map<LLUUID, LLInventoryGalleryItem*> gallery_item_map_t;
+    gallery_item_map_t mItemMap;
+    uuid_vec_t mCOFLinkedItems;
+    uuid_vec_t mActiveGestures;
+    uuid_set_t mItemBuildQuery;
+    std::map<LLInventoryGalleryItem*, S32> mItemIndexMap;
+    std::map<S32, LLInventoryGalleryItem*> mIndexToItemMap;
+
+    LLInventoryFilter::ESearchType mSearchType;
+    std::string mUsername;
+};
+
+class LLInventoryGalleryItem : public LLPanel
+{
+public:
+    struct Params : public LLInitParam::Block<Params, LLPanel::Params>
+    {};
+
+    enum EInventorySortGroup
+    {
+        SG_SYSTEM_FOLDER,
+        SG_TRASH_FOLDER,
+        SG_NORMAL_FOLDER,
+        SG_ITEM
+    };
+
+    LLInventoryGalleryItem(const Params& p);
+    virtual ~LLInventoryGalleryItem();
+
+    BOOL postBuild();
+    void draw();
+    BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+    BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+    BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
+    BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+    BOOL handleHover(S32 x, S32 y, MASK mask);
+    BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
+                                   EDragAndDropType cargo_type,
+                                   void* cargo_data,
+                                   EAcceptance* accept,
+                                   std::string& tooltip_msg);
+    BOOL handleKeyHere(KEY key, MASK mask);
+
+    void onFocusLost();
+    void onFocusReceived();
+
+    LLFontGL* getTextFont();
+
+    void setItemName(std::string name);
+    bool isSelected() { return mSelected; }
+    void setSelected(bool value);
+    void setWorn(bool value);
+    void setUUID(LLUUID id) {mUUID = id;}
+    LLUUID getUUID() { return mUUID;}
+
+    void setAssetIDStr(std::string asset_id) {mAssetIDStr = asset_id;}
+    std::string getAssetIDStr() { return mAssetIDStr;}
+    void setDescription(std::string desc) {mDesc = desc;}
+    std::string getDescription() { return mDesc;}
+    void setCreatorName(std::string name) {mCreatorName = name;}
+    std::string getCreatorName() { return mCreatorName;}
+    void setCreationDate(time_t date) {mCreationDate = date;}
+    time_t getCreationDate() { return mCreationDate;}
+
+    std::string getItemName() {return mItemName;}
+    std::string getItemNameSuffix() {return mPermSuffix + mWornSuffix;}
+    bool isDefaultImage() {return mDefaultImage;}
+    
+    bool isHidden() {return mHidden;}
+    void setHidden(bool hidden) {mHidden = hidden;}
+
+    void setType(LLAssetType::EType type, LLInventoryType::EType inventory_type, U32 flags, bool is_link);
+    LLAssetType::EType getAssetType() { return mType; }
+    void setThumbnail(LLUUID id);
+    void setGallery(LLInventoryGallery* gallery) { mGallery = gallery; }
+    bool isFolder() { return mIsFolder; }
+    bool isLink() { return mIsLink; }
+    EInventorySortGroup getSortGroup() { return mSortGroup; }
+
+    void updateNameText();
+    
+private:
+    bool isFadeItem();
+
+    LLUUID mUUID;
+    LLTextBox* mNameText;
+    LLPanel* mTextBgPanel;
+    bool     mSelected;
+    bool     mWorn;
+    bool     mDefaultImage;
+    bool     mHidden;
+    bool     mIsFolder;
+    bool     mIsLink;
+    S32      mCutGeneration;
+    bool     mSelectedForCut;
+
+    std::string mAssetIDStr;
+    std::string mDesc;
+    std::string mCreatorName;
+    time_t mCreationDate;
+
+    EInventorySortGroup mSortGroup;
+    LLAssetType::EType mType;
+    std::string mItemName;
+    std::string mWornSuffix;
+    std::string mPermSuffix;
+    LLInventoryGallery* mGallery;
+};
+
+class LLThumbnailsObserver : public LLInventoryObserver
+{
+public:
+    LLThumbnailsObserver(){};
+
+    virtual void changed(U32 mask);
+    bool addItem(const LLUUID& obj_id, callback_t cb);
+    void removeItem(const LLUUID& obj_id);
+
+protected:
+
+    struct LLItemData
+    {
+        LLItemData(const LLUUID& obj_id, const LLUUID& thumbnail_id, callback_t cb)
+            : mItemID(obj_id)
+            , mCallback(cb)
+            , mThumbnailID(thumbnail_id)
+        {}
+
+        callback_t mCallback;
+        LLUUID mItemID;
+        LLUUID mThumbnailID;
+    };
+
+    typedef std::map<LLUUID, LLItemData> item_map_t;
+    typedef item_map_t::value_type item_map_value_t;
+    item_map_t mItemMap;
+};
+
+class LLGalleryGestureObserver : public LLGestureManagerObserver
+{
+public:
+    LLGalleryGestureObserver(LLInventoryGallery* gallery) : mGallery(gallery) {}
+    virtual ~LLGalleryGestureObserver() {}
+    virtual void changed() { mGallery->onGesturesChanged(); }
+
+private:
+    LLInventoryGallery* mGallery;
+};
+
+#endif
diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5f4b816b99b6715cc2be45fbe33ae68b40eef78d
--- /dev/null
+++ b/indra/newview/llinventorygallerymenu.cpp
@@ -0,0 +1,714 @@
+/**
+ * @file llinventorygallerymenu.cpp
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llinventorygallery.h"
+#include "llinventorygallerymenu.h"
+
+#include "llagent.h"
+#include "llappearancemgr.h"
+#include "llavataractions.h"
+#include "llclipboard.h"
+#include "llfloaterreg.h"
+#include "llfloatersidepanelcontainer.h"
+#include "llfloaterworldmap.h"
+#include "llinventorybridge.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h"
+#include "lllandmarkactions.h"
+#include "llmarketplacefunctions.h"
+#include "llmenugl.h"
+#include "llnotificationsutil.h"
+#include "llpreviewtexture.h"
+#include "lltrans.h"
+#include "llviewerfoldertype.h"
+#include "llviewerwindow.h"
+#include "llvoavatarself.h"
+
+LLContextMenu* LLInventoryGalleryContextMenu::createMenu()
+{
+    LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+    LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+
+    registrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryGalleryContextMenu::doToSelected, this, _2));
+    registrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::fileUploadLocation, this, _2));
+    registrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));
+    registrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND));
+
+    std::set<LLUUID> uuids(mUUIDs.begin(), mUUIDs.end());
+    registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery)));
+
+    enable_registrar.add("Inventory.CanSetUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::canSetUploadLocation, this, _2));
+    
+    LLContextMenu* menu = createFromFile("menu_gallery_inventory.xml");
+
+    updateMenuItemsVisibility(menu);
+
+    return menu;
+}
+
+void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata)
+{
+    std::string action = userdata.asString();
+    LLInventoryObject* obj = gInventory.getObject(mUUIDs.front());
+    if(!obj) return;
+
+    if ("open_selected_folder" == action)
+    {
+        mGallery->setRootFolder(mUUIDs.front());
+    }
+    else if ("open_in_new_window" == action)
+    {
+        new_folder_window(mUUIDs.front());
+    }
+    else if ("properties" == action)
+    {
+        show_item_profile(mUUIDs.front());
+    }
+    else if ("restore" == action)
+    {
+        for (LLUUID& selected_id : mUUIDs)
+        {
+            LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id);
+            if (cat)
+            {
+                const LLUUID new_parent = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(cat->getType()));
+                // do not restamp children on restore
+                gInventory.changeCategoryParent(cat, new_parent, false);
+            }
+            else
+            {
+                LLViewerInventoryItem* item = gInventory.getItem(selected_id);
+                if (item)
+                {
+                    bool is_snapshot = (item->getInventoryType() == LLInventoryType::IT_SNAPSHOT);
+
+                    const LLUUID new_parent = gInventory.findCategoryUUIDForType(is_snapshot ? LLFolderType::FT_SNAPSHOT_CATEGORY : LLFolderType::assetTypeToFolderType(item->getType()));
+                    // do not restamp children on restore
+                    gInventory.changeItemParent(item, new_parent, false);
+                }
+            }
+        }
+    }
+    else if ("copy_uuid" == action)
+    {
+        LLViewerInventoryItem* item = gInventory.getItem(mUUIDs.front());
+        if(item)
+        {
+            LLUUID asset_id = item->getProtectedAssetUUID();
+            std::string buffer;
+            asset_id.toString(buffer);
+
+            gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(buffer));
+        }
+    }
+    else if ("purge" == action)
+    {
+        for (LLUUID& selected_id : mUUIDs)
+        {
+            remove_inventory_object(selected_id, NULL);
+        }
+    }
+    else if ("goto" == action)
+    {
+        show_item_original(mUUIDs.front());
+    }
+    else if ("thumbnail" == action)
+    {
+        LLSD data(mUUIDs.front());
+        LLFloaterReg::showInstance("change_item_thumbnail", data);
+    }
+    else if ("cut" == action)
+    {
+        if (mGallery->canCut())
+        {
+            mGallery->cut();
+        }
+    }
+    else if ("paste" == action)
+    {
+        if (mGallery->canPaste())
+        {
+            mGallery->paste();
+        }
+    }
+    else if ("delete" == action)
+    {
+        mGallery->deleteSelection();
+    }
+    else if ("copy" == action)
+    {
+        if (mGallery->canCopy())
+        {
+            mGallery->copy();
+        }
+    }
+    else if ("paste_link" == action)
+    {
+        mGallery->pasteAsLink();
+    }
+    else if ("rename" == action)
+    {
+        rename(mUUIDs.front());
+    }
+    else if ("open" == action || "open_original" == action)
+    {
+        LLViewerInventoryItem* item = gInventory.getItem(mUUIDs.front());
+        if (item)
+        {
+            LLInvFVBridgeAction::doAction(item->getType(), mUUIDs.front(), &gInventory);
+        }
+    }
+    else if ("ungroup_folder_items" == action)
+    {
+        ungroup_folder_items(mUUIDs.front());
+    }
+    else if ("take_off" == action || "detach" == action)
+    {
+        for (LLUUID& selected_id : mUUIDs)
+        {
+            LLAppearanceMgr::instance().removeItemFromAvatar(selected_id);
+        }
+    }
+    else if ("wear_add" == action)
+    {
+        for (LLUUID& selected_id : mUUIDs)
+        {
+            LLAppearanceMgr::instance().wearItemOnAvatar(selected_id, true, false); // Don't replace if adding.
+        }
+    }
+    else if ("wear" == action)
+    {
+        for (LLUUID& selected_id : mUUIDs)
+        {
+            LLAppearanceMgr::instance().wearItemOnAvatar(selected_id, true, true);
+        }
+    }
+    else if ("activate" == action)
+    {
+        for (LLUUID& selected_id : mUUIDs)
+        {
+            LLGestureMgr::instance().activateGesture(selected_id);
+
+            LLViewerInventoryItem* item = gInventory.getItem(selected_id);
+            if (!item) return;
+
+            gInventory.updateItem(item);
+        }
+        gInventory.notifyObservers();
+    }
+    else if ("deactivate" == action)
+    {
+        for (LLUUID& selected_id : mUUIDs)
+        {
+            LLGestureMgr::instance().deactivateGesture(selected_id);
+
+            LLViewerInventoryItem* item = gInventory.getItem(selected_id);
+            if (!item) return;
+
+            gInventory.updateItem(item);
+        }
+        gInventory.notifyObservers();
+    }
+    else if ("replace_links" == action)
+    {
+        LLFloaterReg::showInstance("linkreplace", LLSD(mUUIDs.front()));
+    }
+    else if ("copy_slurl" == action)
+    {
+        boost::function<void(LLLandmark*)> copy_slurl_cb = [](LLLandmark* landmark)
+        {
+            LLVector3d global_pos;
+            landmark->getGlobalPos(global_pos);
+            boost::function<void(std::string& slurl)> copy_slurl_to_clipboard_cb = [](const std::string& slurl)
+            {
+               gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(slurl));
+               LLSD args;
+               args["SLURL"] = slurl;
+               LLNotificationsUtil::add("CopySLURL", args);
+            };
+            LLLandmarkActions::getSLURLfromPosGlobal(global_pos, copy_slurl_to_clipboard_cb, true);
+        };
+        LLLandmark* landmark = LLLandmarkActions::getLandmark(mUUIDs.front(), copy_slurl_cb);
+        if (landmark)
+        {
+            copy_slurl_cb(landmark);
+        }
+    }
+    else if ("about" == action)
+    {
+        LLSD key;
+        key["type"] = "landmark";
+        key["id"] = mUUIDs.front();
+        LLFloaterSidePanelContainer::showPanel("places", key);
+    }
+    else if ("show_on_map" == action)
+    {
+        boost::function<void(LLLandmark*)> show_on_map_cb = [](LLLandmark* landmark)
+        {
+            LLVector3d landmark_global_pos;
+            if (landmark->getGlobalPos(landmark_global_pos))
+            {
+                LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance();
+                if (!landmark_global_pos.isExactlyZero() && worldmap_instance)
+                {
+                    worldmap_instance->trackLocation(landmark_global_pos);
+                    LLFloaterReg::showInstance("world_map", "center");
+                }
+            }
+        };
+        LLLandmark* landmark = LLLandmarkActions::getLandmark(mUUIDs.front(), show_on_map_cb);
+        if(landmark)
+        {
+            show_on_map_cb(landmark);
+        }
+    }
+    else if ("save_as" == action)
+    {
+        LLPreviewTexture* preview_texture = LLFloaterReg::getTypedInstance<LLPreviewTexture>("preview_texture", mUUIDs.front());
+        if (preview_texture)
+        {
+            preview_texture->openToSave();
+            preview_texture->saveAs();
+        }
+    }
+}
+
+void LLInventoryGalleryContextMenu::rename(const LLUUID& item_id)
+{
+    LLInventoryObject* obj = gInventory.getObject(item_id);
+    if (!obj) return;
+
+    LLSD args;
+    args["NAME"] = obj->getName();
+
+    LLSD payload;
+    payload["id"] = mUUIDs.front();
+
+    LLNotificationsUtil::add("RenameItem", args, payload, boost::bind(onRename, _1, _2));
+}
+
+void LLInventoryGalleryContextMenu::onRename(const LLSD& notification, const LLSD& response)
+{
+    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+    if (option != 0) return; // canceled
+
+    std::string new_name = response["new_name"].asString();
+    LLStringUtil::trim(new_name);
+    if (!new_name.empty())
+    {
+        LLUUID id = notification["payload"]["id"].asUUID();
+        
+        LLViewerInventoryCategory* cat = gInventory.getCategory(id);
+        if(cat && (cat->getName() != new_name))
+        {
+            LLSD updates;
+            updates["name"] = new_name;
+            update_inventory_category(cat->getUUID(),updates, NULL);
+            return;
+        }
+        
+        LLViewerInventoryItem* item = gInventory.getItem(id);
+        if(item && (item->getName() != new_name))
+        {
+            LLSD updates;
+            updates["name"] = new_name;
+            update_inventory_item(item->getUUID(),updates, NULL);
+        }
+    }
+}
+
+void LLInventoryGalleryContextMenu::fileUploadLocation(const LLSD& userdata)
+{
+    const std::string param = userdata.asString();
+    if (param == "model")
+    {
+        gSavedPerAccountSettings.setString("ModelUploadFolder", mUUIDs.front().asString());
+    }
+    else if (param == "texture")
+    {
+        gSavedPerAccountSettings.setString("TextureUploadFolder", mUUIDs.front().asString());
+    }
+    else if (param == "sound")
+    {
+        gSavedPerAccountSettings.setString("SoundUploadFolder", mUUIDs.front().asString());
+    }
+    else if (param == "animation")
+    {
+        gSavedPerAccountSettings.setString("AnimationUploadFolder", mUUIDs.front().asString());
+    }
+}
+
+bool LLInventoryGalleryContextMenu::canSetUploadLocation(const LLSD& userdata)
+{
+    if (mUUIDs.size() != 1)
+    {
+        return false;
+    }
+    LLInventoryCategory* cat = gInventory.getCategory(mUUIDs.front());
+    if (!cat)
+    {
+        return false;
+    }
+    return true;
+}
+
+bool is_inbox_folder(LLUUID item_id)
+{
+    const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
+    
+    if (inbox_id.isNull())
+    {
+        return false;
+    }
+    
+    return gInventory.isObjectDescendentOf(item_id, inbox_id);
+}
+
+void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* menu)
+{
+    LLUUID selected_id = mUUIDs.front();
+    LLInventoryObject* obj = gInventory.getObject(selected_id);
+    if (!obj)
+    {
+        return;
+    }
+
+    std::vector<std::string> items;
+    std::vector<std::string> disabled_items;
+
+    bool is_agent_inventory = gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID());
+    bool is_link = obj->getIsLinkType();
+    bool is_folder = (obj->getType() == LLAssetType::AT_CATEGORY);
+    bool is_cof = LLAppearanceMgr::instance().getIsInCOF(selected_id);
+    bool is_inbox = is_inbox_folder(selected_id);
+    bool is_trash = (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH));
+    bool is_in_trash = gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH));
+    bool is_lost_and_found = (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND));
+    bool is_outfits= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS));
+    //bool is_favorites= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE));
+
+    bool is_system_folder = false;
+    LLFolderType::EType folder_type(LLFolderType::FT_NONE);
+    bool has_children = false;
+    bool is_full_perm_item = false;
+    bool is_copyable = false;
+    LLViewerInventoryItem* selected_item = gInventory.getItem(selected_id);
+
+    if(is_folder)
+    {
+        LLInventoryCategory* category = gInventory.getCategory(selected_id);
+        if (category)
+        {
+            folder_type = category->getPreferredType();
+            is_system_folder = LLFolderType::lookupIsProtectedType(folder_type);
+            has_children = (gInventory.categoryHasChildren(selected_id) != LLInventoryModel::CHILDREN_NO);
+        }
+    }
+    else
+    {
+        if (selected_item)
+        {
+            is_full_perm_item = selected_item->getIsFullPerm();
+            is_copyable = selected_item->getPermissions().allowCopyBy(gAgent.getID());
+        }
+    }
+
+    if(!is_link)
+    {
+        items.push_back(std::string("thumbnail"));
+        if (!is_agent_inventory || (is_in_trash && !is_trash))
+        {
+            disabled_items.push_back(std::string("thumbnail"));
+        }
+    }
+
+    if (is_folder)
+    {
+        if(!isRootFolder())
+        {
+            items.push_back(std::string("Copy Separator"));
+
+            items.push_back(std::string("open_in_current_window"));
+            items.push_back(std::string("open_in_new_window"));
+            items.push_back(std::string("Open Folder Separator"));
+        }
+    }
+    else
+    {
+        if (is_agent_inventory && (obj->getType() != LLAssetType::AT_LINK_FOLDER))
+        {
+            items.push_back(std::string("Replace Links"));
+        }
+        if (obj->getType() == LLAssetType::AT_LANDMARK)
+        {
+            items.push_back(std::string("Landmark Separator"));
+            items.push_back(std::string("url_copy"));
+            items.push_back(std::string("About Landmark"));
+            items.push_back(std::string("show_on_map"));
+        }
+    }
+
+    if(is_trash)
+    {
+        items.push_back(std::string("Empty Trash"));
+
+        LLInventoryModel::cat_array_t* cat_array;
+        LLInventoryModel::item_array_t* item_array;
+        gInventory.getDirectDescendentsOf(selected_id, cat_array, item_array);
+        if (0 == cat_array->size() && 0 == item_array->size())
+        {
+            disabled_items.push_back(std::string("Empty Trash"));
+        }
+    }
+    else if(is_in_trash)
+    {
+        if (is_link)
+        {
+            items.push_back(std::string("Find Original"));
+            if (LLAssetType::lookupIsLinkType(obj->getType()))
+            {
+                disabled_items.push_back(std::string("Find Original"));
+            }
+        }
+        items.push_back(std::string("Purge Item"));
+        if (is_folder && !get_is_category_removable(&gInventory, selected_id))
+        {
+            disabled_items.push_back(std::string("Purge Item"));
+        }
+        items.push_back(std::string("Restore Item"));
+    }
+    else
+    {
+        if(can_share_item(selected_id))
+        {
+            items.push_back(std::string("Share"));
+        }
+        if (LLClipboard::instance().hasContents() && is_agent_inventory && !is_cof && !is_inbox_folder(selected_id))
+        {
+            items.push_back(std::string("Paste"));
+
+            static LLCachedControl<bool> inventory_linking(gSavedSettings, "InventoryLinking", true);
+            if (inventory_linking)
+            {
+                items.push_back(std::string("Paste As Link"));
+            }
+        }
+        if (is_folder && is_agent_inventory)
+        {
+            if (!is_cof && (folder_type != LLFolderType::FT_OUTFIT) && !is_outfits && !is_inbox_folder(selected_id))
+            {
+                if (!gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD)) && !isRootFolder())
+                {
+                    items.push_back(std::string("New Folder"));
+                }
+                items.push_back(std::string("upload_def"));
+            }
+
+            if(is_outfits && !isRootFolder())
+            {
+                items.push_back(std::string("New Outfit"));
+            }
+
+            items.push_back(std::string("Subfolder Separator"));
+            if (!is_system_folder && !isRootFolder())
+            {
+                if(has_children && (folder_type != LLFolderType::FT_OUTFIT))
+                {
+                    items.push_back(std::string("Ungroup folder items"));
+                }
+                items.push_back(std::string("Cut"));
+                items.push_back(std::string("Delete"));
+                if(!get_is_category_removable(&gInventory, selected_id))
+                {
+                    disabled_items.push_back(std::string("Delete"));
+                    disabled_items.push_back(std::string("Cut"));
+                }
+
+                if(!is_inbox)
+                {
+                    items.push_back(std::string("Rename"));
+                }
+            }
+            if(!is_system_folder)
+            {
+                items.push_back(std::string("Copy"));
+            }
+        }
+        else if(!is_folder)
+        {
+            items.push_back(std::string("Properties"));
+            items.push_back(std::string("Copy Asset UUID"));
+            items.push_back(std::string("Copy Separator"));
+
+            bool is_asset_knowable = is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(obj->getType());
+            if ( !is_asset_knowable // disable menu item for Inventory items with unknown asset. EXT-5308
+                 || (! ( is_full_perm_item || gAgent.isGodlike())))
+            {
+                disabled_items.push_back(std::string("Copy Asset UUID"));
+            }
+            if(is_agent_inventory)
+            {
+                items.push_back(std::string("Cut"));
+                if (!is_link || !is_cof || !get_is_item_worn(selected_id))
+                {
+                    items.push_back(std::string("Delete"));
+                }
+                if(!get_is_item_removable(&gInventory, selected_id))
+                {
+                    disabled_items.push_back(std::string("Delete"));
+                    disabled_items.push_back(std::string("Cut"));
+                }
+
+                if (selected_item && (selected_item->getInventoryType() != LLInventoryType::IT_CALLINGCARD) && !is_inbox && selected_item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()))
+                {
+                    items.push_back(std::string("Rename"));
+                }
+            }
+            items.push_back(std::string("Copy"));
+            if (!is_copyable)
+            {
+                disabled_items.push_back(std::string("Copy"));
+            }
+        }
+        if((obj->getType() == LLAssetType::AT_SETTINGS)
+           || ((obj->getType() <= LLAssetType::AT_GESTURE)
+               && obj->getType() != LLAssetType::AT_OBJECT
+               && obj->getType() != LLAssetType::AT_CLOTHING
+               && obj->getType() != LLAssetType::AT_CATEGORY
+               && obj->getType() != LLAssetType::AT_LANDMARK
+               && obj->getType() != LLAssetType::AT_BODYPART))
+        {
+            bool can_open = !LLAssetType::lookupIsLinkType(obj->getType());
+
+            if (can_open)
+            {
+                if (is_link)
+                    items.push_back(std::string("Open Original"));
+                else
+                    items.push_back(std::string("Open"));
+            }
+            else
+            {
+                disabled_items.push_back(std::string("Open"));
+                disabled_items.push_back(std::string("Open Original"));
+            }
+            
+            if(LLAssetType::AT_GESTURE == obj->getType())
+            {
+                items.push_back(std::string("Gesture Separator"));
+                if(!LLGestureMgr::instance().isGestureActive(selected_id))
+                {
+                    items.push_back(std::string("Activate"));
+                }
+                else
+                {
+                    items.push_back(std::string("Deactivate"));
+                }
+            }
+        }
+        else if(LLAssetType::AT_LANDMARK == obj->getType())
+        {
+            items.push_back(std::string("Landmark Open"));
+        }
+        else if (obj->getType() == LLAssetType::AT_OBJECT || obj->getType() == LLAssetType::AT_CLOTHING || obj->getType() == LLAssetType::AT_BODYPART)
+        {
+            items.push_back(std::string("Wearable And Object Separator"));
+            if(obj->getType() == LLAssetType::AT_CLOTHING)
+            {
+                items.push_back(std::string("Take Off"));
+            }
+            if(get_is_item_worn(selected_id))
+            {
+                if(obj->getType() == LLAssetType::AT_OBJECT)
+                {
+                    items.push_back(std::string("Detach From Yourself"));
+                }
+                disabled_items.push_back(std::string("Wearable And Object Wear"));
+                disabled_items.push_back(std::string("Wearable Add"));
+            }
+            else
+            {
+                if(obj->getType() == LLAssetType::AT_OBJECT)
+                {
+                    items.push_back(std::string("Wearable Add"));
+                }
+                items.push_back(std::string("Wearable And Object Wear"));
+                disabled_items.push_back(std::string("Take Off"));
+            }
+
+            if (!gAgentAvatarp->canAttachMoreObjects() && (obj->getType() == LLAssetType::AT_OBJECT))
+            {
+                disabled_items.push_back(std::string("Wearable And Object Wear"));
+                disabled_items.push_back(std::string("Wearable Add"));
+            }
+            if (selected_item && (obj->getType() != LLAssetType::AT_OBJECT) && LLWearableType::getInstance()->getAllowMultiwear(selected_item->getWearableType()))
+            {
+                items.push_back(std::string("Wearable Add"));
+                if (!gAgentWearables.canAddWearable(selected_item->getWearableType()))
+                {
+                    disabled_items.push_back(std::string("Wearable Add"));
+                }
+            }
+        }
+        if(obj->getType() == LLAssetType::AT_TEXTURE)
+        {
+            items.push_back(std::string("Save As"));
+            bool can_copy = selected_item && selected_item->checkPermissionsSet(PERM_ITEM_UNRESTRICTED);
+            if (!can_copy)
+            {
+                disabled_items.push_back(std::string("Save As"));
+            }
+        }
+        if (is_link)
+        {
+            items.push_back(std::string("Find Original"));
+            if (LLAssetType::lookupIsLinkType(obj->getType()))
+            {
+                disabled_items.push_back(std::string("Find Original"));
+            }
+        }
+        if (is_lost_and_found)
+        {
+            items.push_back(std::string("Empty Lost And Found"));
+
+            LLInventoryModel::cat_array_t* cat_array;
+            LLInventoryModel::item_array_t* item_array;
+            gInventory.getDirectDescendentsOf(selected_id, cat_array, item_array);
+            // Enable Empty menu item only when there is something to act upon.
+            if (0 == cat_array->size() && 0 == item_array->size())
+            {
+                disabled_items.push_back(std::string("Empty Lost And Found"));
+            }
+
+            disabled_items.push_back(std::string("New Folder"));
+            disabled_items.push_back(std::string("upload_def"));
+        }
+    }
+
+    hide_context_entries(*menu, items, disabled_items);
+}
+
diff --git a/indra/newview/llinventorygallerymenu.h b/indra/newview/llinventorygallerymenu.h
new file mode 100644
index 0000000000000000000000000000000000000000..7c3545432b1d3797c77366036bf778bbc4d6beca
--- /dev/null
+++ b/indra/newview/llinventorygallerymenu.h
@@ -0,0 +1,62 @@
+/**
+ * @file llinventorygallerymenu.h
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLINVENTORYGALLERYMENU_H
+#define LL_LLINVENTORYGALLERYMENU_H
+
+#include "lllistcontextmenu.h"
+
+class LLInventoryGalleryContextMenu : public LLListContextMenu
+{
+public:
+    LLInventoryGalleryContextMenu(LLInventoryGallery* gallery)
+    : LLListContextMenu(),
+    mGallery(gallery),
+    mRootFolder(false){}
+    /*virtual*/ LLContextMenu* createMenu();
+
+    bool isRootFolder() { return mRootFolder; }
+    void setRootFolder(bool is_root) { mRootFolder = is_root; }
+    void doToSelected(const LLSD& userdata);
+    void rename(const LLUUID& item_id);
+
+protected:
+    //virtual void buildContextMenu(class LLMenuGL& menu, U32 flags);
+    void updateMenuItemsVisibility(LLContextMenu* menu);
+
+    void fileUploadLocation(const LLSD& userdata);
+    bool canSetUploadLocation(const LLSD& userdata);
+
+    static void onRename(const LLSD& notification, const LLSD& response);
+
+private:
+    bool enableContextMenuItem(const LLSD& userdata);
+    bool checkContextMenuItem(const LLSD& userdata);
+
+    LLInventoryGallery* mGallery;
+    bool mRootFolder;
+};
+
+#endif
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index d30329f68b0e32faf4c0130f5c5e8fb10ec69aa9..751558f7013b11788444190db5983be4297525f2 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -37,9 +37,11 @@
 #include "llappearancemgr.h"
 #include "llavatarnamecache.h"
 #include "llclipboard.h"
+#include "lldispatcher.h"
 #include "llinventorypanel.h"
 #include "llinventorybridge.h"
 #include "llinventoryfunctions.h"
+#include "llinventorymodelbackgroundfetch.h"
 #include "llinventoryobserver.h"
 #include "llinventorypanel.h"
 #include "llfloaterpreviewtrash.h"
@@ -49,6 +51,7 @@
 #include "llviewercontrol.h"
 #include "llviewernetwork.h"
 #include "llpreview.h" 
+#include "llviewergenericmessage.h"
 #include "llviewermessage.h"
 #include "llviewerfoldertype.h"
 #include "llviewerwindow.h"
@@ -80,9 +83,11 @@
 
 // Increment this if the inventory contents change in a non-backwards-compatible way.
 // For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect.
-const S32 LLInventoryModel::sCurrentInvCacheVersion = 2;
+const S32 LLInventoryModel::sCurrentInvCacheVersion = 3;
 BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE;
 
+S32 LLInventoryModel::sPendingSystemFolders = 0;
+
 ///----------------------------------------------------------------------------
 /// Local function declarations, constants, enums, and typedefs
 ///----------------------------------------------------------------------------
@@ -139,6 +144,222 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 	return rv;
 }
 
+struct InventoryCallbackInfo
+{
+    InventoryCallbackInfo(U32 callback, const LLUUID& inv_id) :
+        mCallback(callback), mInvID(inv_id) {}
+    U32 mCallback;
+    LLUUID mInvID;
+};
+
+///----------------------------------------------------------------------------
+/// Class LLDispatchClassifiedClickThrough
+///----------------------------------------------------------------------------
+
+class LLDispatchBulkUpdateInventory : public LLDispatchHandler
+{
+public:
+    virtual bool operator()(
+        const LLDispatcher* dispatcher,
+        const std::string& key,
+        const LLUUID& invoice,
+        const sparam_t& strings)
+    {
+        LLSD message;
+
+        // Expect single string parameter in the form of a notation serialized LLSD.
+        sparam_t::const_iterator it = strings.begin();
+        if (it != strings.end()) {
+            const std::string& llsdRaw = *it++;
+            std::istringstream llsdData(llsdRaw);
+            if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length()))
+            {
+                LL_WARNS() << "LLDispatchBulkUpdateInventory: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL;
+            }
+        }
+
+        LLInventoryModel::update_map_t update;
+        LLInventoryModel::cat_array_t folders;
+        LLInventoryModel::item_array_t items;
+        std::list<InventoryCallbackInfo> cblist;
+        uuid_vec_t wearable_ids;
+
+        LLSD item_data = message["item_data"];
+        if (item_data.isArray())
+        {
+            for (LLSD::array_iterator itd = item_data.beginArray(); itd != item_data.endArray(); ++itd)
+            {
+                const LLSD &item(*itd);
+
+                // Agent id probably should be in the root of the message
+                LLUUID agent_id = item["agent_id"].asUUID();
+                if (agent_id != gAgent.getID())
+                {
+                    LL_WARNS() << "Got a BulkUpdateInventory for the wrong agent." << LL_ENDL;
+                    return false;
+                }
+
+                LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
+                titem->unpackMessage(item);
+                LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in "
+                    << titem->getParentUUID() << LL_ENDL;
+                // callback id might be no longer supported
+                U32 callback_id = item["callback_id"].asInteger();
+
+                if (titem->getUUID().notNull())
+                {
+                    items.push_back(titem);
+                    cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID()));
+                    if (titem->getInventoryType() == LLInventoryType::IT_WEARABLE)
+                    {
+                        wearable_ids.push_back(titem->getUUID());
+                    }
+
+                    // examine update for changes.
+                    LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID());
+                    if (itemp)
+                    {
+                        if (titem->getParentUUID() == itemp->getParentUUID())
+                        {
+                            update[titem->getParentUUID()];
+                        }
+                        else
+                        {
+                            ++update[titem->getParentUUID()];
+                            --update[itemp->getParentUUID()];
+                        }
+                    }
+                    else
+                    {
+                        LLViewerInventoryCategory* folderp = gInventory.getCategory(titem->getParentUUID());
+                        if (folderp)
+                        {
+                            ++update[titem->getParentUUID()];
+                        }
+                    }
+                }
+                else
+                {
+                    cblist.push_back(InventoryCallbackInfo(callback_id, LLUUID::null));
+                }
+            }
+        }
+
+        LLSD folder_data = message["folder_data"];
+        if (folder_data.isArray())
+        {
+            for (LLSD::array_iterator itd = folder_data.beginArray(); itd != folder_data.endArray(); ++itd)
+            {
+                const LLSD &folder(*itd);
+
+                LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());
+                tfolder->unpackMessage(folder);
+
+                LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' ("
+                        << tfolder->getUUID() << ") in " << tfolder->getParentUUID()
+                        << LL_ENDL;
+
+                // If the folder is a listing or a version folder, all we need to do is update the SLM data
+                int depth_folder = depth_nesting_in_marketplace(tfolder->getUUID());
+                if ((depth_folder == 1) || (depth_folder == 2))
+                {
+                    // Trigger an SLM listing update
+                    LLUUID listing_uuid = (depth_folder == 1 ? tfolder->getUUID() : tfolder->getParentUUID());
+                    S32 listing_id = LLMarketplaceData::instance().getListingID(listing_uuid);
+                    LLMarketplaceData::instance().getListing(listing_id);
+                    // In that case, there is no item to update so no callback -> we skip the rest of the update
+                }
+                else if (tfolder->getUUID().notNull())
+                {
+                    folders.push_back(tfolder);
+                    LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID());
+                    if (folderp)
+                    {
+                        if (tfolder->getParentUUID() == folderp->getParentUUID())
+                        {
+                            update[tfolder->getParentUUID()];
+                        }
+                        else
+                        {
+                            ++update[tfolder->getParentUUID()];
+                            --update[folderp->getParentUUID()];
+                        }
+                    }
+                    else
+                    {
+                        // we could not find the folder, so it is probably
+                        // new. However, we only want to attempt accounting
+                        // for the parent if we can find the parent.
+                        folderp = gInventory.getCategory(tfolder->getParentUUID());
+                        if (folderp)
+                        {
+                            ++update[tfolder->getParentUUID()];
+                        }
+                    }
+                }
+            }
+        }
+
+        gInventory.accountForUpdate(update);
+
+        for (LLInventoryModel::cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit)
+        {
+            gInventory.updateCategory(*cit);
+        }
+        for (LLInventoryModel::item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit)
+        {
+            gInventory.updateItem(*iit);
+        }
+        gInventory.notifyObservers();
+
+        /*
+        Transaction id not included?
+
+        // The incoming inventory could span more than one BulkInventoryUpdate packet,
+        // so record the transaction ID for this purchase, then wear all clothing
+        // that comes in as part of that transaction ID.  JC
+        if (LLInventoryState::sWearNewClothing)
+        {
+            LLInventoryState::sWearNewClothingTransactionID = tid;
+            LLInventoryState::sWearNewClothing = FALSE;
+        }
+
+        if (tid.notNull() && tid == LLInventoryState::sWearNewClothingTransactionID)
+        {
+            count = wearable_ids.size();
+            for (i = 0; i < count; ++i)
+            {
+                LLViewerInventoryItem* wearable_item;
+                wearable_item = gInventory.getItem(wearable_ids[i]);
+                LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true);
+            }
+        }
+        */
+
+        if (LLInventoryState::sWearNewClothing && wearable_ids.size() > 0)
+        {
+            LLInventoryState::sWearNewClothing = FALSE;
+
+            size_t count = wearable_ids.size();
+            for (S32 i = 0; i < count; ++i)
+            {
+                LLViewerInventoryItem* wearable_item;
+                wearable_item = gInventory.getItem(wearable_ids[i]);
+                LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true);
+            }
+        }
+
+        std::list<InventoryCallbackInfo>::iterator inv_it;
+        for (inv_it = cblist.begin(); inv_it != cblist.end(); ++inv_it)
+        {
+            InventoryCallbackInfo cbinfo = (*inv_it);
+            gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID);
+        }
+        return true;
+    }
+};
+static LLDispatchBulkUpdateInventory sBulkUpdateInventory;
+
 ///----------------------------------------------------------------------------
 /// Class LLInventoryValidationInfo
 ///----------------------------------------------------------------------------
@@ -228,6 +449,7 @@ LLInventoryModel::LLInventoryModel()
 	mIsNotifyObservers(FALSE),
 	mModifyMask(LLInventoryObserver::ALL),
 	mChangedItemIDs(),
+    mBulkFecthCallbackSlot(),
 	mObservers(),
 	mHttpRequestFG(NULL),
 	mHttpRequestBG(NULL),
@@ -257,6 +479,11 @@ void LLInventoryModel::cleanupInventory()
 		mObservers.erase(iter);
 		delete observer;
 	}
+
+    if (mBulkFecthCallbackSlot.connected())
+    {
+        mBulkFecthCallbackSlot.disconnect();
+    }
 	mObservers.clear();
 
 	// Run down HTTP transport
@@ -475,6 +702,31 @@ void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id,
 	items = get_ptr_in_map(mParentChildItemTree, cat_id);
 }
 
+void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& categories, item_array_t& items, LLInventoryCollectFunctor& f) const
+{
+    if (cat_array_t* categoriesp = get_ptr_in_map(mParentChildCategoryTree, cat_id))
+    {
+        for (LLViewerInventoryCategory* pFolder : *categoriesp)
+        {
+			if (f(pFolder, nullptr))
+			{
+				categories.push_back(pFolder);
+			}
+        }
+    }
+
+    if (item_array_t* itemsp = get_ptr_in_map(mParentChildItemTree, cat_id))
+    {
+        for (LLViewerInventoryItem* pItem : *itemsp)
+        {
+			if (f(nullptr, pItem))
+			{
+				items.push_back(pItem);
+			}
+        }
+    }
+}
+
 LLInventoryModel::digest_t LLInventoryModel::hashDirectDescendentNames(const LLUUID& cat_id) const
 {
 	LLInventoryModel::cat_array_t* cat_array;
@@ -584,10 +836,77 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E
 	}
 }
 
+void LLInventoryModel::ensureCategoryForTypeExists(LLFolderType::EType preferred_type)
+{
+    LLUUID rv = LLUUID::null;
+    LLUUID root_id = gInventory.getRootFolderID();
+    if (LLFolderType::FT_ROOT_INVENTORY == preferred_type)
+    {
+        rv = root_id;
+    }
+    else if (root_id.notNull())
+    {
+        cat_array_t* cats = NULL;
+        cats = get_ptr_in_map(mParentChildCategoryTree, root_id);
+        if (cats)
+        {
+            S32 count = cats->size();
+            for (S32 i = 0; i < count; ++i)
+            {
+                LLViewerInventoryCategory* p_cat = cats->at(i);
+                if (p_cat && p_cat->getPreferredType() == preferred_type)
+                {
+                    const LLUUID& folder_id = cats->at(i)->getUUID();
+                    if (rv.isNull() || folder_id < rv)
+                    {
+                        rv = folder_id;
+                    }
+                }
+            }
+        }
+    }
+
+    if (rv.isNull() && root_id.notNull())
+    {
+
+        if (isInventoryUsable())
+        {
+            createNewCategory(
+                root_id,
+                preferred_type,
+                LLStringUtil::null,
+                [preferred_type](const LLUUID &new_cat_id)
+            {
+                    if (new_cat_id.isNull())
+                    {
+                        LL_WARNS("Inventory")
+                            << "Failed to create folder of type " << preferred_type
+                            << LL_ENDL;
+                    }
+                    else
+                    {
+                        LL_WARNS("Inventory") << "Created category: " << new_cat_id
+                            << " for type: " << preferred_type << LL_ENDL;
+                        sPendingSystemFolders--;
+                    }
+            }
+            );
+        }
+        else
+        {
+            LL_WARNS("Inventory") << "Can't create requested folder, type " << preferred_type
+                << " because inventory is not usable" << LL_ENDL;
+        }
+    }
+    else
+    {
+        sPendingSystemFolders--;
+    }
+}
+
 const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot(
 	LLFolderType::EType preferred_type,
-	bool create_folder,
-	const LLUUID& root_id)
+	const LLUUID& root_id) const
 {
 	LLUUID rv = LLUUID::null;
 	if(LLFolderType::FT_ROOT_INVENTORY == preferred_type)
@@ -618,20 +937,15 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot(
 	
 	if(rv.isNull() 
        && root_id.notNull()
-       && create_folder
        && preferred_type != LLFolderType::FT_MARKETPLACE_LISTINGS
        && preferred_type != LLFolderType::FT_OUTBOX)
 	{
-
-		if (isInventoryUsable())
-		{
-			return createNewCategory(root_id, preferred_type, LLStringUtil::null);
-		}
-		else
-		{
-			LL_WARNS("Inventory") << "Can't create requested folder, type " << preferred_type
-								  << " because inventory is not usable" << LL_ENDL;
-		}
+        // if it does not exists, it should either be added
+        // to createCommonSystemCategories or server should
+        // have set it
+        llassert(!isInventoryUsable());
+        LL_WARNS("Inventory") << "Tried to find folder, type " << preferred_type
+								  << " but category does not exist" << LL_ENDL;
 	}
 	return rv;
 }
@@ -673,12 +987,12 @@ const LLUUID LLInventoryModel::findCategoryUUIDForNameInRoot(std::string const&
 // specifies 'type' as what it defaults to containing. The category is
 // not necessarily only for that type. *NOTE: This will create a new
 // inventory category on the fly if one does not exist.
-const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder)
+const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type) const
 {
-	return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getRootFolderID());
+	return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getRootFolderID());
 }
 
-const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type)
+const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type) const
 {
     LLUUID cat_id;
     switch (preferred_type)
@@ -714,14 +1028,14 @@ const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::
     
     if (cat_id.isNull() || !getCategory(cat_id))
     {
-        cat_id = findCategoryUUIDForTypeInRoot(preferred_type, true, getRootFolderID());
+        cat_id = findCategoryUUIDForTypeInRoot(preferred_type, getRootFolderID());
     }
     return cat_id;
 }
 
-const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder)
+const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type) const
 {
-	return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getLibraryRootFolderID());
+	return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getLibraryRootFolderID());
 }
 
 const LLUUID LLInventoryModel::findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string& name) const
@@ -746,27 +1060,33 @@ const LLUUID LLInventoryModel::findDescendentCategoryIDByName(const LLUUID& pare
 // Convenience function to create a new category. You could call
 // updateCategory() with a newly generated UUID category, but this
 // version will take care of details like what the name should be
-// based on preferred type. Returns the UUID of the new category.
-LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
+// based on preferred type.
+void LLInventoryModel::createNewCategory(const LLUUID& parent_id,
 										   LLFolderType::EType preferred_type,
 										   const std::string& pname,
-										   inventory_func_type callback)
+										   inventory_func_type callback,
+										   const LLUUID& thumbnail_id)
 {
 	LL_DEBUGS(LOG_INV) << "Create '" << pname << "' in '" << make_inventory_path(parent_id) << "'" << LL_ENDL;
-	LLUUID id;
 	if (!isInventoryUsable())
 	{
 		LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type "
 						  << preferred_type << LL_ENDL;
-		// FIXME failing but still returning an id?
-		return id;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
+		return;
 	}
 
 	if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup())
 	{
 		LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL;
-		// FIXME failing but still returning an id?
-		return id;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
+		return;
 	}
 
 	if (preferred_type != LLFolderType::FT_NONE && preferred_type != LLFolderType::FT_LOCAL)
@@ -777,13 +1097,8 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
 		LL_WARNS(LOG_INV) << "Creating new system folder, type " << preferred_type << LL_ENDL;
 	}
 
-	id.generate();
 	std::string name = pname;
-	if(!pname.empty())
-	{
-		name.assign(pname);
-	}
-	else
+	if (pname.empty())
 	{
 		name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type));
 	}
@@ -791,26 +1106,82 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
 	// Local Inventory is local as such, finish up before server comms.
     if (preferred_type == LLFolderType::FT_LOCAL || parent_id.isNull() || parent_id == gLocalInventory)
     {
+		LLUUID id;
+		id.generate();
         LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID());
         cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1);  // accountForUpdate() will increase version by 1
         cat->setDescendentCount(0);
         LLCategoryUpdate update(cat->getParentUUID(), 1);
         accountForUpdate(update);
         updateCategory(cat);
+		if (callback)
+		{
+			callback(id);
+		}
+		return;
+	}
+	
+	// back to our regularly scheduled programming
+	if (AISAPI::isAvailable())
+	{
+		LLSD new_inventory = LLSD::emptyMap();
+		new_inventory["categories"] = LLSD::emptyArray();
+		LLViewerInventoryCategory cat(LLUUID::null, parent_id, preferred_type, name, gAgent.getID());
+        cat.setThumbnailUUID(thumbnail_id);
+		LLSD cat_sd = cat.asAISCreateCatLLSD();
+		new_inventory["categories"].append(cat_sd);
+		AISAPI::CreateInventory(
+            parent_id,
+            new_inventory,
+            [this, callback, parent_id, preferred_type, name] (const LLUUID& new_category)
+        {
+            if (new_category.isNull())
+            {
+                if (callback && !callback.empty())
+                {
+                    callback(new_category);
+                }
+                return;
+            }
+
+            // todo: not needed since AIS does the accounting?
+            LLViewerInventoryCategory* folderp = gInventory.getCategory(new_category);
+            if (!folderp)
+            {
+                // Add the category to the internal representation
+                LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(
+                    new_category,
+                    parent_id,
+                    preferred_type,
+                    name,
+                    gAgent.getID());
+
+                LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1);
+                accountForUpdate(update);
+
+                cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1
+                cat->setDescendentCount(0);
+                updateCategory(cat);
+            }
 
-		return id;
+            if (callback && !callback.empty())
+            {
+                callback(new_category);
+            }
+        });
+        return;
 	}
 
-	// back to our regularly scheduled programming
 	LLViewerRegion* viewer_region = gAgent.getRegion();
 	std::string url;
 	if ( viewer_region )
 		url = viewer_region->getCapability("CreateInventoryCategory");
 	
-	if (!url.empty() && callback)
+	if (!url.empty())
 	{
 		//Let's use the new capability.
-		
+        LLUUID id;
+		id.generate();
 		LLSD request, body;
 		body["folder_id"] = id;
 		body["parent_id"] = parent_id;
@@ -823,44 +1194,13 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
 		LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL;
         LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro",
             boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback));
-
-		return LLUUID::null;
-	}
-
-	if (!gMessageSystem)
-	{
-		return LLUUID::null;
+        return;
 	}
 
-	// FIXME this UDP code path needs to be removed. Requires
-	// reworking many of the callers to use callbacks rather than
-	// assuming instant success.
-
-	// Add the category to the internal representation
-	LLPointer<LLViewerInventoryCategory> cat =
-		new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID());
-	cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1
-	cat->setDescendentCount(0);
-	LLCategoryUpdate update(cat->getParentUUID(), 1);
-	accountForUpdate(update);
-	updateCategory(cat);
-
-	LL_DEBUGS(LOG_INV) << "Creating category via UDP message CreateInventoryFolder, type " << preferred_type << LL_ENDL;
-
-	// Create the category on the server. We do this to prevent people
-	// from munging their protected folders.
-	LLMessageSystem* msg = gMessageSystem;
-	msg->newMessageFast(_PREHASH_CreateInventoryFolder);
-	msg->nextBlockFast(_PREHASH_AgentData);
-	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-	msg->nextBlockFast(_PREHASH_FolderData);
-	cat->packMessage(msg);
-	gAgent.sendReliableMessage();
-
-	LL_INFOS(LOG_INV) << "Created new category '" << make_inventory_path(id) << "'" << LL_ENDL;
-	// return the folder id of the newly created folder
-	return id;
+    if (callback)
+    {
+        callback(LLUUID::null); // Notify about failure
+    }
 }
 
 void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inventory_func_type callback)
@@ -884,12 +1224,20 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv
     if (!status)
     {
         LL_WARNS() << "HTTP failure attempting to create category." << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
         return;
     }
 
     if (!result.has("folder_id"))
     {
         LL_WARNS() << "Malformed response contents" << ll_pretty_print_sd(result) << LL_ENDL;
+        if (callback)
+        {
+            callback(LLUUID::null);
+        }
         return;
     }
 
@@ -1444,7 +1792,7 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32
 			mask |= LLInventoryObserver::LABEL;
 		}
         // Under marketplace, category labels are quite complex and need extra upate
-        const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+        const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
         if (marketplace_id.notNull() && isObjectDescendentOf(cat->getUUID(), marketplace_id))
         {
 			mask |= LLInventoryObserver::LABEL;
@@ -1591,17 +1939,25 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat,
 	notifyObservers();
 }
 
-void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLSD& update)
+void LLInventoryModel::rebuildBrockenLinks()
 {
-	LLTimer timer;
-	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
-	{
-		dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
-	}
+    // make sure we aren't adding expensive Rebuild to anything else.
+    notifyObservers();
 
-	AISUpdate ais_update(update); // parse update llsd into stuff to do.
-	ais_update.doUpdate(); // execute the updates in the appropriate order.
-	LL_INFOS(LOG_INV) << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL;
+    for (const broken_links_t::value_type &link_list : mPossiblyBrockenLinks)
+    {
+        for (const LLUUID& link_id : link_list.second)
+        {
+            addChangedMask(LLInventoryObserver::REBUILD , link_id);
+        }
+    }
+    for (const LLUUID& link_id : mLinksRebuildList)
+    {
+        addChangedMask(LLInventoryObserver::REBUILD , link_id);
+    }
+    mPossiblyBrockenLinks.clear();
+    mLinksRebuildList.clear();
+    notifyObservers();
 }
 
 // Does not appear to be used currently.
@@ -1907,6 +2263,20 @@ void LLInventoryModel::idleNotifyObservers()
 {
 	// *FIX:  Think I want this conditional or moved elsewhere...
 	handleResponses(true);
+
+    if (mLinksRebuildList.size() > 0)
+    {
+        if (mModifyMask != LLInventoryObserver::NONE || (mChangedItemIDs.size() != 0))
+        {
+            notifyObservers();
+        }
+        for (const LLUUID& link_id : mLinksRebuildList)
+        {
+            addChangedMask(LLInventoryObserver::REBUILD , link_id);
+        }
+        mLinksRebuildList.clear();
+        notifyObservers();
+    }
 	
 	if (mModifyMask == LLInventoryObserver::NONE && (mChangedItemIDs.size() == 0))
 	{
@@ -2235,10 +2605,52 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item)
 		// The item will show up as a broken link.
 		if (item->getIsBrokenLink())
 		{
-			LL_INFOS(LOG_INV) << "Adding broken link [ name: " << item->getName()
-							  << " itemID: " << item->getUUID()
-							  << " assetID: " << item->getAssetUUID() << " )  parent: " << item->getParentUUID() << LL_ENDL;
+            if (item->getAssetUUID().notNull()
+                && LLInventoryModelBackgroundFetch::getInstance()->folderFetchActive())
+            {
+                // Schedule this link for a recheck as inventory gets loaded
+                // Todo: expand to cover not just an initial fetch
+                mPossiblyBrockenLinks[item->getAssetUUID()].insert(item->getUUID());
+
+                // Do a blank rebuild of links once fetch is done
+                if (!mBulkFecthCallbackSlot.connected())
+                {
+                    // Links might take a while to update this way, and there
+                    // might be a lot of them. A better option might be to check
+                    // links periodically with final check on fetch completion.
+                    mBulkFecthCallbackSlot =
+                        LLInventoryModelBackgroundFetch::getInstance()->setFetchCompletionCallback(
+                            [this]()
+                    {
+                        // rebuild is just in case, primary purpose is to wipe
+                        // the list since we won't be getting anything 'new'
+                        // see mLinksRebuildList
+                        rebuildBrockenLinks();
+                        mBulkFecthCallbackSlot.disconnect();
+                    });
+                }
+                LL_DEBUGS(LOG_INV) << "Scheduling a link to be rebuilt later [ name: " << item->getName()
+                    << " itemID: " << item->getUUID()
+                    << " assetID: " << item->getAssetUUID() << " )  parent: " << item->getParentUUID() << LL_ENDL;
+
+            }
+            else
+            {
+                LL_INFOS(LOG_INV) << "Adding broken link [ name: " << item->getName()
+                    << " itemID: " << item->getUUID()
+                    << " assetID: " << item->getAssetUUID() << " )  parent: " << item->getParentUUID() << LL_ENDL;
+            }
 		}
+        if (!mPossiblyBrockenLinks.empty())
+        {
+            // check if we are waiting for this item
+            broken_links_t::iterator iter = mPossiblyBrockenLinks.find(item->getUUID());
+            if (iter != mPossiblyBrockenLinks.end())
+            {
+                mLinksRebuildList.insert(iter->second.begin() , iter->second.end());
+                mPossiblyBrockenLinks.erase(iter);
+            }
+        }
 		if (item->getIsLinkType())
 		{
 			// Add back-link from linked-to UUID.
@@ -2510,6 +2922,10 @@ bool LLInventoryModel::loadSkeleton(
 				else
 				{
 					cached_ids.insert(tcat->getUUID());
+
+                    // At the moment download does not provide a thumbnail
+                    // uuid, use the one from cache
+                    tcat->setThumbnailUUID(cat->getThumbnailUUID());
 				}
 			}
 
@@ -2801,7 +3217,7 @@ void LLInventoryModel::buildParentChildMap()
 		}
 	}
 
-	const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, FALSE).notNull());
+	const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT).notNull());
 	sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin();
 
 
@@ -2964,6 +3380,11 @@ void LLInventoryModel::initHttpRequest()
 		mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML);
 		mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_INVENTORY);
 	}
+
+    if (!gGenericDispatcher.isHandlerPresent("BulkUpdateInventory"))
+    {
+        gGenericDispatcher.addHandler("BulkUpdateInventory", &sBulkUpdateInventory);
+    }
 }
 
 void LLInventoryModel::handleResponses(bool foreground)
@@ -3015,15 +3436,18 @@ LLCore::HttpHandle LLInventoryModel::requestPost(bool foreground,
 
 void LLInventoryModel::createCommonSystemCategories()
 {
-	gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH,true);
-	gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true);
-	gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD,true);
-	gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS,true);
-	gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, true);
-	gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, true); // folder should exist before user tries to 'landmark this'
-    gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS, true);
-    gInventory.findCategoryUUIDForType(LLFolderType::FT_MATERIAL, true); // probably should be server created
-    gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, true);
+    //amount of System Folder we should wait for
+    sPendingSystemFolders = 9;
+
+	gInventory.ensureCategoryForTypeExists(LLFolderType::FT_TRASH);
+	gInventory.ensureCategoryForTypeExists(LLFolderType::FT_FAVORITE);
+	gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CALLINGCARD);
+	gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MY_OUTFITS);
+	gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT);
+	gInventory.ensureCategoryForTypeExists(LLFolderType::FT_LANDMARK); // folder should exist before user tries to 'landmark this'
+    gInventory.ensureCategoryForTypeExists(LLFolderType::FT_SETTINGS);
+    gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MATERIAL); // probably should be server created
+    gInventory.ensureCategoryForTypeExists(LLFolderType::FT_INBOX);
 }
 
 struct LLUUIDAndName
@@ -3248,9 +3672,6 @@ void LLInventoryModel::registerCallbacks(LLMessageSystem* msg)
 	msg->setHandlerFuncFast(_PREHASH_RemoveInventoryItem,
 						processRemoveInventoryItem,
 						NULL);
-	msg->setHandlerFuncFast(_PREHASH_UpdateInventoryFolder,
-						processUpdateInventoryFolder,
-						NULL);
 	msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder,
 						processRemoveInventoryFolder,
 						NULL);
@@ -3281,6 +3702,10 @@ void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, vo
 		msg->getU32Fast(_PREHASH_InventoryData, _PREHASH_CallbackID, callback_id);
 
 		gInventoryCallbacks.fire(callback_id, item_id);
+
+        // todo: instead of unpacking message fully,
+        // grab only an item_id, then fetch
+        LLInventoryModelBackgroundFetch::instance().scheduleItemFetch(item_id, true);
 	}
 
 }
@@ -3403,66 +3828,6 @@ void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**)
 	gInventory.notifyObservers();
 }
 
-// 	static
-void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg,
-													void**)
-{
-	LL_DEBUGS(LOG_INV) << "LLInventoryModel::processUpdateInventoryFolder()" << LL_ENDL;
-	LLUUID agent_id;
-	//char name[DB_INV_ITEM_NAME_BUF_SIZE];
-	msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_AgentID, agent_id);
-	if(agent_id != gAgent.getID())
-	{
-		LL_WARNS(LOG_INV) << "Got an UpdateInventoryFolder for the wrong agent."
-						  << LL_ENDL;
-		return;
-	}
-	LLPointer<LLViewerInventoryCategory> lastfolder; // hack
-	cat_array_t folders;
-	update_map_t update;
-	S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
-	for(S32 i = 0; i < count; ++i)
-	{
-		LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());
-		lastfolder = tfolder;
-		tfolder->unpackMessage(msg, _PREHASH_FolderData, i);
-		// make sure it's not a protected folder
-		tfolder->setPreferredType(LLFolderType::FT_NONE);
-		folders.push_back(tfolder);
-		// examine update for changes.
-		LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID());
-		if(folderp)
-		{
-			if(tfolder->getParentUUID() == folderp->getParentUUID())
-			{
-				update[tfolder->getParentUUID()];
-			}
-			else
-			{
-				++update[tfolder->getParentUUID()];
-				--update[folderp->getParentUUID()];
-			}
-		}
-		else
-		{
-			++update[tfolder->getParentUUID()];
-		}
-	}
-	gInventory.accountForUpdate(update);
-	for (cat_array_t::iterator it = folders.begin(); it != folders.end(); ++it)
-	{
-		gInventory.updateCategory(*it);
-	}
-	gInventory.notifyObservers();
-
-	// *HACK: Do the 'show' logic for a new item in the inventory.
-	LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
-	if (active_panel)
-	{
-		active_panel->setSelection(lastfolder->getUUID(), TAKE_FOCUS_NO);
-	}
-}
-
 // 	static
 void LLInventoryModel::removeInventoryFolder(LLUUID agent_id,
 											 LLMessageSystem* msg)
@@ -3573,14 +3938,6 @@ void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg,
 	}
 }
 
-struct InventoryCallbackInfo
-{
-	InventoryCallbackInfo(U32 callback, const LLUUID& inv_id) :
-		mCallback(callback), mInvID(inv_id) {}
-	U32 mCallback;
-	LLUUID mInvID;
-};
-
 // static
 void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 {
@@ -3626,29 +3983,36 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 			LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID());
 			if(folderp)
 			{
-				if(tfolder->getParentUUID() == folderp->getParentUUID())
-				{
+                if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
+                {
+                    if (tfolder->getParentUUID() == folderp->getParentUUID())
+                    {
 // [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
-					// NOTE-RLVa: not sure if this is a hack or a bug-fix :o
-					//		-> if we rename the folder on the first BulkUpdateInventory message subsequent messages will still contain
-					//         the old folder name and gInventory.updateCategory() below will "undo" the folder name change but on the
-					//         viewer-side *only* so the folder name actually becomes out of sync with what's on the inventory server
-					//      -> so instead we keep the name of the existing folder and only do it for #RLV/~ in case this causes issues
-					//		-> a better solution would be to only do the rename *after* the transaction completes but there doesn't seem
-					//		   to be any way to accomplish that either *sighs*
-					if ( (rlv_handler_t::isEnabled()) && (!folderp->getName().empty()) && (tfolder->getName() != folderp->getName()) &&
-						 ((tfolder->getName().find(RLV_PUTINV_PREFIX) == 0)) )
-					{
-						tfolder->rename(folderp->getName());
-					}
+						// NOTE-RLVa: not sure if this is a hack or a bug-fix :o
+						//		-> if we rename the folder on the first BulkUpdateInventory message subsequent messages will still contain
+						//         the old folder name and gInventory.updateCategory() below will "undo" the folder name change but on the
+						//         viewer-side *only* so the folder name actually becomes out of sync with what's on the inventory server
+						//      -> so instead we keep the name of the existing folder and only do it for #RLV/~ in case this causes issues
+						//		-> a better solution would be to only do the rename *after* the transaction completes but there doesn't seem
+						//		   to be any way to accomplish that either *sighs*
+						if ( (rlv_handler_t::isEnabled()) && (!folderp->getName().empty()) && (tfolder->getName() != folderp->getName()) &&
+							 ((tfolder->getName().find(RLV_PUTINV_PREFIX) == 0)) )
+						{
+							tfolder->rename(folderp->getName());
+						}
 // [/RLVa:KB]
-					update[tfolder->getParentUUID()];
-				}
-				else
-				{
-					++update[tfolder->getParentUUID()];
-					--update[folderp->getParentUUID()];
-				}
+                        update[tfolder->getParentUUID()];
+                    }
+                    else
+                    {
+                        ++update[tfolder->getParentUUID()];
+                        --update[folderp->getParentUUID()];
+                    }
+                }
+                else
+                {
+                    folderp->fetch();
+                }
 			}
 			else
 			{
@@ -3658,7 +4022,14 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 				folderp = gInventory.getCategory(tfolder->getParentUUID());
 				if(folderp)
 				{
-					++update[tfolder->getParentUUID()];
+                    if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
+                    {
+                        ++update[tfolder->getParentUUID()];
+                    }
+                    else
+                    {
+                        folderp->fetch();
+                    }
 				}
 			}
 		}
@@ -3704,7 +4075,14 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 				LLViewerInventoryCategory* folderp = gInventory.getCategory(titem->getParentUUID());
 				if(folderp)
 				{
-					++update[titem->getParentUUID()];
+                    if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
+                    {
+                        ++update[titem->getParentUUID()];
+                    }
+                    else
+                    {
+                        folderp->fetch();
+                    }
 				}
 			}
 		}
@@ -3718,10 +4096,20 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 	for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit)
 	{
 		gInventory.updateCategory(*cit);
+
+        // Temporary workaround: just fetch the item using AIS to get missing fields.
+        // If this works fine we might want to extract ids only from the message
+        // then use AIS as a primary fetcher
+        LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch((*cit)->getUUID(), true /*force, since it has changes*/);
 	}
 	for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit)
 	{
 		gInventory.updateItem(*iit);
+
+        // Temporary workaround: just fetch the item using AIS to get missing fields.
+        // If this works fine we might want to extract ids only from the message
+        // then use AIS as a primary fetcher
+        LLInventoryModelBackgroundFetch::instance().scheduleItemFetch((*iit)->getUUID(), true);
 	}
 // [SL:KB] - Patch: UI-Notifications | Checked: Catznip-6.5
 	gInventory.notifyObservers(tid);
@@ -4640,7 +5028,6 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
 			}
 			else if (count_under_root > 1)
 			{
-				LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL;
 				validation_info->mDuplicateRequiredSystemFolders.insert(folder_type);
                 if (!is_automatic
                     && folder_type != LLFolderType::FT_SETTINGS
@@ -4652,6 +5039,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
                     // outfits, trash and other non-automatic folders.
 					validation_info->mFatalSystemDuplicate++;
                     fatal_errs++;
+                    LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL;
                 }
                 else
                 {
@@ -4660,6 +5048,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
                     // Exception: FT_SETTINGS is not automatic, but only deserves a warning.
 					validation_info->mWarnings["non_fatal_system_duplicate_under_root"]++;
                     warning_count++;
+                    LL_WARNS("Inventory") << "System folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL;
                 }
 			}
 			if (count_elsewhere > 0)
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index 7c542c1029170fee624f1c85a5689943342e8f3a..b34db25fb91ce1e5663c4e953d443dd6f7850f88 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -229,10 +229,14 @@ class LLInventoryModel
 	//--------------------------------------------------------------------
 public:
 	static BOOL getIsFirstTimeInViewer2();
+    static bool  isSysFoldersReady() { return (sPendingSystemFolders == 0); }
+
 private:
 	static BOOL sFirstTimeInViewer2;
 	const static S32 sCurrentInvCacheVersion; // expected inventory cache version
 
+    static S32 sPendingSystemFolders;
+
 /**                    Initialization/Setup
  **                                                                            **
  *******************************************************************************/
@@ -258,6 +262,7 @@ class LLInventoryModel
 	void getDirectDescendentsOf(const LLUUID& cat_id,
 								cat_array_t*& categories,
 								item_array_t*& items) const;
+    void getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& categories, item_array_t& items, LLInventoryCollectFunctor& f) const;
 
 	typedef LLUUID digest_t; // To clarify the actual usage of this "UUID"
 	// Compute a hash of direct descendant names (for detecting child name changes)
@@ -313,10 +318,13 @@ class LLInventoryModel
 	// Find
 	//--------------------------------------------------------------------
 public:
+
+    // Checks if category exists ("My Inventory" only), if it does not, creates it
+    void ensureCategoryForTypeExists(LLFolderType::EType preferred_type);
+
 	const LLUUID findCategoryUUIDForTypeInRoot(
 		LLFolderType::EType preferred_type,
-		bool create_folder,
-		const LLUUID& root_id);
+		const LLUUID& root_id) const;
 
 	const LLUUID findCategoryUUIDForNameInRoot(std::string const& folder_name,
 											   bool create_folder,
@@ -327,14 +335,12 @@ class LLInventoryModel
 	//    NOTE: If create_folder is true, this will create a new inventory category 
 	//    on the fly if one does not exist. *NOTE: if find_in_library is true it 
 	//    will search in the user's library folder instead of "My Inventory"
-	const LLUUID findCategoryUUIDForType(LLFolderType::EType preferred_type, 
-										 bool create_folder = true);
+	const LLUUID findCategoryUUIDForType(LLFolderType::EType preferred_type) const;
 	//    will search in the user's library folder instead of "My Inventory"
-	const LLUUID findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, 
-												bool create_folder = true);
+	const LLUUID findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type) const;
 	// Returns user specified category for uploads, returns default id if there are no
 	// user specified one or it does not exist, creates default category if it is missing.
-	const LLUUID findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type);
+	const LLUUID findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type) const;
 
 	// Returns the uuid of the category if found, LLUUID::null is not
 	const LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,
@@ -424,13 +430,15 @@ class LLInventoryModel
 							  const LLUUID& new_parent_id,
 							  BOOL restamp);
 
+    // Marks links from a "possibly" broken list for a rebuild
+    // clears the list
+    void rebuildBrockenLinks();
+    bool hasPosiblyBrockenLinks() const { return mPossiblyBrockenLinks.size() > 0; }
+
 	//--------------------------------------------------------------------
 	// Delete
 	//--------------------------------------------------------------------
 public:
-
-	// Update model after an AISv3 update received for any operation.
-	void onAISUpdateReceived(const std::string& context, const LLSD& update);
 		
 	// Update model after an item is confirmed as removed from
 	// server. Works for categories or items.
@@ -494,10 +502,11 @@ class LLInventoryModel
 public:
 	// Returns the UUID of the new category. If you want to use the default 
 	// name based on type, pass in a NULL to the 'name' parameter.
-	LLUUID createNewCategory(const LLUUID& parent_id,
+	void createNewCategory(const LLUUID& parent_id,
 							 LLFolderType::EType preferred_type,
 							 const std::string& name,
-							 inventory_func_type callback = NULL);
+							 inventory_func_type callback = NULL,
+							 const LLUUID& thumbnail_id = LLUUID::null);
 protected:
 	// Internal methods that add inventory and make sure that all of
 	// the internal data structures are consistent. These methods
@@ -600,6 +609,10 @@ class LLInventoryModel
     U32 mModifyMaskBacklog;
     changed_items_t mChangedItemIDsBacklog;
     changed_items_t mAddedItemIDsBacklog;
+    typedef std::map<LLUUID , changed_items_t> broken_links_t;
+    broken_links_t mPossiblyBrockenLinks; // there can be multiple links per item
+    changed_items_t mLinksRebuildList;
+    boost::signals2::connection mBulkFecthCallbackSlot;
 // [SL:KB] - Patch: UI-Notifications | Checked: Catznip-6.5
     LLUUID mTransactionId;
 // [/SL:KB]
@@ -689,7 +702,6 @@ class LLInventoryModel
 	static void processUpdateCreateInventoryItem(LLMessageSystem* msg, void**);
 	static void removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg, const char* msg_label);
 	static void processRemoveInventoryItem(LLMessageSystem* msg, void**);
-	static void processUpdateInventoryFolder(LLMessageSystem* msg, void**);
 	static void removeInventoryFolder(LLUUID agent_id, LLMessageSystem* msg);
 	static void processRemoveInventoryFolder(LLMessageSystem* msg, void**);
 	static void processRemoveInventoryObjects(LLMessageSystem* msg, void**);
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index c944edd4d6d9dce6cf8e649580e60c764ee192af..2e548d4625bcfa316996ad8c851805c39e9a4a8f 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -27,6 +27,7 @@
 #include "llviewerprecompiledheaders.h"
 #include "llinventorymodelbackgroundfetch.h"
 
+#include "llaisapi.h"
 #include "llagent.h"
 #include "llappviewer.h"
 #include "llcallbacklist.h"
@@ -178,8 +179,6 @@ class BGFolderHttpHandler : public LLCore::HttpHandler
 };
 
 
-const S32 MAX_FETCH_RETRIES = 10;
-
 const char * const LOG_INV("Inventory");
 
 } // end of namespace anonymous
@@ -190,17 +189,15 @@ const char * const LOG_INV("Inventory");
 ///----------------------------------------------------------------------------
 
 LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch():
-	mBackgroundFetchActive(FALSE),
+	mBackgroundFetchActive(false),
 	mFolderFetchActive(false),
 	mFetchCount(0),
-	mAllFoldersFetched(FALSE),
-	mRecursiveInventoryFetchStarted(FALSE),
-	mRecursiveLibraryFetchStarted(FALSE),
-	mTimelyFetchPending(FALSE),
-	mNumFetchRetries(0),
-	mMinTimeBetweenFetches(0.3f),
-	mMaxTimeBetweenFetches(10.f)
-
+    mLastFetchCount(0),
+    mFetchFolderCount(0),
+    mAllRecursiveFoldersFetched(false),
+	mRecursiveInventoryFetchStarted(false),
+	mRecursiveLibraryFetchStarted(false),
+	mMinTimeBetweenFetches(0.3f)
 {}
 
 LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch()
@@ -208,7 +205,12 @@ LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch()
 
 bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() const
 {
-	return mFetchQueue.empty() && mFetchCount <= 0;
+	return mFetchFolderQueue.empty() && mFetchItemQueue.empty() && mFetchCount <= 0;
+}
+
+bool LLInventoryModelBackgroundFetch::isFolderFetchProcessingComplete() const
+{
+    return mFetchFolderQueue.empty() && mFetchFolderCount <= 0;
 }
 
 bool LLInventoryModelBackgroundFetch::libraryFetchStarted() const
@@ -243,7 +245,7 @@ bool LLInventoryModelBackgroundFetch::inventoryFetchInProgress() const
 
 bool LLInventoryModelBackgroundFetch::isEverythingFetched() const
 {
-	return mAllFoldersFetched;
+	return mAllRecursiveFoldersFetched;
 }
 
 BOOL LLInventoryModelBackgroundFetch::folderFetchActive() const
@@ -251,17 +253,33 @@ BOOL LLInventoryModelBackgroundFetch::folderFetchActive() const
 	return mFolderFetchActive;
 }
 
-void LLInventoryModelBackgroundFetch::addRequestAtFront(const LLUUID & id, BOOL recursive, bool is_category)
+void LLInventoryModelBackgroundFetch::addRequestAtFront(const LLUUID & id, bool recursive, bool is_category)
 {
-	mFetchQueue.push_front(FetchQueueInfo(id, recursive, is_category));
+    EFetchType recursion_type = recursive ? FT_RECURSIVE : FT_DEFAULT;
+    if (is_category)
+    {
+        mFetchFolderQueue.push_front(FetchQueueInfo(id, recursion_type, is_category));
+    }
+    else
+    {
+        mFetchItemQueue.push_front(FetchQueueInfo(id, recursion_type, is_category));
+    }
 }
 
-void LLInventoryModelBackgroundFetch::addRequestAtBack(const LLUUID & id, BOOL recursive, bool is_category)
+void LLInventoryModelBackgroundFetch::addRequestAtBack(const LLUUID & id, bool recursive, bool is_category)
 {
-	mFetchQueue.push_back(FetchQueueInfo(id, recursive, is_category));
+    EFetchType recursion_type = recursive ? FT_RECURSIVE : FT_DEFAULT;
+    if (is_category)
+    {
+        mFetchFolderQueue.push_back(FetchQueueInfo(id, recursion_type, is_category));
+    }
+    else
+    {
+        mFetchItemQueue.push_back(FetchQueueInfo(id, recursion_type, is_category));
+    }
 }
 
-void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
+void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive)
 {
 	LLViewerInventoryCategory * cat(gInventory.getCategory(id));
 
@@ -270,31 +288,53 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
 		// it's a folder, do a bulk fetch
 		LL_DEBUGS(LOG_INV) << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL;
 
-		mBackgroundFetchActive = TRUE;
+		mBackgroundFetchActive = true;
 		mFolderFetchActive = true;
+        EFetchType recursion_type = recursive ? FT_RECURSIVE : FT_DEFAULT;
 		if (id.isNull())
 		{
 			if (! mRecursiveInventoryFetchStarted)
 			{
 				mRecursiveInventoryFetchStarted |= recursive;
-				mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive));
+                if (recursive && AISAPI::isAvailable())
+                {
+                    // Not only root folder can be massive, but
+                    // most system folders will be requested independently
+                    // so request root folder and content separately
+                    mFetchFolderQueue.push_front(FetchQueueInfo(gInventory.getRootFolderID(), FT_FOLDER_AND_CONTENT));
+                }
+                else
+                {
+                    mFetchFolderQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursion_type));
+                }
 				gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
 			}
 			if (! mRecursiveLibraryFetchStarted)
 			{
 				mRecursiveLibraryFetchStarted |= recursive;
-				mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive));
+                mFetchFolderQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursion_type));
 				gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
 			}
 		}
 		else
 		{
-			// Specific folder requests go to front of queue.
-			if (mFetchQueue.empty() || mFetchQueue.front().mUUID != id)
-			{
-				mFetchQueue.push_front(FetchQueueInfo(id, recursive));
-				gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
-			}
+            if (AISAPI::isAvailable())
+            {
+                if (mFetchFolderQueue.empty() || mFetchFolderQueue.back().mUUID != id)
+                {
+                    // On AIS make sure root goes to the top and follow up recursive
+                    // fetches, not individual requests
+                    mFetchFolderQueue.push_back(FetchQueueInfo(id, recursion_type));
+                    gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+                }
+            }
+            else if (mFetchFolderQueue.empty() || mFetchFolderQueue.front().mUUID != id)
+            {
+                    // Specific folder requests go to front of queue.
+                    mFetchFolderQueue.push_front(FetchQueueInfo(id, recursion_type));
+                    gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+            }
+
 			if (id == gInventory.getLibraryRootFolderID())
 			{
 				mRecursiveLibraryFetchStarted |= recursive;
@@ -307,21 +347,41 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
 	}
 	else if (LLViewerInventoryItem * itemp = gInventory.getItem(id))
 	{
-		if (! itemp->mIsComplete && (mFetchQueue.empty() || mFetchQueue.front().mUUID != id))
+		if (! itemp->mIsComplete)
 		{
-			mBackgroundFetchActive = TRUE;
-
-			mFetchQueue.push_front(FetchQueueInfo(id, false, false));
-			gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+            scheduleItemFetch(id);
 		}
 	}
 }
 
+void LLInventoryModelBackgroundFetch::scheduleFolderFetch(const LLUUID& cat_id, bool forced)
+{
+    if (mFetchFolderQueue.empty() || mFetchFolderQueue.front().mUUID != cat_id)
+    {
+        mBackgroundFetchActive = true;
+
+        // Specific folder requests go to front of queue.
+        mFetchFolderQueue.push_front(FetchQueueInfo(cat_id, forced ? FT_FORCED : FT_DEFAULT));
+        gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+    }
+}
+
+void LLInventoryModelBackgroundFetch::scheduleItemFetch(const LLUUID& item_id, bool forced)
+{
+    if (mFetchItemQueue.empty() || mFetchItemQueue.front().mUUID != item_id)
+    {
+        mBackgroundFetchActive = true;
+
+        mFetchItemQueue.push_front(FetchQueueInfo(item_id, forced ? FT_FORCED : FT_DEFAULT, false));
+        gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+    }
+}
+
 void LLInventoryModelBackgroundFetch::findLostItems()
 {
-	mBackgroundFetchActive = TRUE;
-	mFolderFetchActive = true;
-    mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE));
+    mBackgroundFetchActive = true;
+    mFolderFetchActive = true;
+    mFetchFolderQueue.push_back(FetchQueueInfo(LLUUID::null, FT_RECURSIVE));
     gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
 }
 
@@ -330,15 +390,28 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched()
 	if (mRecursiveInventoryFetchStarted &&
 		mRecursiveLibraryFetchStarted)
 	{
-		mAllFoldersFetched = TRUE;
+        mAllRecursiveFoldersFetched = true;
 		//LL_INFOS(LOG_INV) << "All folders fetched, validating" << LL_ENDL;
 		//gInventory.validate();
 	}
+
 	mFolderFetchActive = false;
-	mBackgroundFetchActive = false;
+    if (isBulkFetchProcessingComplete())
+    {
+        mBackgroundFetchActive = false;
+    }
+
+    // For now only informs about initial fetch being done
+    mFoldersFetchedSignal();
+
 	LL_INFOS(LOG_INV) << "Inventory background fetch completed" << LL_ENDL;
 }
 
+boost::signals2::connection LLInventoryModelBackgroundFetch::setFetchCompletionCallback(folders_fetched_callback_t cb)
+{
+    return mFoldersFetchedSignal.connect(cb);
+}
+
 void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *)
 {
 	LLInventoryModelBackgroundFetch::instance().backgroundFetch();
@@ -346,178 +419,497 @@ void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *)
 
 void LLInventoryModelBackgroundFetch::backgroundFetch()
 {
-	if (mBackgroundFetchActive && gAgent.getRegion() && gAgent.getRegion()->capabilitiesReceived())
+	if (mBackgroundFetchActive)
 	{
-		// If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
-		if (LLGridManager::instance().isInSecondlife() || gSavedSettings.getBOOL("UseHTTPInventory"))
-		{
-			bulkFetch();
-			return;
-		}
-		
-#if 1
-		//--------------------------------------------------------------------------------
-		// DEPRECATED OLD CODE
-		//
+        if (AISAPI::isAvailable())
+        {
+            bulkFetchViaAis();
+        }
+        else if (gAgent.getRegion() && gAgent.getRegion()->capabilitiesReceived())
+        {
+            // If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
+            bulkFetch();
+        }
+	}
+}
 
-		// No more categories to fetch, stop fetch process.
-		if (mFetchQueue.empty())
-		{
-			setAllFoldersFetched();
-			return;
-		}
+void LLInventoryModelBackgroundFetch::incrFetchCount(S32 fetching) 
+{  
+	mFetchCount += fetching; 
+	if (mFetchCount < 0)
+	{
+		LL_WARNS_ONCE(LOG_INV) << "Inventory fetch count fell below zero (0)." << LL_ENDL;
+		mFetchCount = 0; 
+	}
+}
+void LLInventoryModelBackgroundFetch::incrFetchFolderCount(S32 fetching)
+{
+    incrFetchCount(fetching);
+    mFetchFolderCount += fetching;
+    if (mFetchCount < 0)
+    {
+        LL_WARNS_ONCE(LOG_INV) << "Inventory fetch count fell below zero (0)." << LL_ENDL;
+        mFetchFolderCount = 0;
+    }
+}
 
-		F32 fast_fetch_time = ll_lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.1f);
-		F32 slow_fetch_time = ll_lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.5f);
-		if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() > slow_fetch_time)
-		{
-			// Double timeouts on failure.
-			mMinTimeBetweenFetches = llmin(mMinTimeBetweenFetches * 2.f, 10.f);
-			mMaxTimeBetweenFetches = llmin(mMaxTimeBetweenFetches * 2.f, 120.f);
-			LL_DEBUGS(LOG_INV) << "Inventory fetch times grown to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << LL_ENDL;
-			// fetch is no longer considered "timely" although we will wait for full time-out.
-			mTimelyFetchPending = FALSE;
-		}
+void ais_simple_item_callback(const LLUUID& inv_id)
+{
+    LL_DEBUGS(LOG_INV , "AIS3") << "Response for " << inv_id << LL_ENDL;
+    LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
+}
 
-		while(1)
-		{
-			if (mFetchQueue.empty())
-			{
-				break;
-			}
+void LLInventoryModelBackgroundFetch::onAISContentCalback(
+    const LLUUID& request_id,
+    const uuid_vec_t& content_ids,
+    const LLUUID& response_id,
+    EFetchType fetch_type)
+{
+    // Don't push_front on failure - there is a chance it was fired from inside bulkFetchViaAis
+    incrFetchFolderCount(-1);
 
-			if (gDisconnected)
-			{
-				// Just bail if we are disconnected.
-				break;
-			}
+    uuid_vec_t::const_iterator folder_iter = content_ids.begin();
+    uuid_vec_t::const_iterator folder_end = content_ids.end();
+    while (folder_iter != folder_end)
+    {
+        std::list<LLUUID>::const_iterator found = std::find(mExpectedFolderIds.begin(), mExpectedFolderIds.end(), *folder_iter);
+        if (found != mExpectedFolderIds.end())
+        {
+            mExpectedFolderIds.erase(found);
+        }
 
-			const FetchQueueInfo info = mFetchQueue.front();
+        LLViewerInventoryCategory* cat(gInventory.getCategory(*folder_iter));
+        if (cat)
+        {
+            cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+        }
+        if (response_id.isNull())
+        {
+            // Failed to fetch, get it individually
+            mFetchFolderQueue.push_back(FetchQueueInfo(*folder_iter, FT_RECURSIVE));
+        }
+        else
+        {
+            // push descendant back to verify they are fetched fully (ex: didn't encounter depth limit)
+            LLInventoryModel::cat_array_t* categories(NULL);
+            LLInventoryModel::item_array_t* items(NULL);
+            gInventory.getDirectDescendentsOf(*folder_iter, categories, items);
+            if (categories)
+            {
+                for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
+                     it != categories->end();
+                     ++it)
+                {
+                    mFetchFolderQueue.push_back(FetchQueueInfo((*it)->getUUID(), FT_RECURSIVE));
+                }
+            }
+        }
 
-			if (info.mIsCategory)
-			{
+        folder_iter++;
+    }
 
-				LLViewerInventoryCategory* cat = gInventory.getCategory(info.mUUID);
+    if (!mFetchFolderQueue.empty())
+    {
+        mBackgroundFetchActive = true;
+        mFolderFetchActive = true;
+        gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+    }
+}
+void LLInventoryModelBackgroundFetch::onAISFolderCalback(const LLUUID &request_id, const LLUUID &response_id, EFetchType fetch_type)
+{
+    // Don't push_front on failure - there is a chance it was fired from inside bulkFetchViaAis
+    incrFetchFolderCount(-1);
+    std::list<LLUUID>::const_iterator found = std::find(mExpectedFolderIds.begin(), mExpectedFolderIds.end(), request_id);
+    if (found != mExpectedFolderIds.end())
+    {
+        mExpectedFolderIds.erase(found);
+    }
+    else
+    {
+        // ais shouldn't respond twice
+        llassert(false);
+        LL_WARNS() << "Unexpected folder response for " << request_id << LL_ENDL;
+    }
 
-				// Category has been deleted, remove from queue.
-				if (!cat)
-				{
-					mFetchQueue.pop_front();
-					continue;
-				}
-			
-				if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches && 
-					LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
-				{
-					// Category exists but has no children yet, fetch the descendants
-					// for now, just request every time and rely on retry timer to throttle.
-					if (cat->fetch())
-					{
-						mFetchTimer.reset();
-						mTimelyFetchPending = TRUE;
-					}
-					else
-					{
-						//  The catagory also tracks if it has expired and here it says it hasn't
-						//  yet.  Get out of here because nothing is going to happen until we
-						//  update the timers.
-						break;
-					}
-				}
-				// Do I have all my children?
-				else if (gInventory.isCategoryComplete(info.mUUID))
-				{
-					// Finished with this category, remove from queue.
-					mFetchQueue.pop_front();
-
-					// Add all children to queue.
-					LLInventoryModel::cat_array_t* categories;
-					LLInventoryModel::item_array_t* items;
-					gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items);
-					for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
-						 it != categories->end();
-						 ++it)
-					{
-						mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(),info.mRecursive));
-					}
+    if (request_id.isNull())
+    {
+        // orhans, no other actions needed
+        return;
+    }
 
-					// We received a response in less than the fast time.
-					if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() < fast_fetch_time)
-					{
-						// Shrink timeouts based on success.
-						mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f);
-						mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f);
-						LL_DEBUGS(LOG_INV) << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << LL_ENDL;
-					}
+    bool request_descendants = false;
+    if (response_id.isNull()) // Failure
+    {
+        LL_DEBUGS(LOG_INV , "AIS3") << "Failure response for folder " << request_id << LL_ENDL;
+        if (fetch_type == FT_RECURSIVE)
+        {
+            // A full recursive request failed.
+            // Try requesting folder and nested content separately
+            mFetchFolderQueue.push_back(FetchQueueInfo(request_id, FT_FOLDER_AND_CONTENT));
+        }
+        else if (fetch_type == FT_FOLDER_AND_CONTENT)
+        {
+            LL_WARNS() << "Failed to download folder: " << request_id << " Requesting known content separately" << LL_ENDL;
+            mFetchFolderQueue.push_back(FetchQueueInfo(request_id, FT_CONTENT_RECURSIVE));
 
-					mTimelyFetchPending = FALSE;
-					continue;
-				}
-				else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches)
-				{
-					// Received first packet, but our num descendants does not match db's num descendants
-					// so try again later.
-					mFetchQueue.pop_front();
+            // set folder's version to prevent viewer from trying to request folder indefinetely
+            LLViewerInventoryCategory* cat(gInventory.getCategory(request_id));
+            if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
+            {
+                cat->setVersion(0);
+            }
+        }
+    }
+    else
+    {
+        if (fetch_type == FT_RECURSIVE)
+        {
+            // Got the folder and content, now verify content
+            // Request content even for FT_RECURSIVE in case of changes, failures
+            // or if depth limit gets imlemented.
+            // This shouldn't redownload folders if they already have version
+            request_descendants = true;
+            LL_DEBUGS(LOG_INV, "AIS3") << "Got folder " << request_id << ". Requesting content" << LL_ENDL;
+        }
+        else if (fetch_type == FT_FOLDER_AND_CONTENT)
+        {
+            // readd folder for content request
+            mFetchFolderQueue.push_front(FetchQueueInfo(request_id, FT_CONTENT_RECURSIVE));
+        }
+        else
+        {
+            LL_DEBUGS(LOG_INV, "AIS3") << "Got folder " << request_id << "." << LL_ENDL;
+        }
 
-					if (mNumFetchRetries++ < MAX_FETCH_RETRIES)
-					{
-						// push on back of queue
-						mFetchQueue.push_back(info);
-					}
-					mTimelyFetchPending = FALSE;
-					mFetchTimer.reset();
-					break;
-				}
+    }
 
-				// Not enough time has elapsed to do a new fetch
-				break;
-			}
-			else
-			{
-				LLViewerInventoryItem* itemp = gInventory.getItem(info.mUUID);
+    if (request_descendants)
+    {
+        LLInventoryModel::cat_array_t* categories(NULL);
+        LLInventoryModel::item_array_t* items(NULL);
+        gInventory.getDirectDescendentsOf(request_id, categories, items);
+        if (categories)
+        {
+            for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
+                 it != categories->end();
+                 ++it)
+            {
+                mFetchFolderQueue.push_back(FetchQueueInfo((*it)->getUUID(), FT_RECURSIVE));
+            }
+        }
+    }
 
-				mFetchQueue.pop_front();
-				if (!itemp) 
-				{
-					continue;
-				}
+    if (!mFetchFolderQueue.empty())
+    {
+        mBackgroundFetchActive = true;
+        mFolderFetchActive = true;
+        gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+    }
 
-				if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches)
-				{
-					itemp->fetchFromServer();
-					mFetchTimer.reset();
-					mTimelyFetchPending = TRUE;
-				}
-				else if (itemp->mIsComplete)
-				{
-					mTimelyFetchPending = FALSE;
-				}
-				else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches)
-				{
-					mFetchQueue.push_back(info);
-					mFetchTimer.reset();
-					mTimelyFetchPending = FALSE;
-				}
-				// Not enough time has elapsed to do a new fetch
-				break;
-			}
-		}
+    // done
+    LLViewerInventoryCategory * cat(gInventory.getCategory(request_id));
+    if (cat)
+    {
+        cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+    }
+}
 
-		//
-		// DEPRECATED OLD CODE
-		//--------------------------------------------------------------------------------
-#endif
-	}
+static LLTrace::BlockTimerStatHandle FTM_BULK_FETCH("Bulk Fetch");
+
+void LLInventoryModelBackgroundFetch::bulkFetchViaAis()
+{
+    LL_RECORD_BLOCK_TIME(FTM_BULK_FETCH);
+    //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
+    if (gDisconnected)
+    {
+        return;
+    }
+
+    static LLCachedControl<U32> ais_pool(gSavedSettings, "PoolSizeAIS", 20);
+    // Don't have too many requests at once, AIS throttles
+    // Reserve one request for actions outside of fetch (like renames)
+    const U32 max_concurrent_fetches = llclamp(ais_pool - 1, 1, 50);
+
+    if (mFetchCount >= max_concurrent_fetches)
+    {
+        return;
+    }
+
+    // Don't loop for too long (in case of large, fully loaded inventory)
+    F64 curent_time = LLTimer::getTotalSeconds();
+    const F64 max_time = LLStartUp::getStartupState() > STATE_WEARABLES_WAIT
+        ? 0.006f // 6 ms
+        : 1.f; 
+    const F64 end_time = curent_time + max_time;
+    S32 last_fetch_count = mFetchCount;
+
+    while (!mFetchFolderQueue.empty() && mFetchCount < max_concurrent_fetches && curent_time < end_time)
+    {
+        const FetchQueueInfo & fetch_info(mFetchFolderQueue.front());
+        bulkFetchViaAis(fetch_info);
+        mFetchFolderQueue.pop_front();
+        curent_time = LLTimer::getTotalSeconds();
+    }
+
+    // Ideally we shouldn't fetch items if recursive fetch isn't done,
+    // but there is a chance some request will start timeouting and recursive
+    // fetch will get stuck on a signle folder, don't block item fetch in such case
+    while (!mFetchItemQueue.empty() && mFetchCount < max_concurrent_fetches && curent_time < end_time)
+    {
+        const FetchQueueInfo& fetch_info(mFetchItemQueue.front());
+        bulkFetchViaAis(fetch_info);
+        mFetchItemQueue.pop_front();
+        curent_time = LLTimer::getTotalSeconds();
+    }
+
+    if (last_fetch_count != mFetchCount // if anything was added
+        || mLastFetchCount != mFetchCount) // if anything was substracted
+    {
+        LL_DEBUGS(LOG_INV , "AIS3") << "Total active fetches: " << mLastFetchCount << "->" << last_fetch_count << "->" << mFetchCount
+            << ", scheduled folder fetches: " << (S32)mFetchFolderQueue.size()
+            << ", scheduled item fetches: " << (S32)mFetchItemQueue.size()
+            << LL_ENDL;
+        mLastFetchCount = mFetchCount;
+
+        if (!mExpectedFolderIds.empty())
+        {
+            // A folder seem to be stack fetching on QA account, print oldest folder out
+            LL_DEBUGS(LOG_INV , "AIS3") << "Oldest expected folder: ";
+            std::list<LLUUID>::const_iterator iter = mExpectedFolderIds.begin();
+            LL_CONT << *iter;
+            if ((*iter).notNull())
+            {
+                LLViewerInventoryCategory* cat(gInventory.getCategory(*iter));
+                if (cat)
+                {
+                    LL_CONT << " Folder name: " << cat->getName() << " Parent: " << cat->getParentUUID();
+                }
+                else
+                {
+                    LL_CONT << " This folder doesn't exist";
+                }
+            }
+            else
+            {
+                LL_CONT << " Orphans request";
+            }
+            LL_CONT << LL_ENDL;
+        }
+    }
+    
+    if (isFolderFetchProcessingComplete() && mFolderFetchActive)
+    {
+        setAllFoldersFetched();
+    }
+
+    if (isBulkFetchProcessingComplete())
+    {
+        mBackgroundFetchActive = false;
+    }
 }
 
-void LLInventoryModelBackgroundFetch::incrFetchCount(S32 fetching) 
-{  
-	mFetchCount += fetching; 
-	if (mFetchCount < 0)
-	{
-		LL_WARNS_ONCE(LOG_INV) << "Inventory fetch count fell below zero (0)." << LL_ENDL;
-		mFetchCount = 0; 
-	}
+void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetch_info)
+{
+    if (fetch_info.mIsCategory)
+    {
+        const LLUUID & cat_id(fetch_info.mUUID);
+        if (cat_id.isNull())
+        {
+            incrFetchFolderCount(1);
+            mExpectedFolderIds.push_back(cat_id);
+            // Lost and found
+            // Should it actually be recursive?
+            AISAPI::FetchOrphans([](const LLUUID& response_id)
+                                 {
+                                     LLInventoryModelBackgroundFetch::instance().onAISFolderCalback(LLUUID::null,
+                                         response_id,
+                                         FT_DEFAULT);
+                                 });
+        }
+        else
+        {
+            LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
+            if (cat)
+            {
+                if (fetch_info.mFetchType == FT_CONTENT_RECURSIVE)
+                {
+                    // fetch content only, ignore cat itself
+                    uuid_vec_t children;
+                    LLInventoryModel::cat_array_t* categories(NULL);
+                    LLInventoryModel::item_array_t* items(NULL);
+                    gInventory.getDirectDescendentsOf(cat_id, categories, items);
+
+                    LLViewerInventoryCategory::EFetchType target_state = LLViewerInventoryCategory::FETCH_RECURSIVE;
+                    bool content_done = true;
+
+                    // Top limit is 'as many as you can put into url'
+                    static LLCachedControl<S32> ais_batch(gSavedSettings, "BatchSizeAIS3", 20);
+                    S32 batch_limit = llclamp(ais_batch(), 1, 40);
+
+                    for (LLInventoryModel::cat_array_t::iterator it = categories->begin();
+                         it != categories->end();
+                         ++it)
+                    {
+                        LLViewerInventoryCategory* child_cat = (*it);
+                        if (LLViewerInventoryCategory::VERSION_UNKNOWN != child_cat->getVersion()
+                            || child_cat->getFetching() >= target_state)
+                        {
+                            continue;
+                        }
+
+                        if (child_cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_LISTINGS)
+                        {
+                            // special case
+                            content_done = false;
+                            if (children.empty())
+                            {
+                                // fetch marketplace alone
+                                // Should it actually be fetched as FT_FOLDER_AND_CONTENT?
+                                children.push_back(child_cat->getUUID());
+                                mExpectedFolderIds.push_back(child_cat->getUUID());
+                                child_cat->setFetching(target_state);
+                                break;
+                            }
+                            else
+                            {
+                                // fetch marketplace alone next run
+                                continue;
+                            }
+                        }
+
+                        children.push_back(child_cat->getUUID());
+                        mExpectedFolderIds.push_back(child_cat->getUUID());
+                        child_cat->setFetching(target_state);
+
+                        if (children.size() >= batch_limit)
+                        {
+                            content_done = false;
+                            break;
+                        }
+                    }
+
+                    if (!children.empty())
+                    {
+                        // increment before call in case of immediate callback
+                        incrFetchFolderCount(1);
+
+                        EFetchType type = fetch_info.mFetchType;
+                        LLUUID cat_id = cat->getUUID(); // need a copy for lambda
+                        AISAPI::completion_t cb = [cat_id, children, type](const LLUUID& response_id)
+                        {
+                            LLInventoryModelBackgroundFetch::instance().onAISContentCalback(cat_id, children, response_id, type);
+                        };
+
+                        AISAPI::ITEM_TYPE item_type = AISAPI::INVENTORY;
+                        if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
+                        {
+                            item_type = AISAPI::LIBRARY;
+                        }
+
+                        AISAPI::FetchCategorySubset(cat_id, children, item_type, true, cb, 0);
+                    }
+
+                    if (content_done)
+                    {
+                        // This will have a bit of overlap with onAISContentCalback,
+                        // but something else might have dowloaded folders, so verify
+                        // every child that is complete has it's children done as well
+                        for (LLInventoryModel::cat_array_t::iterator it = categories->begin();
+                             it != categories->end();
+                             ++it)
+                        {
+                            LLViewerInventoryCategory* child_cat = (*it);
+                            if (LLViewerInventoryCategory::VERSION_UNKNOWN != child_cat->getVersion())
+                            {
+                                mFetchFolderQueue.push_back(FetchQueueInfo(child_cat->getUUID(), FT_RECURSIVE));
+                            }
+                        }
+                    }
+                    else
+                    {
+                        // send it back to get the rest
+                        mFetchFolderQueue.push_back(FetchQueueInfo(cat_id, FT_CONTENT_RECURSIVE));
+                    }
+                }
+                else if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()
+                         || fetch_info.mFetchType == FT_FORCED)
+                {
+                    LLViewerInventoryCategory::EFetchType target_state =
+                        fetch_info.mFetchType > FT_CONTENT_RECURSIVE
+                        ? LLViewerInventoryCategory::FETCH_RECURSIVE
+                        : LLViewerInventoryCategory::FETCH_NORMAL;
+                    // start again if we did a non-recursive fetch before
+                    // to get all children in a single request
+                    if (cat->getFetching() < target_state)
+                    {
+                        // increment before call in case of immediate callback
+                        incrFetchFolderCount(1);
+                        cat->setFetching(target_state);
+                        mExpectedFolderIds.push_back(cat_id);
+
+                        EFetchType type = fetch_info.mFetchType;
+                        LLUUID cat_id = cat->getUUID();
+                        AISAPI::completion_t cb = [cat_id , type](const LLUUID& response_id)
+                        {
+                            LLInventoryModelBackgroundFetch::instance().onAISFolderCalback(cat_id , response_id , type);
+                        };
+
+                        AISAPI::ITEM_TYPE item_type = AISAPI::INVENTORY;
+                        if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
+                        {
+                            item_type = AISAPI::LIBRARY;
+                        }
+
+                        AISAPI::FetchCategoryChildren(cat_id , item_type , type == FT_RECURSIVE , cb, 0);
+                    }
+                }
+                else
+                {
+                    // Already fetched, check if anything inside needs fetching
+                    if (fetch_info.mFetchType == FT_RECURSIVE
+                        || fetch_info.mFetchType == FT_FOLDER_AND_CONTENT)
+                    {
+                        LLInventoryModel::cat_array_t * categories(NULL);
+                        LLInventoryModel::item_array_t * items(NULL);
+                        gInventory.getDirectDescendentsOf(cat_id, categories, items);
+                        for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
+                            it != categories->end();
+                            ++it)
+                        {
+                            // not push_front to not cause an infinite loop
+                            mFetchFolderQueue.push_back(FetchQueueInfo((*it)->getUUID(), FT_RECURSIVE));
+                        }
+                    }
+                }
+            } // else try to fetch folder either way?
+        }
+    }
+    else
+    {
+        LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID));
+
+        if (itemp)
+        {
+            if (!itemp->isFinished() || fetch_info.mFetchType == FT_FORCED)
+            {
+                mFetchCount++;
+                if (itemp->getPermissions().getOwner() == gAgent.getID())
+                {
+                    AISAPI::FetchItem(fetch_info.mUUID, AISAPI::INVENTORY, ais_simple_item_callback);
+                }
+                else
+                {
+                    AISAPI::FetchItem(fetch_info.mUUID, AISAPI::LIBRARY, ais_simple_item_callback);
+                }
+            }
+        }
+        else // We don't know it, assume incomplete
+        {
+            // Assume agent's inventory, library wouldn't have gotten here
+            mFetchCount++;
+            AISAPI::FetchItem(fetch_info.mUUID, AISAPI::INVENTORY, ais_simple_item_callback);
+        }
+    }
 }
 
 // Bundle up a bunch of requests to send all at once.
@@ -539,13 +931,6 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 	// inventory more quickly.
 	static const U32 max_batch_size(10);
 	static const S32 max_concurrent_fetches(12);		// Outstanding requests, not connections
-	static const F32 new_min_time(0.05f);		// *HACK:  Clean this up when old code goes away entirely.
-	
-	mMinTimeBetweenFetches = new_min_time;
-	if (mMinTimeBetweenFetches < new_min_time) 
-	{
-		mMinTimeBetweenFetches = new_min_time;  // *HACK:  See above.
-	}
 
 	if (mFetchCount)
 	{
@@ -556,14 +941,10 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 		// OnIdle it will be called anyway due to Add flag for processed item.
 		// It seems like in some cases we are updaiting on fail (no flag),
 		// but is there anything to update?
-		if (LLGridManager::getInstance()->isInSecondlife())
-		{
-			gInventory.notifyObservers();
-		}
+		gInventory.notifyObservers();
 	}
 	
-	if ((mFetchCount > max_concurrent_fetches) ||
-		(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))
+	if (mFetchCount > max_concurrent_fetches)
 	{
 		return;
 	}
@@ -585,95 +966,105 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 	LLSD item_request_body;
 	LLSD item_request_body_lib;
 
-	while (! mFetchQueue.empty() 
+	while (! mFetchFolderQueue.empty() 
 			&& (item_count + folder_count) < max_batch_size)
 	{
-		const FetchQueueInfo & fetch_info(mFetchQueue.front());
+		const FetchQueueInfo & fetch_info(mFetchFolderQueue.front());
 		if (fetch_info.mIsCategory)
 		{
 			const LLUUID & cat_id(fetch_info.mUUID);
-			if (cat_id.isNull()) //DEV-17797
+			if (cat_id.isNull()) //DEV-17797 Lost and found
 			{
 				LLSD folder_sd;
 				folder_sd["folder_id"]		= LLUUID::null.asString();
 				folder_sd["owner_id"]		= gAgent.getID();
 				folder_sd["sort_order"]		= LLSD::Integer(sort_order);
-				folder_sd["fetch_folders"]	= LLSD::Boolean(FALSE);
-				folder_sd["fetch_items"]	= LLSD::Boolean(TRUE);
+				folder_sd["fetch_folders"]	= LLSD::Boolean(false);
+				folder_sd["fetch_items"]	= LLSD::Boolean(true);
 				folder_request_body["folders"].append(folder_sd);
 				folder_count++;
 			}
 			else
 			{
-				const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
-		
-				if (cat)
-				{
-					if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()
-                        && std::find(all_cats.begin(), all_cats.end(), cat_id) == all_cats.end())
-					{
-						LLSD folder_sd;
-						folder_sd["folder_id"]		= cat->getUUID();
-						folder_sd["owner_id"]		= cat->getOwnerID();
-						folder_sd["sort_order"]		= LLSD::Integer(sort_order);
-						folder_sd["fetch_folders"]	= LLSD::Boolean(TRUE); //(LLSD::Boolean)sFullFetchStarted;
-						folder_sd["fetch_items"]	= LLSD::Boolean(TRUE);
-				    
-						if (gInventory.getLibraryOwnerID() == cat->getOwnerID())
-						{
-							folder_request_body_lib["folders"].append(folder_sd);
-						}
-						else
-						{
-							folder_request_body["folders"].append(folder_sd);
-						}
-						folder_count++;
-					}
-
-					// May already have this folder, but append child folders to list.
-					if (fetch_info.mRecursive)
-					{	
-						LLInventoryModel::cat_array_t * categories(NULL);
-						LLInventoryModel::item_array_t * items(NULL);
-						gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items);
-						for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
-							 it != categories->end();
-							 ++it)
-						{
-							mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive));
-						}
-					}
-				}
+                const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
+                if (cat)
+                {
+                    if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
+                    {
+                        if (std::find(all_cats.begin(), all_cats.end(), cat_id) == all_cats.end())
+                        {
+                            LLSD folder_sd;
+                            folder_sd["folder_id"] = cat->getUUID();
+                            folder_sd["owner_id"] = cat->getOwnerID();
+                            folder_sd["sort_order"] = LLSD::Integer(sort_order);
+                            folder_sd["fetch_folders"] = LLSD::Boolean(TRUE); //(LLSD::Boolean)sFullFetchStarted;
+                            folder_sd["fetch_items"] = LLSD::Boolean(TRUE);
+
+                            if (gInventory.getLibraryOwnerID() == cat->getOwnerID())
+                            {
+                                folder_request_body_lib["folders"].append(folder_sd);
+                            }
+                            else
+                            {
+                                folder_request_body["folders"].append(folder_sd);
+                            }
+                            folder_count++;
+                        }
+                    }
+                    else
+                    {
+                        // May already have this folder, but append child folders to list.
+                        if (fetch_info.mFetchType >= FT_CONTENT_RECURSIVE)
+                        {
+                            LLInventoryModel::cat_array_t * categories(NULL);
+                            LLInventoryModel::item_array_t * items(NULL);
+                            gInventory.getDirectDescendentsOf(cat_id, categories, items);
+                            for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
+                                it != categories->end();
+                                ++it)
+                            {
+                                mFetchFolderQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mFetchType));
+                            }
+                        }
+                    }
+                }
 			}
-			if (fetch_info.mRecursive)
+			if (fetch_info.mFetchType >= FT_CONTENT_RECURSIVE)
 			{
 				recursive_cats.push_back(cat_id);
 			}
             all_cats.push_back(cat_id);
 		}
-		else
-		{
-			LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID));
 
-			if (itemp)
-			{
-				LLSD item_sd;
-				item_sd["owner_id"] = itemp->getPermissions().getOwner();
-				item_sd["item_id"] = itemp->getUUID();
-				if (itemp->getPermissions().getOwner() == gAgent.getID())
-				{
-					item_request_body.append(item_sd);
-				}
-				else
-				{
-					item_request_body_lib.append(item_sd);
-				}
-				//itemp->fetchFromServer();
-				item_count++;
-			}
-		}
+        mFetchFolderQueue.pop_front();
+    }
+
+
+    while (!mFetchItemQueue.empty()
+        && (item_count + folder_count) < max_batch_size)
+    {
+        const FetchQueueInfo & fetch_info(mFetchItemQueue.front());
 
-		mFetchQueue.pop_front();
+        LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID));
+
+        if (itemp)
+        {
+            LLSD item_sd;
+            item_sd["owner_id"] = itemp->getPermissions().getOwner();
+            item_sd["item_id"] = itemp->getUUID();
+            if (itemp->getPermissions().getOwner() == gAgent.getID())
+            {
+                item_request_body.append(item_sd);
+            }
+            else
+            {
+                item_request_body_lib.append(item_sd);
+            }
+            //itemp->fetchFromServer();
+            item_count++;
+        }
+
+        mFetchItemQueue.pop_front();
 	}
 
 	// Issue HTTP POST requests to fetch folders and items
@@ -744,12 +1135,22 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 
 bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LLUUID & cat_id) const
 {
-	for (const auto& item : mFetchQueue)
+	for (fetch_queue_t::const_iterator it = mFetchFolderQueue.begin();
+		 it != mFetchFolderQueue.end();
+		 ++it)
 	{
-		const LLUUID & fetch_id = item.mUUID;
+		const LLUUID & fetch_id = (*it).mUUID;
 		if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
 			return false;
 	}
+    for (fetch_queue_t::const_iterator it = mFetchItemQueue.begin();
+        it != mFetchItemQueue.end();
+        ++it)
+    {
+        const LLUUID & fetch_id = (*it).mUUID;
+        if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
+            return false;
+    }
 	return true;
 }
 
@@ -873,10 +1274,6 @@ void BGFolderHttpHandler::processData(LLSD & content, LLCore::HttpResponse * res
 							titem->setParent(lost_uuid);
 							titem->updateParentOnServer(FALSE);
 							gInventory.updateItem(titem);
-							if (!LLGridManager::getInstance()->isInSecondlife())
-							{
-								gInventory.notifyObservers();
-							}
 						}
 					}
 				}
@@ -949,11 +1346,6 @@ void BGFolderHttpHandler::processData(LLSD & content, LLCore::HttpResponse * res
 	{
 		fetcher->setAllFoldersFetched();
 	}
-
-	if (!LLGridManager::getInstance()->isInSecondlife())
-	{
-		gInventory.notifyObservers();
-	}
 }
 
 
@@ -996,10 +1388,10 @@ void BGFolderHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::Http
             while (iter != end)
             {
                 folders.append(*iter);
-                LLUUID fodler_id = iter->get("folder_id").asUUID();
-                if (std::find(mRecursiveCatUUIDs.begin(), mRecursiveCatUUIDs.end(), fodler_id) != mRecursiveCatUUIDs.end())
+                LLUUID folder_id = iter->get("folder_id").asUUID();
+                if (std::find(mRecursiveCatUUIDs.begin(), mRecursiveCatUUIDs.end(), folder_id) != mRecursiveCatUUIDs.end())
                 {
-                    recursive_cats.push_back(fodler_id);
+                    recursive_cats.push_back(folder_id);
                 }
                 if (folders.size() == (S32)(size / 2))
                 {
@@ -1050,11 +1442,6 @@ void BGFolderHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::Http
 			fetcher->setAllFoldersFetched();
 		}
 	}
-
-	if (!LLGridManager::getInstance()->isInSecondlife())
-	{
-		gInventory.notifyObservers();
-	}
 }
 
 
@@ -1089,11 +1476,6 @@ void BGFolderHttpHandler::processFailure(const char * const reason, LLCore::Http
 			fetcher->setAllFoldersFetched();
 		}
 	}
-
-	if (!LLGridManager::getInstance()->isInSecondlife())
-	{
-		gInventory.notifyObservers();
-	}
 }
 
 
diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h
index 67066bc0e2402cc2239398eb5e2faca87a594985..54bbafc0a2116273f050d0af78a97a9521858934 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.h
+++ b/indra/newview/llinventorymodelbackgroundfetch.h
@@ -47,9 +47,11 @@ class LLInventoryModelBackgroundFetch final : public LLSingleton<LLInventoryMode
 	~LLInventoryModelBackgroundFetch();
 public:
 
-	// Start and stop background breadth-first fetching of inventory contents.
+    // Start background breadth-first fetching of inventory contents.
 	// This gets triggered when performing a filter-search.
-	void start(const LLUUID& cat_id = LLUUID::null, BOOL recursive = TRUE);
+	void start(const LLUUID& cat_id = LLUUID::null, bool recursive = true);
+    void scheduleFolderFetch(const LLUUID& cat_id, bool forced = false);
+    void scheduleItemFetch(const LLUUID& item_id, bool forced = false);
 
 	BOOL folderFetchActive() const;
 	bool isEverythingFetched() const; // completing the fetch once per session should be sufficient
@@ -62,16 +64,47 @@ class LLInventoryModelBackgroundFetch final : public LLSingleton<LLInventoryMode
 	bool inventoryFetchCompleted() const;
 	bool inventoryFetchInProgress() const;
 
-    void findLostItems();	
-	void incrFetchCount(S32 fetching);
+    void findLostItems();
+    void incrFetchCount(S32 fetching);
+    void incrFetchFolderCount(S32 fetching);
 
 	bool isBulkFetchProcessingComplete() const;
+    bool isFolderFetchProcessingComplete() const;
 	void setAllFoldersFetched();
 
-	void addRequestAtFront(const LLUUID & id, BOOL recursive, bool is_category);
-	void addRequestAtBack(const LLUUID & id, BOOL recursive, bool is_category);
+    typedef boost::function<void()> folders_fetched_callback_t;
+    boost::signals2::connection setFetchCompletionCallback(folders_fetched_callback_t cb);
+
+	void addRequestAtFront(const LLUUID & id, bool recursive, bool is_category);
+	void addRequestAtBack(const LLUUID & id, bool recursive, bool is_category);
 
 protected:
+
+    typedef enum {
+        FT_DEFAULT = 0,
+        FT_FORCED, // request non-recursively even if already loaded
+        FT_CONTENT_RECURSIVE, // request content recursively
+        FT_FOLDER_AND_CONTENT, // request folder, then content recursively
+        FT_RECURSIVE, // request everything recursively
+    } EFetchType;
+    struct FetchQueueInfo
+    {
+        FetchQueueInfo(const LLUUID& id, EFetchType recursive, bool is_category = true)
+            : mUUID(id),
+            mIsCategory(is_category),
+            mFetchType(recursive)
+        {}
+
+        LLUUID mUUID;
+        bool mIsCategory;
+        EFetchType mFetchType;
+    };
+    typedef std::deque<FetchQueueInfo> fetch_queue_t;
+
+    void onAISContentCalback(const LLUUID& request_id, const uuid_vec_t &content_ids, const LLUUID& response_id, EFetchType fetch_type);
+    void onAISFolderCalback(const LLUUID &request_id, const LLUUID &response_id, EFetchType fetch_type);
+    void bulkFetchViaAis();
+    void bulkFetchViaAis(const FetchQueueInfo& fetch_info);
 	void bulkFetch();
 
 	void backgroundFetch();
@@ -80,35 +113,23 @@ class LLInventoryModelBackgroundFetch final : public LLSingleton<LLInventoryMode
 	bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const;
 
 private:
- 	BOOL mRecursiveInventoryFetchStarted;
-	BOOL mRecursiveLibraryFetchStarted;
-	BOOL mAllFoldersFetched;
+ 	bool mRecursiveInventoryFetchStarted;
+	bool mRecursiveLibraryFetchStarted;
+	bool mAllRecursiveFoldersFetched;
+    typedef boost::signals2::signal<void()> folders_fetched_signal_t;
+    folders_fetched_signal_t mFoldersFetchedSignal;
 
-	BOOL mBackgroundFetchActive;
+    bool mBackgroundFetchActive;
 	bool mFolderFetchActive;
 	S32 mFetchCount;
+    S32 mLastFetchCount; // for debug
+    S32 mFetchFolderCount;
 
 	LLFrameTimer mFetchTimer;
-	BOOL mTimelyFetchPending;
-	S32 mNumFetchRetries;
 	F32 mMinTimeBetweenFetches;
-	F32 mMaxTimeBetweenFetches;
-
-
-	struct FetchQueueInfo
-	{
-		FetchQueueInfo(const LLUUID& id, BOOL recursive, bool is_category = true)
-			: mUUID(id),
-			  mIsCategory(is_category),
-			  mRecursive(recursive)
-		{}
-		
-		LLUUID mUUID;
-		bool mIsCategory;
-		BOOL mRecursive;
-	};
-	typedef std::deque<FetchQueueInfo> fetch_queue_t;
-	fetch_queue_t mFetchQueue;
+	fetch_queue_t mFetchFolderQueue;
+    fetch_queue_t mFetchItemQueue;
+    std::list<LLUUID> mExpectedFolderIds; // for debug, should this track time?
 };
 
 #endif // LL_LLINVENTORYMODELBACKGROUNDFETCH_H
diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp
index 45207835d98a4406ce291e97ba8ade27573804bc..d7db3cea053b7f6539f2beb9f27a1bc38b4993cf 100644
--- a/indra/newview/llinventoryobserver.cpp
+++ b/indra/newview/llinventoryobserver.cpp
@@ -37,8 +37,10 @@
 
 #include "llagent.h"
 #include "llagentwearables.h"
+#include "llaisapi.h"
 #include "llfloater.h"
 #include "llfocusmgr.h"
+#include "llinventorymodelbackgroundfetch.h"
 #include "llinventorybridge.h"
 #include "llinventoryfunctions.h"
 #include "llinventorymodel.h"
@@ -58,6 +60,7 @@
 
 #include "llviewernetwork.h"
 
+const S32 LLInventoryFetchItemsObserver::MAX_INDIVIDUAL_ITEM_REQUESTS = 7;
 const F32 LLInventoryFetchItemsObserver::FETCH_TIMER_EXPIRY = 60.0f;
 
 
@@ -151,7 +154,7 @@ LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const uuid_vec_t& i
 
 void LLInventoryFetchItemsObserver::changed(U32 mask)
 {
-	LL_DEBUGS() << this << " remaining incomplete " << mIncomplete.size()
+    LL_DEBUGS("InventoryFetch") << this << " remaining incomplete " << mIncomplete.size()
 			 << " complete " << mComplete.size()
 			 << " wait period " << mFetchingPeriod.getRemainingTimeF32()
 			 << LL_ENDL;
@@ -160,6 +163,15 @@ void LLInventoryFetchItemsObserver::changed(U32 mask)
 	// appropriate.
 	if (!mIncomplete.empty())
 	{
+        if (!LLInventoryModelBackgroundFetch::getInstance()->isEverythingFetched())
+        {
+            // Folders have a priority over items and they download items as well
+            // Wait untill initial folder fetch is done
+            LL_DEBUGS("InventoryFetch") << "Folder fetch in progress, resetting fetch timer" << LL_ENDL;
+
+            mFetchingPeriod.reset();
+            mFetchingPeriod.setTimerExpirySec(FETCH_TIMER_EXPIRY);
+        }
 
 		// Have we exceeded max wait time?
 		bool timeout_expired = mFetchingPeriod.hasExpired();
@@ -178,7 +190,7 @@ void LLInventoryFetchItemsObserver::changed(U32 mask)
 				if (timeout_expired)
 				{
 					// Just concede that this item hasn't arrived in reasonable time and continue on.
-					LL_WARNS() << "Fetcher timed out when fetching inventory item UUID: " << item_id << LL_ENDL;
+                    LL_WARNS("InventoryFetch") << "Fetcher timed out when fetching inventory item UUID: " << item_id << LL_ENDL;
 					it = mIncomplete.erase(it);
 				}
 				else
@@ -193,7 +205,7 @@ void LLInventoryFetchItemsObserver::changed(U32 mask)
 
 	if (mIncomplete.empty())
 	{
-		LL_DEBUGS() << this << " done at remaining incomplete "
+        LL_DEBUGS("InventoryFetch") << this << " done at remaining incomplete "
 				 << mIncomplete.size() << " complete " << mComplete.size() << LL_ENDL;
 		done();
 	}
@@ -281,29 +293,21 @@ void fetch_items_from_llsd(const LLSD& items_llsd)
 
 void LLInventoryFetchItemsObserver::startFetch()
 {
-	LLUUID owner_id;
+    bool aisv3 = AISAPI::isAvailable();
+
 	LLSD items_llsd;
+
+    typedef std::map<LLUUID, uuid_vec_t> requests_by_folders_t;
+    requests_by_folders_t requests;
 	for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it)
 	{
-		LLViewerInventoryItem* item = gInventory.getItem(*it);
-		if (item)
-		{
-			if (item->isFinished())
-			{
-				// It's complete, so put it on the complete container.
-				mComplete.push_back(*it);
-				continue;
-			}
-			else
-			{
-				owner_id = item->getPermissions().getOwner();
-			}
-		}
-		else
-		{
-			// assume it's agent inventory.
-			owner_id = gAgent.getID();
-		}
+        LLViewerInventoryItem* item = gInventory.getItem(*it);
+        if (item && item->isFinished())
+        {
+            // It's complete, so put it on the complete container.
+            mComplete.push_back(*it);
+            continue;
+        }
 
 		// Ignore categories since they're not items.  We
 		// could also just add this to mComplete but not sure what the
@@ -324,17 +328,98 @@ void LLInventoryFetchItemsObserver::startFetch()
 		// pack this on the message.
 		mIncomplete.push_back(*it);
 
-		// Prepare the data to fetch
-		LLSD item_entry;
-		item_entry["owner_id"] = owner_id;
-		item_entry["item_id"] = (*it);
-		items_llsd.append(item_entry);
+        if (aisv3)
+        {
+            if (item)
+            {
+                LLUUID parent_id = item->getParentUUID();
+                requests[parent_id].push_back(*it);
+            }
+            else
+            {
+                // Can happen for gestures and calling cards if server notified us before they fetched
+                // Request by id without checking for an item.
+                LLInventoryModelBackgroundFetch::getInstance()->scheduleItemFetch(*it);
+            }
+        }
+        else
+        {
+            // Prepare the data to fetch
+            LLSD item_entry;
+            if (item)
+            {
+                item_entry["owner_id"] = item->getPermissions().getOwner();
+            }
+            else
+            {
+                // assume it's agent inventory.
+                item_entry["owner_id"] = gAgent.getID();
+            }
+            item_entry["item_id"] = (*it);
+            items_llsd.append(item_entry);
+        }
 	}
 
 	mFetchingPeriod.reset();
 	mFetchingPeriod.setTimerExpirySec(FETCH_TIMER_EXPIRY);
 
-	fetch_items_from_llsd(items_llsd);
+    if (aisv3)
+    {
+        for (requests_by_folders_t::value_type &folder : requests)
+        {
+            if (folder.second.size() > MAX_INDIVIDUAL_ITEM_REQUESTS)
+            {
+                // requesting one by one will take a while
+                // do whole folder
+                LLInventoryModelBackgroundFetch::getInstance()->scheduleFolderFetch(folder.first, true);
+            }
+            else
+            {
+                LLViewerInventoryCategory* cat = gInventory.getCategory(folder.first);
+                if (cat)
+                {
+                    if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
+                    {
+                        // start fetching whole folder since it's not ready either way
+                        cat->fetch();
+                    }
+                    else if (cat->getViewerDescendentCount() <= folder.second.size()
+                             || cat->getDescendentCount() <= folder.second.size())
+                    {
+                        // Start fetching whole folder since we need all items
+                        LLInventoryModelBackgroundFetch::getInstance()->scheduleFolderFetch(folder.first, true);
+
+                    }
+                    else
+                    {
+                        // get items one by one
+                        for (LLUUID &item_id : folder.second)
+                        {
+                            LLInventoryModelBackgroundFetch::getInstance()->scheduleItemFetch(item_id);
+                        }
+                    }
+                }
+                else
+                {
+                    // Isn't supposed to happen? We should have all folders
+                    // and if item exists, folder is supposed to exist as well.
+                    llassert(false);
+                    LL_WARNS("Inventory") << "Missing folder: " << folder.first << " fetching items individually" << LL_ENDL;
+
+                    // get items one by one
+                    for (LLUUID &item_id : folder.second)
+                    {
+                        LLInventoryModelBackgroundFetch::getInstance()->scheduleItemFetch(item_id);
+                    }
+                }
+            }
+        }
+    }
+    else
+    {
+        fetch_items_from_llsd(items_llsd);
+    }
+
 }
 
 LLInventoryFetchDescendentsObserver::LLInventoryFetchDescendentsObserver(const LLUUID& cat_id) :
@@ -679,6 +764,13 @@ void LLInventoryCategoriesObserver::changed(U32 mask)
 			}
 		}
 
+        const LLUUID thumbnail_id = category->getThumbnailUUID();
+        if (cat_data.mThumbnailId != thumbnail_id)
+        {
+            cat_data.mThumbnailId = thumbnail_id;
+            cat_changed = true;
+        }
+
 		// If anything has changed above, fire the callback.
 		if (cat_changed)
 			cat_data.mCallback();
@@ -696,6 +788,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
 	S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN;
 	S32 current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN;
 	bool can_be_added = true;
+    LLUUID thumbnail_id;
 
 	LLViewerInventoryCategory* category = gInventory.getCategory(cat_id);
 	// If category could not be retrieved it might mean that
@@ -707,6 +800,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
 		// Inventory category version is used to find out if some changes
 		// to a category have been made.
 		version = category->getVersion();
+        thumbnail_id = category->getThumbnailUUID();
 
 		LLInventoryModel::cat_array_t* cats;
 		LLInventoryModel::item_array_t* items;
@@ -731,12 +825,12 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
 	{
 		if(init_name_hash)
 		{
-			digest_t item_name_hash = gInventory.hashDirectDescendentNames(cat_id);
-			mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, cb, version, current_num_known_descendents,item_name_hash)));
+			digest_t item_name_hash = gInventory.hashDirectDescendentNames(cat_id);			
+			mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents,item_name_hash)));
 		}
 		else
 		{
-			mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, cb, version, current_num_known_descendents)));
+			mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents)));
 		}
 	}
 
@@ -749,23 +843,25 @@ void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id)
 }
 
 LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData(
-	const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents)
+	const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents)
 	
 	: mCatID(cat_id)
 	, mCallback(cb)
 	, mVersion(version)
 	, mDescendentsCount(num_descendents)
+    , mThumbnailId(thumbnail_id)
 	, mIsNameHashInitialized(false)
 {
 }
 
 LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData(
-	const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash)
+	const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash)
 
 	: mCatID(cat_id)
 	, mCallback(cb)
 	, mVersion(version)
 	, mDescendentsCount(num_descendents)
+    , mThumbnailId(thumbnail_id)
 	, mIsNameHashInitialized(true)
 	, mItemNameHash(name_hash)
 {
diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h
index 4af810205537b2edd54eb3bfc18ac2d3ec1da740..bec08d2cdf9cb83cdb90ec2de758d43795e25da0 100644
--- a/indra/newview/llinventoryobserver.h
+++ b/indra/newview/llinventoryobserver.h
@@ -104,6 +104,9 @@ class LLInventoryFetchItemsObserver : public LLInventoryFetchObserver
 
 	/*virtual*/ void startFetch();
 	/*virtual*/ void changed(U32 mask);
+
+    // For attempts to group requests if too many items are requested
+    static const S32 MAX_INDIVIDUAL_ITEM_REQUESTS;
 private:
 	LLTimer mFetchingPeriod;
 
@@ -125,7 +128,7 @@ class LLInventoryFetchDescendentsObserver : public LLInventoryFetchObserver
 	LLInventoryFetchDescendentsObserver(const LLUUID& cat_id = LLUUID::null);
 	LLInventoryFetchDescendentsObserver(const uuid_vec_t& cat_ids);
 
-	/*virtual*/ void startFetch();
+	virtual void startFetch();
 	/*virtual*/ void changed(U32 mask);
 protected:
 	BOOL isCategoryComplete(const LLViewerInventoryCategory* cat) const;
@@ -273,14 +276,15 @@ class LLInventoryCategoriesObserver : public LLInventoryObserver
 	typedef LLUUID digest_t; // To clarify the actual usage of this "UUID"
 	struct LLCategoryData
 	{
-		LLCategoryData(const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents);
-		LLCategoryData(const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash);
+		LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents);
+		LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash);
 		callback_t	mCallback;
 		S32			mVersion;
 		S32			mDescendentsCount;
 		digest_t	mItemNameHash;
 		bool		mIsNameHashInitialized;
 		LLUUID		mCatID;
+        LLUUID		mThumbnailId;
 	};
 
 	typedef	std::map<LLUUID, LLCategoryData>	category_map_t;
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 38b828c123004aae02a113b7774d38ccf2535557..42b209cf228a271d1a00ed26f7f9f20a290b06d7 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -40,6 +40,7 @@
 #include "llfolderviewitem.h"
 #include "llfloaterimcontainer.h"
 #include "llimview.h"
+#include "llinspecttexture.h"
 #include "llinventorybridge.h"
 #include "llinventoryfunctions.h"
 #include "llinventorymodelbackgroundfetch.h"
@@ -164,13 +165,15 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
 	mInvFVBridgeBuilder(NULL),
 	mInventoryViewModel(p.name),
 	mGroupedItemBridge(new LLFolderViewGroupedItemBridge),
-	mFocusSelection(false)
+	mFocusSelection(false),
+    mBuildChildrenViews(true),
+    mRootInited(false)
 {
 	mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER;
 
 	if (!sColorSetInitialized)
 	{
-		sDefaultColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
+		sDefaultColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
 		sDefaultHighlightColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
 		sLibraryColor = LLUIColorTable::instance().getColor("InventoryItemLibraryColor", DEFAULT_WHITE);
 		sLinkColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
@@ -186,6 +189,7 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
 	mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this));
 	mCommitCallbackRegistrar.add("Inventory.Share",  boost::bind(&LLAvatarActions::shareWithAvatars, this));
 	mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryPanel::fileUploadLocation, this, _2));
+    mCommitCallbackRegistrar.add("Inventory.OpenNewFolderWindow", boost::bind(&LLInventoryPanel::openSingleViewInventory, this, LLUUID()));
 }
 
 LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )
@@ -252,52 +256,116 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)
 {
 	// save off copy of params
 	mParams = params;
-	// Clear up the root view
-	// Note: This needs to be done *before* we build the new folder view 
-	LLUUID root_id = getRootFolderID();
-	if (mFolderRoot.get())
-	{
-		removeItemID(root_id);
-		mFolderRoot.get()->destroyView();
-	}
 
-	mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves
-	{
-		// Determine the root folder in case specified, and
-		// build the views starting with that folder.
+    initFolderRoot();
+
+	// Initialize base class params.
+	LLPanel::initFromParams(mParams);
+}
+
+LLInventoryPanel::~LLInventoryPanel()
+{
+	U32 sort_order = getFolderViewModel()->getSorter().getSortOrder();
+    if (mSortOrderSetting != INHERIT_SORT_ORDER)
+    {
+        gSavedSettings.setU32(mSortOrderSetting, sort_order);
+    }
+    
+    clearFolderRoot();
+}
+
+void LLInventoryPanel::initFolderRoot()
+{
+    // Clear up the root view
+    // Note: This needs to be done *before* we build the new folder view
+    LLUUID root_id = getRootFolderID();
+    if (mFolderRoot.get())
+    {
+        removeItemID(root_id);
+        mFolderRoot.get()->destroyView();
+    }
+
+    mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves
+    {
+        // Determine the root folder in case specified, and
+        // build the views starting with that folder.
         LLFolderView* folder_view = createFolderRoot(root_id);
-		mFolderRoot = folder_view->getHandle();
-	
-		addItemID(root_id, mFolderRoot.get());
-	}
-	mCommitCallbackRegistrar.popScope();
-	mFolderRoot.get()->setCallbackRegistrar(&mCommitCallbackRegistrar);
-	mFolderRoot.get()->setEnableRegistrar(&mEnableCallbackRegistrar);
-	
-	// Scroller
-		LLRect scroller_view_rect = getRect();
-		scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
-	LLScrollContainer::Params scroller_params(mParams.scroll());
-		scroller_params.rect(scroller_view_rect);
-		mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
-		addChild(mScroller);
-		mScroller->addChild(mFolderRoot.get());
-		mFolderRoot.get()->setScrollContainer(mScroller);
-		mFolderRoot.get()->setFollowsAll();
-		mFolderRoot.get()->addChild(mFolderRoot.get()->mStatusTextBox);
-
-	// Set up the callbacks from the inventory we're viewing, and then build everything.
-	mInventoryObserver = new LLInventoryPanelObserver(this);
-	mInventory->addObserver(mInventoryObserver);
-
-	mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this));
-	mInventory->addObserver(mCompletionObserver);
-
-    if (mBuildViewsOnInit && mViewsInitialized == VIEWS_UNINITIALIZED)
+        mFolderRoot = folder_view->getHandle();
+        mRootInited = true;
+    
+        addItemID(root_id, mFolderRoot.get());
+    }
+    mCommitCallbackRegistrar.popScope();
+    mFolderRoot.get()->setCallbackRegistrar(&mCommitCallbackRegistrar);
+    mFolderRoot.get()->setEnableRegistrar(&mEnableCallbackRegistrar);
+    
+    // Scroller
+    LLRect scroller_view_rect = getRect();
+    scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
+    LLScrollContainer::Params scroller_params(mParams.scroll());
+    scroller_params.rect(scroller_view_rect);
+    mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
+    addChild(mScroller);
+    mScroller->addChild(mFolderRoot.get());
+    mFolderRoot.get()->setScrollContainer(mScroller);
+    mFolderRoot.get()->setFollowsAll();
+    mFolderRoot.get()->addChild(mFolderRoot.get()->mStatusTextBox);
+
+    if (mSelectionCallback)
+    {
+        mFolderRoot.get()->setSelectCallback(mSelectionCallback);
+    }
+
+    // Set up the callbacks from the inventory we're viewing, and then build everything.
+    mInventoryObserver = new LLInventoryPanelObserver(this);
+    mInventory->addObserver(mInventoryObserver);
+
+    mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this));
+    mInventory->addObserver(mCompletionObserver);
+
+    if (mBuildViewsOnInit)
+    {
+        initializeViewBuilding();
+    }
+
+    if (mSortOrderSetting != INHERIT_SORT_ORDER)
+    {
+        setSortOrder(gSavedSettings.getU32(mSortOrderSetting));
+    }
+    else
+    {
+        setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER));
+    }
+
+    // hide inbox
+    if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible"))
+    {
+        getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX));
+    }
+    // hide marketplace listing box, unless we are a marketplace panel
+    if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible") && !mParams.use_marketplace_folders)
     {
+        getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS));
+    }
+    
+    // set the filter for the empty folder if the debug setting is on
+    if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders"))
+    {
+        getFilter().setFilterEmptySystemFolders();
+    }
+    
+    // keep track of the clipboard state so that we avoid filtering too much
+    mClipboardState = LLClipboard::instance().getGeneration();
+}
+
+void LLInventoryPanel::initializeViewBuilding()
+{
+    if (mViewsInitialized == VIEWS_UNINITIALIZED)
+    {
+        LL_DEBUGS("Inventory") << "Setting views for " << getName() << " to initialize" << LL_ENDL;
         // Build view of inventory if we need default full hierarchy and inventory is ready, otherwise do in onIdle.
         // Initializing views takes a while so always do it onIdle if viewer already loaded.
-        if (mInventory->isInventoryUsable()            
+        if (mInventory->isInventoryUsable()
             && LLStartUp::getStartupState() <= STATE_WEARABLES_WAIT)
         {
             // Usually this happens on login, so we have less time constraits, but too long and we can cause a disconnect
@@ -310,49 +378,6 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)
             gIdleCallbacks.addFunction(onIdle, (void*)this);
         }
     }
-
-	if (mSortOrderSetting != INHERIT_SORT_ORDER)
-	{
-		setSortOrder(gSavedSettings.getU32(mSortOrderSetting));
-	}
-	else
-	{
-		setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER));
-	}
-
-	// hide inbox
-	if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible"))
-	{
-		getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX));
-	}
-    // hide marketplace listing box, unless we are a marketplace panel
-	if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible") && !mParams.use_marketplace_folders)
-	{
-		getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS));
-    }
-    
-	// set the filter for the empty folder if the debug setting is on
-	if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders"))
-	{
-		getFilter().setFilterEmptySystemFolders();
-	}
-	
-	// keep track of the clipboard state so that we avoid filtering too much
-	mClipboardState = LLClipboard::instance().getGeneration();
-	
-	// Initialize base class params.
-	LLPanel::initFromParams(mParams);
-}
-
-LLInventoryPanel::~LLInventoryPanel()
-{
-	U32 sort_order = getFolderViewModel()->getSorter().getSortOrder();
-    if (mSortOrderSetting != INHERIT_SORT_ORDER)
-    {
-        gSavedSettings.setU32(mSortOrderSetting, sort_order);
-    }
-    
-    clearFolderRoot();
 }
 
 /*virtual*/
@@ -360,8 +385,11 @@ void LLInventoryPanel::onVisibilityChange(BOOL new_visibility)
 {
     if (new_visibility && mViewsInitialized == VIEWS_UNINITIALIZED)
     {
-        mViewsInitialized = VIEWS_INITIALIZING;
-        gIdleCallbacks.addFunction(onIdle, (void*)this);
+        // first call can be from tab initialization
+        if (gFloaterView->getParentFloater(this) != NULL)
+        {
+            initializeViewBuilding();
+        }
     }
     LLPanel::onVisibilityChange(new_visibility);
 }
@@ -747,7 +775,7 @@ LLUUID LLInventoryPanel::getRootFolderID()
                 LLStringExplicit label(mParams.start_folder.name());
                 setLabel(label);
                 
-				root_id = gInventory.findCategoryUUIDForType(preferred_type, false);
+				root_id = gInventory.findCategoryUUIDForType(preferred_type);
 				if (root_id.isNull())
 				{
 					LL_WARNS() << "Could not find folder of type " << preferred_type << LL_ENDL;
@@ -882,6 +910,7 @@ void LLInventoryPanel::idle(void* user_data)
 void LLInventoryPanel::initializeViews(F64 max_time)
 {
 	if (!gInventory.isInventoryUsable()) return;
+    if (!mRootInited) return;
 
     mViewsInitialized = VIEWS_BUILDING;
 
@@ -909,7 +938,10 @@ void LLInventoryPanel::initializeViews(F64 max_time)
 
 	gIdleCallbacks.addFunction(idle, this);
 	
-	openStartFolderOrMyInventory();
+    if(mParams.open_first_folder)
+    {
+        openStartFolderOrMyInventory();
+    }
 	
 	// Special case for new user login
 	if (gAgent.isFirstLogin())
@@ -941,8 +973,8 @@ LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * br
 	params.tool_tip = params.name;
     params.allow_drop = allow_drop;
 
-	params.font_color = (bridge->isLibraryItem() ? sLibraryColor : (bridge->isLink() ? sLinkColor : sDefaultColor));
-	params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : (bridge->isLink() ? sLinkColor : sDefaultHighlightColor));
+	params.font_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultColor);
+	params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultHighlightColor);
 	
 	return LLUICtrlFactory::create<LLFolderViewFolder>(params);
 }
@@ -958,8 +990,8 @@ LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge
 	params.rect = LLRect (0, 0, 0, 0);
 	params.tool_tip = params.name;
 
-	params.font_color = (bridge->isLibraryItem() ? sLibraryColor : (bridge->isLink() ? sLinkColor : sDefaultColor));
-	params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : (bridge->isLink() ? sLinkColor : sDefaultHighlightColor));
+	params.font_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultColor);
+	params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultHighlightColor);
 	
 	return LLUICtrlFactory::create<LLFolderViewItem>(params);
 }
@@ -1015,8 +1047,11 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
                                                   LLInventoryObject const* objectp,
                                                   LLFolderViewItem *folder_view_item,
                                                   LLFolderViewFolder *parent_folder,
-                                                  const EBuildModes &mode)
+                                                  const EBuildModes &mode,
+                                                  S32 depth)
 {
+    depth++;
+
     // Force the creation of an extra root level folder item if required by the inventory panel (default is "false")
     bool allow_drop = true;
     bool create_root = false;
@@ -1046,7 +1081,7 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
 			if (objectp->getType() >= LLAssetType::AT_COUNT)
   			{
 				// Example: Happens when we add assets of new, not yet supported type to library
-				LL_DEBUGS() << "LLInventoryPanel::buildViewsTree called with unknown objectp->mType : "
+				LL_DEBUGS("Inventory") << "LLInventoryPanel::buildViewsTree called with unknown objectp->mType : "
 				<< ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID()
 				<< LL_ENDL;
 
@@ -1116,7 +1151,8 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
         }
 	}
 
-    bool create_children = folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY;
+    bool create_children = folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY
+                            && (mBuildChildrenViews || depth == 0);
 
     if (create_children)
     {
@@ -1136,12 +1172,15 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
                 {
                     create_children = false;
                     // run it again for the sake of creating children
-                    mBuildViewsQueue.push_back(id);
+                    if (mBuildChildrenViews || depth == 0)
+                    {
+                        mBuildViewsQueue.push_back(id);
+                    }
                 }
                 else
                 {
                     create_children = true;
-                    folder_view_item->setChildrenInited(true);
+                    folder_view_item->setChildrenInited(mBuildChildrenViews);
                 }
                 break;
             }
@@ -1149,7 +1188,10 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
             {
                 create_children = false;
                 // run it to create children, current caller is only interested in current view
-                mBuildViewsQueue.push_back(id);
+                if (mBuildChildrenViews || depth == 0)
+                {
+                    mBuildViewsQueue.push_back(id);
+                }
                 break;
             }
             case BUILD_ONE_FOLDER:
@@ -1179,7 +1221,13 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
 		LLViewerInventoryItem::item_array_t* items;
 		mInventory->lockDirectDescendentArrays(id, categories, items);
 
+        // Make sure panel won't lock in a loop over existing items if
+        // folder is enormous and at least some work gets done
+        const S32 MIN_ITEMS_PER_CALL = 500;
+        const S32 starting_item_count = mItemMap.size();
+
         LLFolderViewFolder *parentp = dynamic_cast<LLFolderViewFolder*>(folder_view_item);
+        bool done = true;
 
 		if(categories)
         {
@@ -1197,11 +1245,28 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
                         // each time, especially since content is growing, we can just
                         // iter over copy of mItemMap in some way
                         LLFolderViewItem* view_itemp = getItemByID(cat->getUUID());
-                        buildViewsTree(cat->getUUID(), id, cat, view_itemp, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode));
+                        buildViewsTree(cat->getUUID(), id, cat, view_itemp, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode), depth);
                     }
                     else
                     {
-                        buildViewsTree(cat->getUUID(), id, cat, NULL, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode));
+                        buildViewsTree(cat->getUUID(), id, cat, NULL, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode), depth);
+                    }
+                }
+
+                if (!mBuildChildrenViews
+                    && mode == BUILD_TIMELIMIT
+                    && MIN_ITEMS_PER_CALL + starting_item_count < mItemMap.size())
+                {
+                    // Single folder view, check if we still have time
+                    // 
+                    // Todo: make sure this causes no dupplciates, breaks nothing,
+                    // especially filters and arrange
+                    F64 curent_time = LLTimer::getTotalSeconds();
+                    if (mBuildViewsEndTime < curent_time)
+                    {
+                        mBuildViewsQueue.push_back(id);
+                        done = false;
+                        break;
                     }
                 }
 			}
@@ -1221,10 +1286,33 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
                     // each time, especially since content is growing, we can just
                     // iter over copy of mItemMap in some way
                     LLFolderViewItem* view_itemp = getItemByID(item->getUUID());
-                    buildViewsTree(item->getUUID(), id, item, view_itemp, parentp, mode);
+                    buildViewsTree(item->getUUID(), id, item, view_itemp, parentp, mode, depth);
+                }
+
+                if (!mBuildChildrenViews
+                    && mode == BUILD_TIMELIMIT
+                    && MIN_ITEMS_PER_CALL + starting_item_count < mItemMap.size())
+                {
+                    // Single folder view, check if we still have time
+                    // 
+                    // Todo: make sure this causes no dupplciates, breaks nothing,
+                    // especially filters and arrange
+                    F64 curent_time = LLTimer::getTotalSeconds();
+                    if (mBuildViewsEndTime < curent_time)
+                    {
+                        mBuildViewsQueue.push_back(id);
+                        done = false;
+                        break;
+                    }
                 }
 			}
 		}
+
+        if (!mBuildChildrenViews && done)
+        {
+            // flat list is done initializing folder
+            folder_view_item->setChildrenInited(true);
+        }
 		mInventory->unlockDirectDescendentArrays(id);
 	}
 	
@@ -1289,6 +1377,37 @@ BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask)
 	return TRUE;
 }
 
+BOOL LLInventoryPanel::handleToolTip(S32 x, S32 y, MASK mask)
+{
+	if (const LLFolderViewItem* hover_item_p = (!mFolderRoot.isDead()) ? mFolderRoot.get()->getHoveredItem() : nullptr)
+	{
+		if (const LLFolderViewModelItemInventory* vm_item_p = static_cast<const LLFolderViewModelItemInventory*>(hover_item_p->getViewModelItem()))
+		{
+            LLSD params;
+            params["inv_type"] = vm_item_p->getInventoryType();
+            params["thumbnail_id"] = vm_item_p->getThumbnailUUID();
+            params["item_id"] = vm_item_p->getUUID();
+
+            // tooltip should only show over folder, but screen
+            // rect includes items under folder as well
+            LLRect actionable_rect = hover_item_p->calcScreenRect();
+            if (hover_item_p->isOpen() && hover_item_p->hasVisibleChildren())
+            {
+                actionable_rect.mBottom = actionable_rect.mTop - hover_item_p->getItemHeight();
+            }
+
+			LLToolTipMgr::instance().show(LLToolTip::Params()
+					.message(hover_item_p->getToolTip())
+					.sticky_rect(actionable_rect)
+					.delay_time(LLView::getTooltipTimeout())
+					.create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1))
+					.create_params(params));
+			return TRUE;
+		}
+	}
+	return LLPanel::handleToolTip(x, y, mask);
+}
+
 BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 								   EDragAndDropType cargo_type,
 								   void* cargo_data,
@@ -1334,6 +1453,45 @@ void LLInventoryPanel::onFocusReceived()
 	// inventory now handles cut/copy/paste/delete
 	LLEditMenuHandler::gEditMenuHandler = mFolderRoot.get();
 
+    // Tab support, when tabbing into this view, select first item
+    // (ideally needs to account for scroll)
+    bool select_first = mSelectThisID.isNull() && mFolderRoot.get() && mFolderRoot.get()->getSelectedCount() == 0;
+
+    if (select_first)
+    {
+        LLFolderViewFolder::folders_t::const_iterator folders_it = mFolderRoot.get()->getFoldersBegin();
+        LLFolderViewFolder::folders_t::const_iterator folders_end = mFolderRoot.get()->getFoldersEnd();
+
+        for (; folders_it != folders_end; ++folders_it)
+        {
+            const LLFolderViewFolder* folder_view = *folders_it;
+            if (folder_view->getVisible())
+            {
+                const LLFolderViewModelItemInventory* modelp = static_cast<const LLFolderViewModelItemInventory*>(folder_view->getViewModelItem());
+                setSelectionByID(modelp->getUUID(), TRUE);
+                select_first = false;
+                break;
+            }
+        }
+    }
+
+    if (select_first)
+    {
+        LLFolderViewFolder::items_t::const_iterator items_it = mFolderRoot.get()->getItemsBegin();
+        LLFolderViewFolder::items_t::const_iterator items_end = mFolderRoot.get()->getItemsEnd();
+
+        for (; items_it != items_end; ++items_it)
+        {
+            const LLFolderViewItem* item_view = *items_it;
+            if (item_view->getVisible())
+            {
+                const LLFolderViewModelItemInventory* modelp = static_cast<const LLFolderViewModelItemInventory*>(item_view->getViewModelItem());
+                setSelectionByID(modelp->getUUID(), TRUE);
+                break;
+            }
+        }
+    }
+
 	LLPanel::onFocusReceived();
 }
 
@@ -1384,6 +1542,7 @@ void LLInventoryPanel::setSelectCallback(const boost::function<void (const std::
 	{
 		mFolderRoot.get()->setSelectCallback(cb);
 	}
+    mSelectionCallback = cb;
 }
 
 void LLInventoryPanel::clearSelection()
@@ -1430,6 +1589,10 @@ void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& it
 		{
 			fv->startRenamingSelectedItem();
 		}
+        else
+        {
+            LL_DEBUGS("Inventory") << "Failed to start renemr, no items selected" << LL_ENDL;
+        }
 	}
 
 	std::set<LLFolderViewItem*> selected_items = mFolderRoot.get()->getSelectionList();
@@ -1665,6 +1828,11 @@ void LLInventoryPanel::fileUploadLocation(const LLSD& userdata)
     }
 }
 
+void LLInventoryPanel::openSingleViewInventory(LLUUID folder_id)
+{
+    LLPanelMainInventory::newFolderWindow(folder_id.isNull() ? LLFolderBridge::sSelf.get()->getUUID() : folder_id);
+}
+
 void LLInventoryPanel::purgeSelectedItems()
 {
     if (!mFolderRoot.get()) return;
@@ -1801,22 +1969,49 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open)
 }
 
 //static
-void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const LLUUID& obj_id, BOOL main_panel, BOOL take_keyboard_focus, BOOL reset_filter)
+void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const LLUUID& obj_id, BOOL use_main_panel, BOOL take_keyboard_focus, BOOL reset_filter)
 {
 	LLSidepanelInventory* sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
 	sidepanel_inventory->showInventoryPanel();
 
 	bool in_inbox = (gInventory.isObjectDescendentOf(obj_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX)));
 
-	if (!in_inbox && (main_panel || !sidepanel_inventory->getMainInventoryPanel()->isRecentItemsPanelSelected()))
+	if (!in_inbox && (use_main_panel || !sidepanel_inventory->getMainInventoryPanel()->isRecentItemsPanelSelected()))
 	{
 		sidepanel_inventory->selectAllItemsPanel();
 	}
+
+    LLFloater* inventory_floater = LLFloaterSidePanelContainer::getTopmostInventoryFloater();
+    if(!auto_open && inventory_floater && inventory_floater->getVisible())
+    {
+        LLSidepanelInventory *inventory_panel = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
+        LLPanelMainInventory* main_panel = inventory_panel->getMainInventoryPanel();
+        if(main_panel->isSingleFolderMode() && main_panel->isGalleryViewMode())
+        {
+            LL_DEBUGS("Inventory") << "Opening gallery panel for item" << obj_id << LL_ENDL;
+            main_panel->setGallerySelection(obj_id);
+            return;
+        }
+    }
+
+    LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
+    if (main_inventory && main_inventory->isSingleFolderMode()
+        && use_main_panel)
+    {
+        const LLInventoryObject *obj = gInventory.getObject(obj_id);
+        if (obj)
+        {
+            LL_DEBUGS("Inventory") << "Opening main inventory panel for item" << obj_id << LL_ENDL;
+            main_inventory->setSingleFolderViewRoot(obj->getParentUUID(), false);
+            main_inventory->setGallerySelection(obj_id);
+            return;
+        }
+    }
 	LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open);
 
 	if (active_panel)
 	{
-		LL_DEBUGS("Messaging") << "Highlighting" << obj_id  << LL_ENDL;
+		LL_DEBUGS("Messaging", "Inventory") << "Highlighting" << obj_id  << LL_ENDL;
 
 		if (reset_filter)
 		{
@@ -1835,7 +2030,7 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L
 				inventory_panel->setSelection(obj_id, take_keyboard_focus);
 			}
 		}
-		else
+		else if (auto_open)
 		{
 			LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
 			if (floater_inventory)
@@ -1844,9 +2039,33 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L
 			}
 			active_panel->setSelection(obj_id, take_keyboard_focus);
 		}
+        else
+        {
+            // Created items are going to receive proper focus from callbacks
+            active_panel->setSelection(obj_id, take_keyboard_focus);
+        }
 	}
 }
 
+void LLInventoryPanel::setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id)
+{
+
+    LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
+    for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+    {
+        LLFloaterSidePanelContainer* inventory_floater = dynamic_cast<LLFloaterSidePanelContainer*>(*iter);
+        LLSidepanelInventory* sidepanel_inventory = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
+
+        LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
+        if (main_inventory && panel->hasAncestor(main_inventory) && !main_inventory->isSingleFolderMode())
+        {
+            main_inventory->initSingleFolderRoot(folder_id);
+            main_inventory->toggleViewMode();
+            main_inventory->setSingleFolderViewRoot(folder_id, false);
+        }
+    }
+}
+
 void LLInventoryPanel::addHideFolderType(LLFolderType::EType folder_type)
 {
 	getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << folder_type));
@@ -2054,10 +2273,204 @@ LLInventoryRecentItemsPanel::LLInventoryRecentItemsPanel( const Params& params)
 	mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER;
 }
 
+static LLDefaultChildRegistry::Register<LLInventorySingleFolderPanel> t_single_folder_inventory_panel("single_folder_inventory_panel");
+
+LLInventorySingleFolderPanel::LLInventorySingleFolderPanel(const Params& params)
+    : LLInventoryPanel(params)
+{
+    mBuildChildrenViews = false;
+    getFilter().setSingleFolderMode(true);
+    getFilter().setEmptyLookupMessage("InventorySingleFolderNoMatches");
+    getFilter().setDefaultEmptyLookupMessage("InventorySingleFolderEmpty");
+
+    mCommitCallbackRegistrar.replace("Inventory.DoToSelected", boost::bind(&LLInventorySingleFolderPanel::doToSelected, this, _2));
+    mCommitCallbackRegistrar.replace("Inventory.DoCreate", boost::bind(&LLInventorySingleFolderPanel::doCreate, this, _2));
+    mCommitCallbackRegistrar.replace("Inventory.Share", boost::bind(&LLInventorySingleFolderPanel::doShare, this));
+}
+
+LLInventorySingleFolderPanel::~LLInventorySingleFolderPanel()
+{
+}
+
+void LLInventorySingleFolderPanel::initFromParams(const Params& p)
+{
+    mFolderID = gInventory.getRootFolderID();
+
+    mParams = p;
+    LLPanel::initFromParams(mParams);
+}
+
+void LLInventorySingleFolderPanel::initFolderRoot(const LLUUID& start_folder_id)
+{
+    if(mRootInited) return;
+
+    mRootInited = true;
+    if(start_folder_id.notNull())
+    {
+        mFolderID = start_folder_id;
+    }
+
+    mParams.open_first_folder = false;
+    mParams.start_folder.id = mFolderID;
+
+    LLInventoryPanel::initFolderRoot();
+    mFolderRoot.get()->setSingleFolderMode(true);
+}
+
+void LLInventorySingleFolderPanel::changeFolderRoot(const LLUUID& new_id)
+{
+    if (mFolderID != new_id)
+    {
+        if(mFolderID.notNull())
+        {
+            mBackwardFolders.push_back(mFolderID);
+        }
+        mFolderID = new_id;
+        updateSingleFolderRoot();
+    }
+}
+
+void LLInventorySingleFolderPanel::onForwardFolder()
+{
+    if(isForwardAvailable())
+    {
+        mBackwardFolders.push_back(mFolderID);
+        mFolderID = mForwardFolders.back();
+        mForwardFolders.pop_back();
+        updateSingleFolderRoot();
+    }
+}
+
+void LLInventorySingleFolderPanel::onBackwardFolder()
+{
+    if(isBackwardAvailable())
+    {
+        mForwardFolders.push_back(mFolderID);
+        mFolderID = mBackwardFolders.back();
+        mBackwardFolders.pop_back();
+        updateSingleFolderRoot();
+    }
+}
+
+void LLInventorySingleFolderPanel::clearNavigationHistory()
+{
+    mForwardFolders.clear();
+    mBackwardFolders.clear();
+}
+
+bool LLInventorySingleFolderPanel::isBackwardAvailable()
+{
+    return (!mBackwardFolders.empty() && (mFolderID != mBackwardFolders.back()));
+}
+
+bool LLInventorySingleFolderPanel::isForwardAvailable()
+{
+    return (!mForwardFolders.empty() && (mFolderID != mForwardFolders.back()));
+}
+
+boost::signals2::connection LLInventorySingleFolderPanel::setRootChangedCallback(root_changed_callback_t cb)
+{
+    return mRootChangedSignal.connect(cb);
+}
+
+void LLInventorySingleFolderPanel::updateSingleFolderRoot()
+{
+    if (mFolderID != getRootFolderID())
+    {
+        mRootChangedSignal();
+
+        LLUUID root_id = mFolderID;
+        if (mFolderRoot.get())
+        {
+            mItemMap.clear();
+            mFolderRoot.get()->destroyRoot();
+        }
+
+        mCommitCallbackRegistrar.pushScope();
+        {
+            LLFolderView* folder_view = createFolderRoot(root_id);
+            folder_view->setChildrenInited(false);
+            mFolderRoot = folder_view->getHandle();
+            mFolderRoot.get()->setSingleFolderMode(true);
+            addItemID(root_id, mFolderRoot.get());
+
+            LLRect scroller_view_rect = getRect();
+            scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
+            LLScrollContainer::Params scroller_params(mParams.scroll());
+            scroller_params.rect(scroller_view_rect);
+
+            if (mScroller)
+            {
+                removeChild(mScroller);
+                delete mScroller;
+                mScroller = NULL;
+            }
+            mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
+            addChild(mScroller);
+            mScroller->addChild(mFolderRoot.get());
+            mFolderRoot.get()->setScrollContainer(mScroller);
+            mFolderRoot.get()->setFollowsAll();
+            mFolderRoot.get()->addChild(mFolderRoot.get()->mStatusTextBox);
+
+            if (!mSelectionCallback.empty())
+            {
+                mFolderRoot.get()->setSelectCallback(mSelectionCallback);
+            }
+        }
+        mCommitCallbackRegistrar.popScope();
+        mFolderRoot.get()->setCallbackRegistrar(&mCommitCallbackRegistrar);
+
+        buildNewViews(mFolderID);
+        
+        LLFloater* root_floater = gFloaterView->getParentFloater(this);
+        if(root_floater)
+        {
+            root_floater->setFocus(true);
+        }
+    }
+}
+
+bool LLInventorySingleFolderPanel::hasVisibleItems()
+{
+    return mFolderRoot.get()->hasVisibleChildren();
+}
+
+void LLInventorySingleFolderPanel::doCreate(const LLSD& userdata)
+{
+    std::string type_name = userdata.asString();
+    LLUUID dest_id = LLFolderBridge::sSelf.get()->getUUID();
+    if (("category" == type_name) || ("outfit" == type_name))
+    {
+        changeFolderRoot(dest_id);
+    }
+    reset_inventory_filter();
+    menu_create_inventory_item(this, dest_id, userdata);
+}
+
+void LLInventorySingleFolderPanel::doToSelected(const LLSD& userdata)
+{
+    if (("open_in_current_window" == userdata.asString()))
+    {
+        changeFolderRoot(LLFolderBridge::sSelf.get()->getUUID());
+        return;
+    }
+    LLInventoryPanel::doToSelected(userdata);
+}
+
+void LLInventorySingleFolderPanel::doShare()
+{
+    LLAvatarActions::shareWithAvatars(this);
+}
 /************************************************************************/
 /* Asset Pre-Filtered Inventory Panel related class                     */
 /************************************************************************/
 
+LLAssetFilteredInventoryPanel::LLAssetFilteredInventoryPanel(const Params& p)
+    : LLInventoryPanel(p)
+{
+}
+
+
 void LLAssetFilteredInventoryPanel::initFromParams(const Params& p)
 {
     // Init asset types
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index 2ac3f03579c3b2535dd90e9f162a01f1bf494393..3c17e1fe13bffdf8c84068c86b1cc98098dd9bd7 100644
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -109,6 +109,7 @@ class LLInventoryPanel : public LLPanel
 		Optional<LLFolderView::Params>		folder_view;
 		Optional<LLFolderViewFolder::Params> folder;
 		Optional<LLFolderViewItem::Params>	 item;
+        Optional<bool>                       open_first_folder;
 
         // All item and folder views will be initialized on init if true (default)
         // Will initialize on visibility change otherwise.
@@ -128,6 +129,7 @@ class LLInventoryPanel : public LLPanel
             show_root_folder("show_root_folder", false),
             allow_drop_on_root("allow_drop_on_root", true),
             use_marketplace_folders("use_marketplace_folders", false),
+            open_first_folder("open_first_folder", true),
 			scroll("scroll"),
 			accepts_drag_and_drop("accepts_drag_and_drop"),
 			folder_view("folder_view"),
@@ -161,22 +163,23 @@ class LLInventoryPanel : public LLPanel
 	LLFolderViewModelInventory& getRootViewModel() { return mInventoryViewModel; }
 
 	// LLView methods
-	/*virtual*/ void onVisibilityChange(BOOL new_visibility);
-	void draw();
-	/*virtual*/ BOOL handleKeyHere( KEY key, MASK mask );
-	BOOL handleHover(S32 x, S32 y, MASK mask);
+	/*virtual*/ void onVisibilityChange(BOOL new_visibility) override;
+	void draw() override;
+	/*virtual*/ BOOL handleKeyHere( KEY key, MASK mask ) override;
+	BOOL handleHover(S32 x, S32 y, MASK mask) override;
 	/*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 								   EDragAndDropType cargo_type,
 								   void* cargo_data,
 								   EAcceptance* accept,
-								   std::string& tooltip_msg);
+								   std::string& tooltip_msg) override;
+	            BOOL handleToolTip(S32 x, S32 y, MASK mask) override;
 	// LLUICtrl methods
-	 /*virtual*/ void onFocusLost();
-	 /*virtual*/ void onFocusReceived();
+	 /*virtual*/ void onFocusLost() override;
+	 /*virtual*/ void onFocusReceived() override;
      void onFolderOpening(const LLUUID &id);
 
 	// LLBadgeHolder methods
-	bool addBadge(LLBadge * badge);
+	bool addBadge(LLBadge * badge) override;
 
 	// Call this method to set the selection.
 	void openAllFolders();
@@ -213,6 +216,7 @@ class LLInventoryPanel : public LLPanel
 	LLUUID getRootFolderID();
 	LLScrollContainer* getScrollableContainer() { return mScroller; }
     bool getAllowDropOnRoot() { return mParams.allow_drop_on_root; }
+    bool areViewsInitialized() { return mViewsInitialized == VIEWS_INITIALIZED && mFolderRoot.get() && !mFolderRoot.get()->needsArrange(); }
 	
 	void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action);
 	
@@ -223,6 +227,7 @@ class LLInventoryPanel : public LLPanel
 	void doCreate(const LLSD& userdata);
 	bool beginIMSession();
 	void fileUploadLocation(const LLSD& userdata);
+    void openSingleViewInventory(LLUUID folder_id = LLUUID());
 	void purgeSelectedItems();
 	bool attachObject(const LLSD& userdata);
 	static void idle(void* user_data);
@@ -243,10 +248,10 @@ class LLInventoryPanel : public LLPanel
 
 	static void openInventoryPanelAndSetSelection(BOOL auto_open,
 													const LLUUID& obj_id,
-													BOOL main_panel = FALSE,
+													BOOL use_main_panel = FALSE,
 													BOOL take_keyboard_focus = TAKE_FOCUS_YES,
 													BOOL reset_filter = FALSE);
-
+    static void setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id);
 	void addItemID(const LLUUID& id, LLFolderViewItem* itemp);
 	void removeItemID(const LLUUID& id);
 	LLFolderViewItem* getItemByID(const LLUUID& id);
@@ -264,6 +269,10 @@ class LLInventoryPanel : public LLPanel
 
     static void callbackPurgeSelectedItems(const LLSD& notification, const LLSD& response, const std::vector<LLUUID> inventory_selected);
 
+    void changeFolderRoot(const LLUUID& new_id) {};
+    void initFolderRoot();
+    void initializeViewBuilding();
+
 protected:
 	void openStartFolderOrMyInventory(); // open the first level of inventory
 	void onItemsCompletion();			// called when selected items are complete
@@ -300,6 +309,9 @@ class LLInventoryPanel : public LLPanel
 	 */
 	const LLInventoryFolderViewModelBuilder* mInvFVBridgeBuilder;
 
+    bool mBuildChildrenViews; // build root and children
+    bool mRootInited;
+
 
 	//--------------------------------------------------------------------
 	// Sorting
@@ -359,6 +371,8 @@ class LLInventoryPanel : public LLPanel
     virtual LLFolderView * createFolderRoot(LLUUID root_id );
 	virtual LLFolderViewFolder*	createFolderViewFolder(LLInvFVBridge * bridge, bool allow_drop);
 	virtual LLFolderViewItem*	createFolderViewItem(LLInvFVBridge * bridge);
+
+    boost::function<void(const std::deque<LLFolderViewItem*>& items, BOOL user_action)> mSelectionCallback;
 private:
     // buildViewsTree does not include some checks and is meant
     // for recursive use, use buildNewViews() for first call
@@ -367,7 +381,8 @@ class LLInventoryPanel : public LLPanel
                                               LLInventoryObject const* objectp,
                                               LLFolderViewItem *target_view,
                                               LLFolderViewFolder *parent_folder_view,
-                                              const EBuildModes &mode);
+                                              const EBuildModes &mode,
+                                              S32 depth = -1);
 
     typedef enum e_views_initialization_state
     {
@@ -383,6 +398,55 @@ class LLInventoryPanel : public LLPanel
     std::deque<LLUUID>			mBuildViewsQueue;
 };
 
+
+class LLInventorySingleFolderPanel : public LLInventoryPanel
+{
+public:
+    struct Params : public LLInitParam::Block<Params, LLInventoryPanel::Params>
+    {};
+
+    void initFromParams(const Params& p);
+    bool isSelectionRemovable() { return false; }
+
+    void initFolderRoot(const LLUUID& start_folder_id = LLUUID::null);
+
+    void changeFolderRoot(const LLUUID& new_id);
+    void onForwardFolder();
+    void onBackwardFolder();
+    void clearNavigationHistory();
+    LLUUID getSingleFolderRoot() { return mFolderID; }
+
+    void doCreate(const LLSD& userdata);
+    void doToSelected(const LLSD& userdata);
+    void doShare();
+
+    bool isBackwardAvailable();
+    bool isForwardAvailable();
+
+    bool hasVisibleItems();
+
+    void setNavBackwardList(std::list<LLUUID> backward_list) { mBackwardFolders = backward_list; }
+    void setNavForwardList(std::list<LLUUID> forward_list) { mForwardFolders = forward_list; }
+    std::list<LLUUID> getNavBackwardList() { return mBackwardFolders; }
+    std::list<LLUUID> getNavForwardList() { return mForwardFolders; }
+
+    typedef boost::function<void()> root_changed_callback_t;
+    boost::signals2::connection setRootChangedCallback(root_changed_callback_t cb);
+
+protected:
+    LLInventorySingleFolderPanel(const Params& params);
+    ~LLInventorySingleFolderPanel();
+    void updateSingleFolderRoot();
+
+    friend class LLUICtrlFactory;
+    
+    LLUUID mFolderID;
+    std::list<LLUUID> mBackwardFolders;
+    std::list<LLUUID> mForwardFolders;
+
+    boost::signals2::signal<void()> mRootChangedSignal;
+};
+
 /************************************************************************/
 /* Asset Pre-Filtered Inventory Panel related class                     */
 /* Exchanges filter's flexibility for speed of generation and           */
@@ -402,7 +466,7 @@ class LLAssetFilteredInventoryPanel : public LLInventoryPanel
 
     void initFromParams(const Params& p);
 protected:
-    LLAssetFilteredInventoryPanel(const Params& p) : LLInventoryPanel(p) {}
+    LLAssetFilteredInventoryPanel(const Params& p);
     friend class LLUICtrlFactory;
 public:
     ~LLAssetFilteredInventoryPanel() {}
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 8a269dc382c1185ae64771f9528fb950795ceb1d..8965be4944f60569497bdb385b15e29c443cae8b 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -86,6 +86,7 @@ LLLoginInstance::LLLoginInstance() :
 	mLoginModule(new LLLogin()),
 	mNotifications(NULL),
 	mLoginState("offline"),
+    mSaveMFA(true),
 	mAttemptComplete(false),
 	mTransferRate(0.0f),
 	mDispatcher("LLLoginInstance", "change")
@@ -456,10 +457,7 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
             gViewerWindow->setShowProgress(FALSE);
         }
 
-        LLSD args(llsd::map( "MESSAGE", LLTrans::getString(response["message_id"].asString()) ));
-        LLSD payload;
-        LLNotificationsUtil::add("PromptMFAToken", args, payload,
-            boost::bind(&LLLoginInstance::handleMFAChallenge, this, _1, _2));
+        showMFAChallange(LLTrans::getString(response["message_id"].asString()));
     }
     else if(   reason_response == "key"
             || reason_response == "presence"
@@ -547,10 +545,7 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
         {
             // SL-18511 this TOS failure happened while we are in the middle of an MFA challenge/response.
             // the previously entered token is very likely expired, so prompt again
-            LLSD args(llsd::map( "MESSAGE", LLTrans::getString("LoginFailedAuthenticationMFARequired") ));
-            LLSD payload;
-            LLNotificationsUtil::add("PromptMFAToken", args, payload,
-                boost::bind(&LLLoginInstance::handleMFAChallenge, this, _1, _2));
+            showMFAChallange(LLTrans::getString("LoginFailedAuthenticationMFARequired"));
         }
         else
         {
@@ -568,6 +563,22 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
     return true;
 }
 
+void LLLoginInstance::showMFAChallange(const std::string& message)
+{
+    LLSD args(llsd::map("MESSAGE", message));
+    LLSD payload;
+    if (gSavedSettings.getBOOL("RememberUser"))
+    {
+        LLNotificationsUtil::add("PromptMFATokenWithSave", args, payload,
+                                 boost::bind(&LLLoginInstance::handleMFAChallenge, this, _1, _2));
+    }
+    else
+    {
+        LLNotificationsUtil::add("PromptMFAToken", args, payload,
+                                 boost::bind(&LLLoginInstance::handleMFAChallenge, this, _1, _2));
+    }
+}
+
 bool LLLoginInstance::handleMFAChallenge(LLSD const & notif, LLSD const & response)
 {
     bool continue_clicked = response["continue"].asBoolean();
@@ -583,6 +594,7 @@ bool LLLoginInstance::handleMFAChallenge(LLSD const & notif, LLSD const & respon
 
         // Set the request data to true and retry login.
         mRequestData["params"]["token"] = token;
+        mSaveMFA = response.has("ignore") ? response["ignore"].asBoolean() : false;
         reconnect();
     } else {
         LL_INFOS("LLLogin") << "PromptMFAToken: no token, attemptComplete" << LL_ENDL;
diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h
index 48d75544ee28381be2de59b90b38d58e7ba19b68..5ccaa5b7b4e63572fad1932e2cf1840e299a486a 100644
--- a/indra/newview/lllogininstance.h
+++ b/indra/newview/lllogininstance.h
@@ -55,6 +55,7 @@ class LLLoginInstance final : public LLSingleton<LLLoginInstance>
 	bool authSuccess() { return mAttemptComplete && mLoginState == "online"; }
 
 	const std::string& getLoginState() { return mLoginState; }
+    bool saveMFA() const { return mSaveMFA; }
 	bool hasResponse(const std::string& key) { return getResponse().has(key); }
 	LLSD getResponse(const std::string& key) { return getResponse()[key]; }
 	LLSD getResponse();
@@ -84,6 +85,7 @@ class LLLoginInstance final : public LLSingleton<LLLoginInstance>
 	void syncWithUpdater(ResponsePtr resp, const LLSD& notification, const LLSD& response);
 
 	bool handleTOSResponse(bool v, const std::string& key);
+    void showMFAChallange(const std::string& message);
     bool handleMFAChallenge(LLSD const & notif, LLSD const & response);
 
 	void attemptComplete();
@@ -95,6 +97,7 @@ class LLLoginInstance final : public LLSingleton<LLLoginInstance>
 	LLSD mRequestData;
 	LLSD mResponseData;
 	bool mAttemptComplete;
+    bool mSaveMFA;
 	F64 mTransferRate;
 	std::string mSerialNumber;
 	int mLastExecEvent;
diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp
index 1f77bb4e3d777f3c8134df574e11ef1d7ca92cce..c5526af89fc5ecdbb2157d4f18991d3f87fdd194 100644
--- a/indra/newview/llmarketplacefunctions.cpp
+++ b/indra/newview/llmarketplacefunctions.cpp
@@ -698,10 +698,9 @@ void LLMarketplaceInventoryObserver::onIdleProcessQueue(void *userdata)
                 // If it's a folder known to the marketplace, let's check it's in proper shape
                 if (LLMarketplaceData::instance().isListed(*id_it) || LLMarketplaceData::instance().isVersionFolder(*id_it))
                 {
-                    LLInventoryCategory* cat = (LLInventoryCategory*)(obj);
                     // can trigger notifyObservers
                     // can cause more structural changes
-                    validate_marketplacelistings(cat);
+                    LLMarketplaceValidator::getInstance()->validateMarketplaceListings(obj->getUUID());
                 }
             }
             else
@@ -895,7 +894,7 @@ void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot
 // Get/Post/Put requests to the SLM Server using the SLM API
 void LLMarketplaceData::getSLMListings()
 {
-    const LLUUID marketplaceFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+    const LLUUID marketplaceFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
     setUpdating(marketplaceFolderId, true);
 
     LLCoros::instance().launch("getSLMListings",
@@ -1784,7 +1783,7 @@ bool LLMarketplaceData::isUpdating(const LLUUID& folder_id, S32 depth)
     }
     else
     {
-        const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+        const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
         std::set<LLUUID>::iterator it = mPendingUpdateSet.find(marketplace_listings_uuid);
         if (it != mPendingUpdateSet.end())
         {
@@ -1828,8 +1827,7 @@ void LLMarketplaceData::decrementValidationWaiting(const LLUUID& folder_id, S32
         if (found->second <= 0)
         {
             mValidationWaitingList.erase(found);
-            LLInventoryCategory *cat = gInventory.getCategory(folder_id);
-            validate_marketplacelistings(cat);
+            LLMarketplaceValidator::getInstance()->validateMarketplaceListings(folder_id);
             update_marketplace_category(folder_id);
             gInventory.notifyObservers();
         }
diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index a94c658f54327dde5dbdf1da035abcc5a40ffa15..e9af183ed24a47f57210a6bc32ab39f9bdc9287c 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -1537,7 +1537,7 @@ void LLMaterialEditor::onSaveAsMsgCallback(const LLSD& notification, const LLSD&
             }
             if (item)
             {
-                const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+                const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
                 LLUUID parent_id = item->getParentUUID();
                 if (mObjectUUID.notNull() || marketplacelistings_id == parent_id || gInventory.isObjectDescendentOf(item->getUUID(), gInventory.getLibraryRootFolderID()))
                 {
diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp
index ab2f56c13da195288a0ec7d1a5b4eaa9ccccfbe3..29c1705d3327c5486f4bda759a8f63eee7e7597c 100644
--- a/indra/newview/lloutfitgallery.cpp
+++ b/indra/newview/lloutfitgallery.cpp
@@ -33,12 +33,11 @@
 
 #include "llaccordionctrltab.h"
 #include "llappearancemgr.h"
-#include "llagentbenefits.h"
 #include "llerror.h"
 #include "llfilepicker.h"
 #include "llfloaterperms.h"
 #include "llfloaterreg.h"
-#include "llfloatersimpleoutfitsnapshot.h"
+#include "llfloatersimplesnapshot.h"
 #include "llfloatertexturepicker.h"
 #include "llimagedimensionsinfo.h"
 #include "llinventoryfunctions.h"
@@ -62,7 +61,6 @@ const S32 GALLERY_ITEMS_PER_ROW_MIN = 2;
 
 LLOutfitGallery::LLOutfitGallery(const LLOutfitGallery::Params& p)
     : LLOutfitListBase(),
-      mTexturesObserver(NULL),
       mOutfitsObserver(NULL),
       mScrollPanel(NULL),
       mGalleryPanel(NULL),
@@ -122,7 +120,6 @@ void LLOutfitGallery::onOpen(const LLSD& info)
     LLOutfitListBase::onOpen(info);
     if (!mGalleryCreated)
     {
-        loadPhotos();
         uuid_vec_t cats;
         getCurrentCategories(cats);
         int n = cats.size();
@@ -146,6 +143,264 @@ void LLOutfitGallery::draw()
     }
 }
 
+BOOL LLOutfitGallery::handleKeyHere(KEY key, MASK mask)
+{
+    BOOL handled = FALSE;
+    switch (key)
+    {
+        case KEY_RETURN:
+            // Open selected items if enter key hit on the inventory panel
+            if (mask == MASK_NONE && mSelectedOutfitUUID.notNull())
+            {
+                // Or should it wearSelectedOutfit?
+                getSelectedItem()->openOutfitsContent();
+            }
+            handled = TRUE;
+            break;
+        case KEY_DELETE:
+#if LL_DARWIN
+        case KEY_BACKSPACE:
+#endif
+            // Delete selected items if delete or backspace key hit on the inventory panel
+            // Note: on Mac laptop keyboards, backspace and delete are one and the same
+            if (mSelectedOutfitUUID.notNull())
+            {
+                onRemoveOutfit(mSelectedOutfitUUID);
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_F2:
+            LLAppearanceMgr::instance().renameOutfit(mSelectedOutfitUUID);
+            handled = TRUE;
+            break;
+
+        case KEY_PAGE_UP:
+            if (mScrollPanel)
+            {
+                mScrollPanel->pageUp(30);
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_PAGE_DOWN:
+            if (mScrollPanel)
+            {
+                mScrollPanel->pageDown(30);
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_HOME:
+            if (mScrollPanel)
+            {
+                mScrollPanel->goToTop();
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_END:
+            if (mScrollPanel)
+            {
+                mScrollPanel->goToBottom();
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_LEFT:
+            moveLeft();
+            handled = TRUE;
+            break;
+
+        case KEY_RIGHT:
+            moveRight();
+            handled = TRUE;
+            break;
+
+        case KEY_UP:
+            moveUp();
+            handled = TRUE;
+            break;
+
+        case KEY_DOWN:
+            moveDown();
+            handled = TRUE;
+            break;
+
+        default:
+            break;
+    }
+
+    if (handled)
+    {
+        mOutfitGalleryMenu->hide();
+    }
+
+    return handled;
+}
+
+void LLOutfitGallery::moveUp()
+{
+    if (mSelectedOutfitUUID.notNull() && mItemsAddedCount > 1)
+    {
+        LLOutfitGalleryItem* item = getSelectedItem();
+        if (item)
+        {
+            S32 n = mItemIndexMap[item];
+            n -= mItemsInRow;
+            if (n >= 0)
+            {
+                item = mIndexToItemMap[n];
+                LLUUID item_id = item->getUUID();
+                ChangeOutfitSelection(nullptr, item_id);
+                item->setFocus(TRUE);
+
+                scrollToShowItem(mSelectedOutfitUUID);
+            }
+        }
+    }
+}
+
+void LLOutfitGallery::moveDown()
+{
+    if (mSelectedOutfitUUID.notNull() && mItemsAddedCount > 1)
+    {
+        LLOutfitGalleryItem* item = getSelectedItem();
+        if (item)
+        {
+            S32 n = mItemIndexMap[item];
+            n += mItemsInRow;
+            if (n < mItemsAddedCount)
+            {
+                item = mIndexToItemMap[n];
+                LLUUID item_id = item->getUUID();
+                ChangeOutfitSelection(nullptr, item_id);
+                item->setFocus(TRUE);
+
+                scrollToShowItem(mSelectedOutfitUUID);
+            }
+        }
+    }
+}
+
+void LLOutfitGallery::moveLeft()
+{
+    if (mSelectedOutfitUUID.notNull() && mItemsAddedCount > 1)
+    {
+        LLOutfitGalleryItem* item = getSelectedItem();
+        if (item)
+        {
+            // Might be better to get item from panel
+            S32 n = mItemIndexMap[item];
+            n--;
+            if (n < 0)
+            {
+                n = mItemsAddedCount - 1;
+            }
+            item = mIndexToItemMap[n];
+            LLUUID item_id = item->getUUID();
+            ChangeOutfitSelection(nullptr, item_id);
+            item->setFocus(TRUE);
+
+            scrollToShowItem(mSelectedOutfitUUID);
+        }
+    }
+}
+
+void LLOutfitGallery::moveRight()
+{
+    if (mSelectedOutfitUUID.notNull() && mItemsAddedCount > 1)
+    {
+        LLOutfitGalleryItem* item = getSelectedItem();
+        if (item)
+        {
+            S32 n = mItemIndexMap[item];
+            n++;
+            if (n == mItemsAddedCount)
+            {
+                n = 0;
+            }
+            item = mIndexToItemMap[n];
+            LLUUID item_id = item->getUUID();
+            ChangeOutfitSelection(nullptr, item_id);
+            item->setFocus(TRUE);
+
+            scrollToShowItem(mSelectedOutfitUUID);
+        }
+    }
+}
+
+void LLOutfitGallery::onFocusLost()
+{
+    LLOutfitListBase::onFocusLost();
+
+    if (mSelectedOutfitUUID.notNull())
+    {
+        LLOutfitGalleryItem* item = getSelectedItem();
+        if (item)
+        {
+            item->setSelected(false);
+        }
+    }
+}
+
+void LLOutfitGallery::onFocusReceived()
+{
+    LLOutfitListBase::onFocusReceived();
+
+    if (mSelectedOutfitUUID.notNull())
+    {
+        LLOutfitGalleryItem* item = getSelectedItem();
+        if (item)
+        {
+            item->setSelected(true);
+        }
+    }
+}
+
+void LLOutfitGallery::onRemoveOutfit(const LLUUID& outfit_cat_id)
+{
+    LLNotificationsUtil::add("DeleteOutfits", LLSD(), LLSD(), boost::bind(onOutfitsRemovalConfirmation, _1, _2, outfit_cat_id));
+}
+
+void LLOutfitGallery::onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response, const LLUUID& outfit_cat_id)
+{
+    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+    if (option != 0) return; // canceled
+
+    if (outfit_cat_id.notNull())
+    {
+        gInventory.removeCategory(outfit_cat_id);
+    }
+}
+
+void LLOutfitGallery::scrollToShowItem(const LLUUID& item_id)
+{
+    LLOutfitGalleryItem* item = mOutfitMap[item_id];
+    if (item)
+    {
+        const LLRect visible_content_rect = mScrollPanel->getVisibleContentRect();
+
+        LLRect item_rect;
+        item->localRectToOtherView(item->getLocalRect(), &item_rect, mScrollPanel);
+        LLRect overlap_rect(item_rect);
+        overlap_rect.intersectWith(visible_content_rect);
+
+        //Scroll when the selected item is outside the visible area
+        if (overlap_rect.getHeight() + 5 < item->getRect().getHeight())
+        {
+            LLRect content_rect = mScrollPanel->getContentWindowRect();
+            LLRect constraint_rect;
+            constraint_rect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight());
+
+            LLRect item_doc_rect;
+            item->localRectToOtherView(item->getLocalRect(), &item_doc_rect, mGalleryPanel);
+
+            mScrollPanel->scrollToShowRect(item_doc_rect, constraint_rect);
+        }
+    }
+}
+
 void LLOutfitGallery::updateRowsIfNeeded()
 {
     if(((getRect().getWidth() - mRowPanelWidth) > mItemWidth) && mRowCount > 1)
@@ -267,8 +522,9 @@ void LLOutfitGallery::addToGallery(LLOutfitGalleryItem* item)
         mHiddenItems.push_back(item);
         return;
     }
+    mItemIndexMap[item] = mItemsAddedCount;
+    mIndexToItemMap[mItemsAddedCount] = item;
     mItemsAddedCount++;
-    mItemIndexMap[item] = mItemsAddedCount - 1;
     int n = mItemsAddedCount;
     int row_count = (n % mItemsInRow) == 0 ? n / mItemsInRow : n / mItemsInRow + 1;
     int n_prev = n - 1;
@@ -304,6 +560,7 @@ void LLOutfitGallery::removeFromGalleryLast(LLOutfitGalleryItem* item)
     int row_count = (n % mItemsInRow) == 0 ? n / mItemsInRow : n / mItemsInRow + 1;
     int row_count_prev = (n_prev % mItemsInRow) == 0 ? n_prev / mItemsInRow : n_prev / mItemsInRow + 1;
     mItemsAddedCount--;
+    mIndexToItemMap.erase(mItemsAddedCount);
 
     bool remove_row = row_count != row_count_prev;
     removeFromLastRow(mItems[mItemsAddedCount]);
@@ -329,6 +586,7 @@ void LLOutfitGallery::removeFromGalleryMiddle(LLOutfitGalleryItem* item)
     }
     int n = mItemIndexMap[item];
     mItemIndexMap.erase(item);
+    mIndexToItemMap.erase(n);
     std::vector<LLOutfitGalleryItem*> saved;
     for (int i = mItemsAddedCount - 1; i > n; i--)
     {
@@ -362,9 +620,15 @@ LLOutfitGalleryItem* LLOutfitGallery::buildGalleryItem(std::string name, LLUUID
     gitem->setFollowsTop();
     gitem->setOutfitName(name);
     gitem->setUUID(outfit_id);
+    gitem->setGallery(this);
     return gitem;
 }
 
+LLOutfitGalleryItem* LLOutfitGallery::getSelectedItem()
+{
+    return mOutfitMap[mSelectedOutfitUUID];
+}
+
 void LLOutfitGallery::buildGalleryPanel(int row_count)
 {
     LLPanel::Params params;
@@ -438,12 +702,6 @@ void LLOutfitGallery::moveRowPanel(LLPanel* stack, int left, int bottom)
 LLOutfitGallery::~LLOutfitGallery()
 {
     delete mOutfitGalleryMenu;
-    
-    if (gInventory.containsObserver(mTexturesObserver))
-    {
-        gInventory.removeObserver(mTexturesObserver);
-    }
-    delete mTexturesObserver;
 
     if (gInventory.containsObserver(mOutfitsObserver))
     {
@@ -619,6 +877,7 @@ void LLOutfitGallery::onChangeOutfitSelection(LLWearableItemsList* list, const L
     {
         category_it->second->setSelected(TRUE);
     }
+    // mSelectedOutfitUUID will be set in LLOutfitListBase::ChangeOutfitSelection
 }
 
 void LLOutfitGallery::wearSelectedOutfit()
@@ -671,7 +930,8 @@ static LLDefaultChildRegistry::Register<LLOutfitGalleryItem> r("outfit_gallery_i
 
 LLOutfitGalleryItem::LLOutfitGalleryItem(const Params& p)
     : LLPanel(p),
-    mTexturep(NULL),
+    mGallery(nullptr),
+    mTexturep(nullptr),
     mSelected(false),
     mWorn(false),
     mDefaultImage(true),
@@ -749,10 +1009,13 @@ void LLOutfitGalleryItem::setOutfitWorn(bool value)
     mWorn = value;
     LLStringUtil::format_map_t worn_string_args;
     std::string worn_string = getString("worn_string", worn_string_args);
-    LLUIColor text_color = LLUIColorTable::instance().getColor(mSelected ? "White" : (mWorn ? "OutfitGalleryItemWorn" : "White"), LLColor4::white);
+    LLUIColor text_color = LLUIColorTable::instance().getColor("White", LLColor4::white);
     mOutfitWornText->setReadOnlyColor(text_color.get());
     mOutfitNameText->setReadOnlyColor(text_color.get());
+    mOutfitWornText->setFont(value ? LLFontGL::getFontSansSerifBold() : LLFontGL::getFontSansSerifSmall());
+    mOutfitNameText->setFont(value ? LLFontGL::getFontSansSerifBold() : LLFontGL::getFontSansSerifSmall());
     mOutfitWornText->setValue(value ? worn_string : "");
+    mOutfitNameText->setText(mOutfitName); // refresh LLTextViewModel to pick up font changes
 }
 
 void LLOutfitGalleryItem::setSelected(bool value)
@@ -775,9 +1038,64 @@ BOOL LLOutfitGalleryItem::handleRightMouseDown(S32 x, S32 y, MASK mask)
 }
 
 BOOL LLOutfitGalleryItem::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+    return openOutfitsContent() || LLPanel::handleDoubleClick(x, y, mask);
+}
+
+BOOL LLOutfitGalleryItem::handleKeyHere(KEY key, MASK mask)
+{
+    if (!mGallery)
+    {
+        return FALSE;
+    }
+
+    BOOL handled = FALSE;
+    switch (key)
+    {
+        case KEY_LEFT:
+            mGallery->moveLeft();
+            handled = true;
+            break;
+
+        case KEY_RIGHT:
+            mGallery->moveRight();
+            handled = true;
+            break;
+
+        case KEY_UP:
+            mGallery->moveUp();
+            handled = true;
+            break;
+
+        case KEY_DOWN:
+            mGallery->moveDown();
+            handled = true;
+            break;
+
+        default:
+            break;
+    }
+    return handled;
+}
+
+void LLOutfitGalleryItem::onFocusLost()
+{
+    setSelected(false);
+
+    LLPanel::onFocusLost();
+}
+
+void LLOutfitGalleryItem::onFocusReceived()
+{
+    setSelected(true);
+
+    LLPanel::onFocusReceived();
+}
+
+bool LLOutfitGalleryItem::openOutfitsContent()
 {
     LLTabContainer* appearence_tabs = LLPanelOutfitsInventory::findInstance()->getChild<LLTabContainer>("appearance_tabs");
-    if (appearence_tabs && (mUUID != LLUUID()))
+    if (appearence_tabs && mUUID.notNull())
     {
         appearence_tabs->selectTabByName("outfitslist_tab");
         LLPanel* panel = appearence_tabs->getCurrentPanel();
@@ -790,12 +1108,11 @@ BOOL LLOutfitGalleryItem::handleDoubleClick(S32 x, S32 y, MASK mask)
                 outfit_list->setSelectedOutfitByUUID(mUUID);
                 LLAccordionCtrlTab* tab = accordion->getSelectedTab();
                 tab->showAndFocusHeader();
-                return TRUE;
+                return true;
             }
         }
     }
-
-    return LLPanel::handleDoubleClick(x, y, mask);
+    return false;
 }
 
 bool LLOutfitGalleryItem::setImageAssetId(LLUUID image_asset_id)
@@ -841,68 +1158,22 @@ LLContextMenu* LLOutfitGalleryContextMenu::createMenu()
                   boost::bind(&LLAppearanceMgr::takeOffOutfit, &LLAppearanceMgr::instance(), selected_id));
     registrar.add("Outfit.Edit", boost::bind(editOutfit));
     registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id));
-    registrar.add("Outfit.Delete", boost::bind(&LLOutfitGalleryContextMenu::onRemoveOutfit, this, selected_id));
+    registrar.add("Outfit.Delete", boost::bind(LLOutfitGallery::onRemoveOutfit, selected_id));
     registrar.add("Outfit.Create", boost::bind(&LLOutfitGalleryContextMenu::onCreate, this, _2));
-    registrar.add("Outfit.UploadPhoto", boost::bind(&LLOutfitGalleryContextMenu::onUploadPhoto, this, selected_id));
-    registrar.add("Outfit.SelectPhoto", boost::bind(&LLOutfitGalleryContextMenu::onSelectPhoto, this, selected_id));
-    registrar.add("Outfit.TakeSnapshot", boost::bind(&LLOutfitGalleryContextMenu::onTakeSnapshot, this, selected_id));
-    registrar.add("Outfit.RemovePhoto", boost::bind(&LLOutfitGalleryContextMenu::onRemovePhoto, this, selected_id));
+    registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitGalleryContextMenu::onThumbnail, this, selected_id));
     enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitGalleryContextMenu::onEnable, this, _2));
     enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitGalleryContextMenu::onVisible, this, _2));
     
     return createFromFile("menu_gallery_outfit_tab.xml");
 }
 
-void LLOutfitGalleryContextMenu::onUploadPhoto(const LLUUID& outfit_cat_id)
-{
-    LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
-    if (gallery && outfit_cat_id.notNull())
-    {
-        gallery->uploadPhoto(outfit_cat_id);
-    }
-}
-
-void LLOutfitGalleryContextMenu::onSelectPhoto(const LLUUID& outfit_cat_id)
-{
-    LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
-    if (gallery && outfit_cat_id.notNull())
-    {
-        gallery->onSelectPhoto(outfit_cat_id);
-    }
-}
-
-void LLOutfitGalleryContextMenu::onRemovePhoto(const LLUUID& outfit_cat_id)
+void LLOutfitGalleryContextMenu::onThumbnail(const LLUUID& outfit_cat_id)
 {
     LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
     if (gallery && outfit_cat_id.notNull())
     {
-        gallery->checkRemovePhoto(outfit_cat_id);
-        gallery->refreshOutfit(outfit_cat_id);
-    }
-}
-
-void LLOutfitGalleryContextMenu::onTakeSnapshot(const LLUUID& outfit_cat_id)
-{
-    LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
-    if (gallery && outfit_cat_id.notNull())
-    {
-        gallery->onTakeSnapshot(outfit_cat_id);
-    }
-}
-
-void LLOutfitGalleryContextMenu::onRemoveOutfit(const LLUUID& outfit_cat_id)
-{
-    LLNotificationsUtil::add("DeleteOutfits", LLSD(), LLSD(), boost::bind(&LLOutfitGalleryContextMenu::onOutfitsRemovalConfirmation, this, _1, _2, outfit_cat_id));
-}
-
-void LLOutfitGalleryContextMenu::onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response, const LLUUID& outfit_cat_id)
-{
-    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-    if (option != 0) return; // canceled
-    
-    if (outfit_cat_id.notNull())
-    {
-        gInventory.removeCategory(outfit_cat_id);
+        LLSD data(outfit_cat_id);
+        LLFloaterReg::showInstance("change_item_thumbnail", data);
     }
 }
 
@@ -925,16 +1196,6 @@ bool LLOutfitGalleryContextMenu::onEnable(LLSD::String param)
 
 bool LLOutfitGalleryContextMenu::onVisible(LLSD::String param)
 {
-	mMenuHandle.get()->getChild<LLUICtrl>("upload_photo")->setLabelArg("[UPLOAD_COST]", fmt::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()));
-    if ("remove_photo" == param)
-    {
-        LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
-        LLUUID selected_id = mUUIDs.front();
-        if (gallery && selected_id.notNull())
-        {
-            return !gallery->hasDefaultImage(selected_id);
-        }
-    }
     return LLOutfitContextMenu::onVisible(param);
 }
 
@@ -949,56 +1210,12 @@ void LLOutfitGalleryGearMenu::onUpdateItemsVisibility()
     bool have_selection = getSelectedOutfitID().notNull();
     mMenu->setItemVisible("expand", FALSE);
     mMenu->setItemVisible("collapse", FALSE);
-    mMenu->setItemVisible("upload_photo", have_selection);
-    mMenu->setItemVisible("select_photo", have_selection);
-    mMenu->setItemVisible("take_snapshot", have_selection);
-    mMenu->setItemVisible("remove_photo", !hasDefaultImage());
+    mMenu->setItemVisible("thumbnail", have_selection);
     mMenu->setItemVisible("sepatator3", TRUE);
     mMenu->setItemVisible("sort_folders_by_name", TRUE);
     LLOutfitListGearMenuBase::onUpdateItemsVisibility();
 }
 
-void LLOutfitGalleryGearMenu::onUploadFoto()
-{
-    LLUUID selected_outfit_id = getSelectedOutfitID();
-    LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
-    if (gallery && selected_outfit_id.notNull())
-    {
-        gallery->uploadPhoto(selected_outfit_id);
-    }
-}
-
-void LLOutfitGalleryGearMenu::onSelectPhoto()
-{
-    LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
-    LLUUID selected_outfit_id = getSelectedOutfitID();
-    if (gallery && !selected_outfit_id.isNull())
-    {
-        gallery->onSelectPhoto(selected_outfit_id);
-    }
-}
-
-void LLOutfitGalleryGearMenu::onRemovePhoto()
-{
-    LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
-    LLUUID selected_outfit_id = getSelectedOutfitID();
-    if (gallery && !selected_outfit_id.isNull())
-    {
-        gallery->checkRemovePhoto(selected_outfit_id);
-        gallery->refreshOutfit(selected_outfit_id);
-    }
-}
-
-void LLOutfitGalleryGearMenu::onTakeSnapshot()
-{
-    LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
-    LLUUID selected_outfit_id = getSelectedOutfitID();
-    if (gallery && !selected_outfit_id.isNull())
-    {
-        gallery->onTakeSnapshot(selected_outfit_id);
-    }
-}
-
 void LLOutfitGalleryGearMenu::onChangeSortOrder()
 {
     bool sort_by_name = !gSavedSettings.getBOOL("OutfitGallerySortByName");
@@ -1025,251 +1242,91 @@ void LLOutfitGallery::onTextureSelectionChanged(LLInventoryItem* itemp)
 {
 }
 
-void LLOutfitGallery::loadPhotos()
-{
-    //Iterate over inventory
-    mSnapshotFolderID = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE);
-    LLViewerInventoryCategory* textures_category = gInventory.getCategory(mSnapshotFolderID);
-    if (!textures_category)
-        return;
-    if (mTexturesObserver == NULL)
-    {
-        mTexturesObserver = new LLInventoryCategoriesObserver();
-        gInventory.addObserver(mTexturesObserver);
-    }
-
-    // Start observing changes in "Textures" category.
-    mTexturesObserver->addCategory(mSnapshotFolderID,
-        boost::bind(&LLOutfitGallery::refreshTextures, this, mSnapshotFolderID));
-
-    textures_category->fetch();
-}
-
-void LLOutfitGallery::updateSnapshotFolderObserver()
-{
-    if(mSnapshotFolderID != gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE))
-    {
-        if (gInventory.containsObserver(mTexturesObserver))
-        {
-            gInventory.removeObserver(mTexturesObserver);
-        }
-        delete mTexturesObserver;
-        mTexturesObserver = NULL;
-        loadPhotos();
-    }
-}
-
 void LLOutfitGallery::refreshOutfit(const LLUUID& category_id)
 {
     LLViewerInventoryCategory* category = gInventory.getCategory(category_id);
     if (category)
     {
         bool photo_loaded = false;
-        LLInventoryModel::cat_array_t sub_cat_array;
-        LLInventoryModel::item_array_t outfit_item_array;
-        // Collect all sub-categories of a given category.
-        gInventory.collectDescendents(
-            category->getUUID(),
-            sub_cat_array,
-            outfit_item_array,
-            LLInventoryModel::EXCLUDE_TRASH);
-
-        LLOutfitGalleryItem* gallery_item = mOutfitMap[category_id];
-
-        for (LLViewerInventoryItem* outfit_item : outfit_item_array)
+        LLUUID asset_id = category->getThumbnailUUID();
+        if (asset_id.isNull())
         {
-            LLViewerInventoryItem* linked_item = outfit_item->getLinkedItem();
-            LLUUID asset_id, inv_id;
-            std::string item_name;
-            if (linked_item != NULL)
+            LLInventoryModel::cat_array_t sub_cat_array;
+            LLInventoryModel::item_array_t outfit_item_array;
+            // Collect all sub-categories of a given category.
+            gInventory.collectDescendents(
+                category->getUUID(),
+                sub_cat_array,
+                outfit_item_array,
+                LLInventoryModel::EXCLUDE_TRASH);
+            for(LLViewerInventoryItem* outfit_item : outfit_item_array)
             {
-                if (linked_item->getActualType() == LLAssetType::AT_TEXTURE)
+                LLViewerInventoryItem* linked_item = outfit_item->getLinkedItem();
+                LLUUID asset_id, inv_id;
+                std::string item_name;
+                if (linked_item != NULL)
                 {
-                    asset_id = linked_item->getAssetUUID();
-                    inv_id = linked_item->getUUID();
-                    item_name = linked_item->getName();
+                    if (linked_item->getActualType() == LLAssetType::AT_TEXTURE)
+                    {
+                        asset_id = linked_item->getAssetUUID();
+                        inv_id = linked_item->getUUID();
+                        item_name = linked_item->getName();
+                    }
                 }
-            }
-            else if (outfit_item->getActualType() == LLAssetType::AT_TEXTURE)
-            {
-                asset_id = outfit_item->getAssetUUID();
-                inv_id = outfit_item->getUUID();
-                item_name = outfit_item->getName();
-            }
-            if (asset_id.notNull())
-            {
-                photo_loaded |= gallery_item->setImageAssetId(asset_id);
-                // Rename links
-                if (!mOutfitRenamePending.isNull() && mOutfitRenamePending.asString() == item_name)
+                else if (outfit_item->getActualType() == LLAssetType::AT_TEXTURE)
                 {
-                    LLViewerInventoryCategory *outfit_cat = gInventory.getCategory(mOutfitRenamePending);
-                    LLStringUtil::format_map_t photo_string_args;
-                    photo_string_args["OUTFIT_NAME"] = outfit_cat->getName();
-                    std::string new_name = getString("outfit_photo_string", photo_string_args);
-                    LLSD updates;
-                    updates["name"] = new_name;
-                    update_inventory_item(inv_id, updates, NULL);
-                    mOutfitRenamePending.setNull();
-                    LLFloater* appearance_floater = LLFloaterReg::getInstance("appearance");
-                    if (appearance_floater)
+                    asset_id = outfit_item->getAssetUUID();
+                    inv_id = outfit_item->getUUID();
+                    item_name = outfit_item->getName();
+                }
+                if (category->getThumbnailUUID().notNull())
+                {
+                    asset_id = category->getThumbnailUUID();
+                }
+                if (asset_id.notNull())
+                {
+                    photo_loaded |= mOutfitMap[category_id]->setImageAssetId(asset_id);
+                    // Rename links
+                    if (!mOutfitRenamePending.isNull() && mOutfitRenamePending.asString() == item_name)
+                    {
+                        LLViewerInventoryCategory *outfit_cat = gInventory.getCategory(mOutfitRenamePending);
+                        LLStringUtil::format_map_t photo_string_args;
+                        photo_string_args["OUTFIT_NAME"] = outfit_cat->getName();
+                        std::string new_name = getString("outfit_photo_string", photo_string_args);
+                        LLSD updates;
+                        updates["name"] = new_name;
+                        update_inventory_item(inv_id, updates, NULL);
+                        mOutfitRenamePending.setNull();
+                        LLFloater* appearance_floater = LLFloaterReg::getInstance("appearance");
+                        if (appearance_floater)
+                        {
+                            appearance_floater->setFocus(TRUE);
+                        }
+                    }
+                    if (item_name == LLAppearanceMgr::sExpectedTextureName)
                     {
-                        appearance_floater->setFocus(TRUE);
+                        // Images with "appropriate" name take priority
+                        break;
                     }
                 }
-                if (item_name == LLAppearanceMgr::sExpectedTextureName)
+                if (!photo_loaded)
                 {
-                    // Images with "appropriate" name take priority
-                    break;
+                    mOutfitMap[category_id]->setDefaultImage();
                 }
             }
-            if (!photo_loaded)
-            {
-                gallery_item->setDefaultImage();
-            }
-        }
-    }
-    
-    if (mGalleryCreated && !LLApp::isExiting())
-    {
-        reArrangeRows();
-    }
-}
-
-// Refresh linked textures from "textures" uploads folder
-void LLOutfitGallery::refreshTextures(const LLUUID& category_id)
-{
-    LLInventoryModel::cat_array_t cat_array;
-    LLInventoryModel::item_array_t item_array;
-
-    // Collect all sub-categories of a given category.
-    LLIsType is_texture(LLAssetType::AT_TEXTURE);
-    gInventory.collectDescendentsIf(
-        category_id,
-        cat_array,
-        item_array,
-        LLInventoryModel::EXCLUDE_TRASH,
-        is_texture);
-
-    //Find texture which contain pending outfit ID string in name
-    LLViewerInventoryItem* photo_upload_item = NULL;
-    for (LLViewerInventoryItem* item : item_array)
-    {
-        std::string name = item->getName();
-        if (!mOutfitLinkPending.isNull() && name == mOutfitLinkPending.asString())
-        {
-            photo_upload_item = item;
-            break;
-        }
-    }
-
-    if (photo_upload_item != NULL)
-    {
-        LLUUID photo_item_id = photo_upload_item->getUUID();
-        LLInventoryObject* upload_object = gInventory.getObject(photo_item_id);
-        if (!upload_object)
-        {
-            LL_WARNS() << "LLOutfitGallery::refreshTextures added_object is null!" << LL_ENDL;
         }
         else
         {
-            linkPhotoToOutfit(photo_item_id, mOutfitLinkPending);
-            mOutfitRenamePending = mOutfitLinkPending;
-            mOutfitLinkPending.setNull();
+            mOutfitMap[category_id]->setImageAssetId(asset_id);
         }
     }
-}
-
-void LLOutfitGallery::uploadPhoto(LLUUID outfit_id)
-{
-	outfit_map_t::iterator outfit_it = mOutfitMap.find(outfit_id);
-	if (outfit_it == mOutfitMap.end() || outfit_it->first.isNull())
-	{
-		return;
-	}
-    LLFilePickerReplyThread::startPicker(boost::bind(&LLOutfitGallery::uploadOutfitImage, this, _1, outfit_id), LLFilePicker::FFLOAD_IMAGE, false);
-}
-
-void LLOutfitGallery::uploadOutfitImage(const std::vector<std::string>& filenames, LLUUID outfit_id)
-{
-    std::string filename = filenames[0];
-
-	const std::string exten = gDirUtilp->getExtension(filename);
-	const U32 codec = LLImageBase::getCodecFromExtension(exten);
-
-	if (codec != IMG_CODEC_INVALID)
-	{
-		LLImageDimensionsInfo image_info;
-		std::string image_load_error;
-		if (!image_info.load(filename, codec))
-		{
-			image_load_error = image_info.getLastError();
-		}
-
-		S32 max_width = MAX_OUTFIT_PHOTO_WIDTH;
-		S32 max_height = MAX_OUTFIT_PHOTO_HEIGHT;
-
-		if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height))
-		{
-			LLStringUtil::format_map_t args;
-			args["WIDTH"] = llformat("%d", max_width);
-			args["HEIGHT"] = llformat("%d", max_height);
-
-			image_load_error = LLTrans::getString("outfit_photo_load_dimensions_error", args);
-		}
-
-		if (!image_load_error.empty())
-		{
-			LLSD subst;
-			subst["REASON"] = image_load_error;
-			LLNotificationsUtil::add("OutfitPhotoLoadError", subst);
-			return;
-		}
-
-        S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost();
-		void* nruserdata = NULL;
-		nruserdata = (void*)&outfit_id;
-
-		LLViewerInventoryCategory* outfit_cat = gInventory.getCategory(outfit_id);
-		if (!outfit_cat) return;
-		updateSnapshotFolderObserver();
-		checkRemovePhoto(outfit_id);
-		std::string upload_pending_name = outfit_id.asString();
-		std::string upload_pending_desc = "";
-        upload_new_resource(filename, // file
-			upload_pending_name,
-			upload_pending_desc,
-			0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
-			LLFloaterPerms::getNextOwnerPerms("Uploads"),
-			LLFloaterPerms::getGroupPerms("Uploads"),
-			LLFloaterPerms::getEveryonePerms("Uploads"),
-			upload_pending_name, LLAssetStorage::LLStoreAssetCallback(), expected_upload_cost, nruserdata, false);
-		mOutfitLinkPending = outfit_id;
-	}
-    else
+    
+    if (mGalleryCreated && !LLApp::isExiting())
     {
-        LLSD subst;
-        subst["REASON"] = LLTrans::getString("outfit_photo_load_codec_error");;
-        LLNotificationsUtil::add("OutfitPhotoLoadError", subst);
-        return;
+        reArrangeRows();
     }
 }
 
-void LLOutfitGallery::linkPhotoToOutfit(LLUUID photo_id, LLUUID outfit_id)
-{
-    LLPointer<LLInventoryCallback> cb = new LLUpdateGalleryOnPhotoLinked();
-    link_inventory_object(outfit_id, photo_id, cb);
-}
-
-bool LLOutfitGallery::checkRemovePhoto(LLUUID outfit_id)
-{
-    LLAppearanceMgr::instance().removeOutfitPhoto(outfit_id);
-    return true;
-}
-
-void LLUpdateGalleryOnPhotoLinked::fire(const LLUUID& inv_item_id)
-{
-}
-
 LLUUID LLOutfitGallery::getPhotoAssetId(const LLUUID& outfit_id)
 {
     outfit_map_t::iterator outfit_it = mOutfitMap.find(outfit_id);
@@ -1285,151 +1342,3 @@ LLUUID LLOutfitGallery::getDefaultPhoto()
     return LLUUID();
 }
 
-void LLOutfitGallery::onTexturePickerCommit(LLTextureCtrl::ETexturePickOp op, LLUUID id)
-{
-    LLUUID selected_outfit_id = getSelectedOutfitUUID();
-
-    if (selected_outfit_id.isNull())
-    {
-        return;
-    }
-
-    LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
-
-    if (floaterp && op == LLTextureCtrl::TEXTURE_SELECT)
-    {
-        LLUUID image_item_id;
-        if (id.notNull())
-        {
-            image_item_id = id;
-        }
-        else
-        {
-            image_item_id = floaterp->findItemID(floaterp->getAssetID(), FALSE, TRUE);
-            if (image_item_id.isNull())
-            {
-                LL_WARNS() << "id or image_item_id is NULL!" << LL_ENDL;
-                return;
-            }
-        }
-
-        std::string image_load_error;
-        S32 max_width = MAX_OUTFIT_PHOTO_WIDTH;
-        S32 max_height = MAX_OUTFIT_PHOTO_HEIGHT;
-        if (mTextureSelected.isNull() ||
-            mTextureSelected->getFullWidth() == 0 ||
-            mTextureSelected->getFullHeight() == 0)
-        {
-            image_load_error = LLTrans::getString("outfit_photo_verify_dimensions_error");
-            LL_WARNS() << "Cannot verify selected texture dimensions" << LL_ENDL;
-            return;
-        }
-        S32 width = mTextureSelected->getFullWidth();
-        S32 height = mTextureSelected->getFullHeight();
-        if ((width > max_width) || (height > max_height))
-        {
-            LLStringUtil::format_map_t args;
-            args["WIDTH"] = llformat("%d", max_width);
-            args["HEIGHT"] = llformat("%d", max_height);
-
-            image_load_error = LLTrans::getString("outfit_photo_select_dimensions_error", args);
-        }
-
-        if (!image_load_error.empty())
-        {
-            LLSD subst;
-            subst["REASON"] = image_load_error;
-            LLNotificationsUtil::add("OutfitPhotoLoadError", subst);
-            return;
-        }
-
-        checkRemovePhoto(selected_outfit_id);
-        linkPhotoToOutfit(image_item_id, selected_outfit_id);
-    }
-}
-
-void LLOutfitGallery::onSelectPhoto(LLUUID selected_outfit_id)
-{
-    if (selected_outfit_id.notNull())
-    {
-
-        // show hourglass cursor when loading inventory window
-        // because inventory construction is slooow
-        getWindow()->setCursor(UI_CURSOR_WAIT);
-        LLFloater* floaterp = mFloaterHandle.get();
-
-        // Show the dialog
-        if (floaterp)
-        {
-            floaterp->openFloater();
-        }
-        else
-        {
-            floaterp = new LLFloaterTexturePicker(
-                this,
-                getPhotoAssetId(selected_outfit_id),
-                getPhotoAssetId(selected_outfit_id),
-                getPhotoAssetId(selected_outfit_id),
-                getPhotoAssetId(selected_outfit_id),
-                FALSE,
-                TRUE,
-                "SELECT PHOTO",
-                PERM_NONE,
-                PERM_NONE,
-                FALSE,
-                NULL);
-
-            mFloaterHandle = floaterp->getHandle();
-            mTextureSelected = NULL;
-
-            LLFloaterTexturePicker* texture_floaterp = dynamic_cast<LLFloaterTexturePicker*>(floaterp);
-            if (texture_floaterp)
-            {
-                texture_floaterp->setTextureSelectedCallback(boost::bind(&LLOutfitGallery::onTextureSelectionChanged, this, _1));
-                texture_floaterp->setOnFloaterCommitCallback(boost::bind(&LLOutfitGallery::onTexturePickerCommit, this, _1, _2));
-                texture_floaterp->setOnUpdateImageStatsCallback(boost::bind(&LLOutfitGallery::onTexturePickerUpdateImageStats, this, _1));
-                texture_floaterp->setLocalTextureEnabled(FALSE);
-                texture_floaterp->setBakeTextureEnabled(FALSE);
-                texture_floaterp->setCanApply(false, true);
-            }
-
-            floaterp->openFloater();
-        }
-        floaterp->setFocus(TRUE);
-    }
-}
-
-void LLOutfitGallery::onTakeSnapshot(LLUUID selected_outfit_id)
-{
-    LLFloaterReg::toggleInstanceOrBringToFront("simple_outfit_snapshot");
-    LLFloaterSimpleOutfitSnapshot* snapshot_floater = LLFloaterSimpleOutfitSnapshot::getInstance();
-    if (snapshot_floater)
-    {
-        snapshot_floater->setOutfitID(selected_outfit_id);
-        snapshot_floater->getInstance()->setGallery(this);
-    }
-}
-
-void LLOutfitGallery::onBeforeOutfitSnapshotSave()
-{
-    LLUUID selected_outfit_id = getSelectedOutfitUUID();
-    if (!selected_outfit_id.isNull())
-    {
-        checkRemovePhoto(selected_outfit_id);
-        updateSnapshotFolderObserver();
-    }
-}
-
-void LLOutfitGallery::onAfterOutfitSnapshotSave()
-{
-    LLUUID selected_outfit_id = getSelectedOutfitUUID();
-    if (!selected_outfit_id.isNull())
-    {
-        mOutfitLinkPending = selected_outfit_id;
-    }
-}
-
-void LLOutfitGallery::onTexturePickerUpdateImageStats(LLPointer<LLViewerTexture> texture)
-{
-    mTextureSelected = texture;
-}
diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h
index 5e479dcc1d8fc4b5adfbe4a6fa12a624650eadf0..f0ee2fdcb41067e911d32529a4454f45948fa9ed 100644
--- a/indra/newview/lloutfitgallery.h
+++ b/indra/newview/lloutfitgallery.h
@@ -33,7 +33,6 @@
 #include "lllayoutstack.h"
 #include "lloutfitslist.h"
 #include "llpanelappearancetab.h"
-#include "lltexturectrl.h"
 #include "llviewertexture.h"
 
 #include <vector>
@@ -44,15 +43,6 @@ class LLOutfitListGearMenuBase;
 class LLOutfitGalleryGearMenu;
 class LLOutfitGalleryContextMenu;
 
-class LLUpdateGalleryOnPhotoLinked : public LLInventoryCallback
-{
-public:
-    LLUpdateGalleryOnPhotoLinked(){}
-    virtual ~LLUpdateGalleryOnPhotoLinked(){}
-    /* virtual */ void fire(const LLUUID& inv_item_id);
-private:
-};
-
 class LLOutfitGallery : public LLOutfitListBase
 {
 public:
@@ -83,10 +73,19 @@ class LLOutfitGallery : public LLOutfitListBase
 
     /*virtual*/ BOOL postBuild();
     /*virtual*/ void onOpen(const LLSD& info);
-    /*virtual*/ void draw();	
-    
-    void onSelectPhoto(LLUUID selected_outfit_id);
-    void onTakeSnapshot(LLUUID selected_outfit_id);
+    /*virtual*/ void draw();
+    /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
+    void moveUp();
+    void moveDown();
+    void moveLeft();
+    void moveRight();
+
+    /*virtual*/ void onFocusLost();
+    /*virtual*/ void onFocusReceived();
+
+    static void onRemoveOutfit(const LLUUID& outfit_cat_id);
+    static void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response, const LLUUID& outfit_cat_id);
+    void scrollToShowItem(const LLUUID& item_id);
 
     void wearSelectedOutfit();
 
@@ -106,14 +105,8 @@ class LLOutfitGallery : public LLOutfitListBase
     void updateMessageVisibility();
     bool hasDefaultImage(const LLUUID& outfit_cat_id);
 
-    void refreshTextures(const LLUUID& category_id);
     void refreshOutfit(const LLUUID& category_id);
 
-    void onTexturePickerCommit(LLTextureCtrl::ETexturePickOp op, LLUUID id);
-    void onTexturePickerUpdateImageStats(LLPointer<LLViewerTexture> texture);
-    void onBeforeOutfitSnapshotSave();
-    void onAfterOutfitSnapshotSave();
-
 protected:
     /*virtual*/ void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id);
     /*virtual*/ void onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid);
@@ -127,14 +120,8 @@ class LLOutfitGallery : public LLOutfitListBase
     void applyFilter(LLOutfitGalleryItem* item, const std::string& filter_substring);
 
 private:
-    void loadPhotos();
-    void uploadPhoto(LLUUID outfit_id);
-    void uploadOutfitImage(const std::vector<std::string>& filenames, LLUUID outfit_id);
-    void updateSnapshotFolderObserver();
     LLUUID getPhotoAssetId(const LLUUID& outfit_id);
     LLUUID getDefaultPhoto();
-    void linkPhotoToOutfit(LLUUID outfit_id, LLUUID photo_id);
-    bool checkRemovePhoto(LLUUID outfit_id);
     void addToGallery(LLOutfitGalleryItem* item);
     void removeFromGalleryLast(LLOutfitGalleryItem* item);
     void removeFromGalleryMiddle(LLOutfitGalleryItem* item);
@@ -150,6 +137,7 @@ class LLOutfitGallery : public LLOutfitListBase
     void updateGalleryWidth();
 
     LLOutfitGalleryItem* buildGalleryItem(std::string name, LLUUID outfit_id);
+    LLOutfitGalleryItem* getSelectedItem();
 
     void onTextureSelectionChanged(LLInventoryItem* itemp);
 
@@ -190,17 +178,15 @@ class LLOutfitGallery : public LLOutfitListBase
     
     LLListContextMenu* mOutfitGalleryMenu;
 
-    LLHandle<LLFloater> mFloaterHandle;
-
-    typedef boost::unordered_flat_map<LLUUID, LLOutfitGalleryItem*>      outfit_map_t;
+    typedef std::map<LLUUID, LLOutfitGalleryItem*>      outfit_map_t;
     typedef outfit_map_t::value_type                    outfit_map_value_t;
     outfit_map_t                                        mOutfitMap;
-    typedef std::map<LLOutfitGalleryItem*, int>         item_num_map_t;
+    typedef std::map<LLOutfitGalleryItem*, S32>         item_num_map_t;
     typedef item_num_map_t::value_type                  item_numb_map_value_t;
     item_num_map_t                                      mItemIndexMap;
+    std::map<S32, LLOutfitGalleryItem*>                 mIndexToItemMap;
 
 
-    LLInventoryCategoriesObserver* 	mTexturesObserver;
     LLInventoryCategoriesObserver* 	mOutfitsObserver;
 };
 class LLOutfitGalleryContextMenu : public LLOutfitContextMenu
@@ -211,17 +197,13 @@ class LLOutfitGalleryContextMenu : public LLOutfitContextMenu
     LLOutfitGalleryContextMenu(LLOutfitListBase* outfit_list)
     : LLOutfitContextMenu(outfit_list),
     mOutfitList(outfit_list){}
+
 protected:
     /* virtual */ LLContextMenu* createMenu();
     bool onEnable(LLSD::String param);
     bool onVisible(LLSD::String param);
-    void onUploadPhoto(const LLUUID& outfit_cat_id);
-    void onSelectPhoto(const LLUUID& outfit_cat_id);
-    void onRemovePhoto(const LLUUID& outfit_cat_id);
-    void onTakeSnapshot(const LLUUID& outfit_cat_id);
+    void onThumbnail(const LLUUID& outfit_cat_id);
     void onCreate(const LLSD& data);
-    void onRemoveOutfit(const LLUUID& outfit_cat_id);
-    void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response, const LLUUID& outfit_cat_id);
 private:
     LLOutfitListBase*	mOutfitList;
 };
@@ -236,10 +218,6 @@ class LLOutfitGalleryGearMenu : public LLOutfitListGearMenuBase
 protected:
     /*virtual*/ void onUpdateItemsVisibility();
 private:
-    /*virtual*/ void onUploadFoto();
-    /*virtual*/ void onSelectPhoto();
-    /*virtual*/ void onTakeSnapshot();
-    /*virtual*/ void onRemovePhoto();
     /*virtual*/ void onChangeSortOrder();
 
     bool hasDefaultImage();
@@ -259,14 +237,21 @@ class LLOutfitGalleryItem : public LLPanel
     /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
     /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
     /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
+    /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
+    /*virtual*/ void onFocusLost();
+    /*virtual*/ void onFocusReceived();
+
+    bool openOutfitsContent();
 
+    void setGallery(LLOutfitGallery* gallery) { mGallery = gallery; }
     void setDefaultImage();
     bool setImageAssetId(LLUUID asset_id);
     LLUUID getImageAssetId();
     void setOutfitName(std::string name);
     void setOutfitWorn(bool value);
     void setSelected(bool value);
-    void setUUID(LLUUID outfit_id) {mUUID = outfit_id;}
+    void setUUID(const LLUUID &outfit_id) {mUUID = outfit_id;}
+    LLUUID getUUID() const { return mUUID; }
     
     std::string getItemName() {return mOutfitName;}
     bool isDefaultImage() {return mDefaultImage;}
@@ -275,6 +260,7 @@ class LLOutfitGalleryItem : public LLPanel
     void setHidden(bool hidden) {mHidden = hidden;}
     
 private:
+    LLOutfitGallery* mGallery;
     LLPointer<LLViewerFetchedTexture> mTexturep;
     LLUUID mUUID;
     LLUUID mImageAssetId;
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 132495c9392dd1bf8baca446cdc2c187066b47aa..e995a45542c85dec8ea7d69c4a8246699beca1a6 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -35,7 +35,7 @@
 #include "llaccordionctrltab.h"
 #include "llagentwearables.h"
 #include "llappearancemgr.h"
-#include "llagentbenefits.h"
+#include "llfloaterreg.h"
 #include "llfloatersidepanelcontainer.h"
 #include "llinventoryfunctions.h"
 #include "llinventorymodel.h"
@@ -123,9 +123,8 @@ void LLOutfitsList::onOpen(const LLSD& info)
 {
     if (!mIsInitialized)
     {
-        const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
         // Start observing changes in Current Outfit category.
-        mCategoriesObserver->addCategory(cof, boost::bind(&LLOutfitsList::onCOFChanged, this));
+        LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLOutfitsList::onCOFChanged, this));
     }
 
     LLOutfitListBase::onOpen(info);
@@ -1113,10 +1112,7 @@ LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist)
 
     registrar.add("Gear.WearAdd", boost::bind(&LLOutfitListGearMenuBase::onAdd, this));
 
-    registrar.add("Gear.UploadPhoto", boost::bind(&LLOutfitListGearMenuBase::onUploadFoto, this));
-    registrar.add("Gear.SelectPhoto", boost::bind(&LLOutfitListGearMenuBase::onSelectPhoto, this));
-    registrar.add("Gear.TakeSnapshot", boost::bind(&LLOutfitListGearMenuBase::onTakeSnapshot, this));
-    registrar.add("Gear.RemovePhoto", boost::bind(&LLOutfitListGearMenuBase::onRemovePhoto, this));
+    registrar.add("Gear.Thumbnail", boost::bind(&LLOutfitListGearMenuBase::onThumbnail, this));
     registrar.add("Gear.SortByName", boost::bind(&LLOutfitListGearMenuBase::onChangeSortOrder, this));
 
     enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenuBase::onEnable, this, _2));
@@ -1233,7 +1229,6 @@ bool LLOutfitListGearMenuBase::onEnable(LLSD::String param)
 
 bool LLOutfitListGearMenuBase::onVisible(LLSD::String param)
 {
-	getMenu()->getChild<LLUICtrl>("upload_photo")->setLabelArg("[UPLOAD_COST]", fmt::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()));
     const LLUUID& selected_outfit_id = getSelectedOutfitID();
     if (selected_outfit_id.isNull()) // no selection or invalid outfit selected
     {
@@ -1252,24 +1247,11 @@ bool LLOutfitListGearMenuBase::onVisible(LLSD::String param)
     return true;
 }
 
-void LLOutfitListGearMenuBase::onUploadFoto()
+void LLOutfitListGearMenuBase::onThumbnail()
 {
-
-}
-
-void LLOutfitListGearMenuBase::onSelectPhoto()
-{
-
-}
-
-void LLOutfitListGearMenuBase::onTakeSnapshot()
-{
-
-}
-
-void LLOutfitListGearMenuBase::onRemovePhoto()
-{
-
+    const LLUUID& selected_outfit_id = getSelectedOutfitID();
+    LLSD data(selected_outfit_id);
+    LLFloaterReg::showInstance("change_item_thumbnail", data);
 }
 
 void LLOutfitListGearMenuBase::onChangeSortOrder()
@@ -1289,10 +1271,7 @@ void LLOutfitListGearMenu::onUpdateItemsVisibility()
     if (!mMenu) return;
     mMenu->setItemVisible("expand", TRUE);
     mMenu->setItemVisible("collapse", TRUE);
-    mMenu->setItemVisible("upload_photo", FALSE);
-    mMenu->setItemVisible("select_photo", FALSE);
-    mMenu->setItemVisible("take_snapshot", FALSE);
-    mMenu->setItemVisible("remove_photo", FALSE);
+    mMenu->setItemVisible("thumbnail", FALSE); // Never visible?
     mMenu->setItemVisible("sepatator3", FALSE);
     mMenu->setItemVisible("sort_folders_by_name", FALSE);
     LLOutfitListGearMenuBase::onUpdateItemsVisibility();
diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h
index 93a939157d6dd38341ec9b04bfe3a7a7b2eea05d..221a0b8c52979f47b4851b5e53cefb628d360c6f 100644
--- a/indra/newview/lloutfitslist.h
+++ b/indra/newview/lloutfitslist.h
@@ -167,10 +167,7 @@ class LLOutfitListGearMenuBase
 
 protected:
     virtual void onUpdateItemsVisibility();
-    virtual void onUploadFoto();
-    virtual void onSelectPhoto();
-    virtual void onTakeSnapshot();
-    virtual void onRemovePhoto();
+    virtual void onThumbnail();
     virtual void onChangeSortOrder();
 
     const LLUUID& getSelectedOutfitID();
diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp
index 834e664723bb1033b553d7f8b9e83f7147ba66b2..cc3c51dd8369b4212ac05f10f5d0bdd3048b9c26 100644
--- a/indra/newview/llpanellandmarkinfo.cpp
+++ b/indra/newview/llpanellandmarkinfo.cpp
@@ -111,9 +111,9 @@ void LLPanelLandmarkInfo::setInfoType(EInfoType type)
 }
 
 // Sets CREATE_LANDMARK infotype and creates landmark at desired folder
-void LLPanelLandmarkInfo::setInfoAndCreateLandmark(const LLUUID& fodler_id)
+void LLPanelLandmarkInfo::setInfoAndCreateLandmark(const LLUUID& folder_id)
 {
-    setInfoType(CREATE_LANDMARK, fodler_id);
+    setInfoType(CREATE_LANDMARK, folder_id);
 }
 
 void LLPanelLandmarkInfo::setInfoType(EInfoType type, const LLUUID &folder_id)
diff --git a/indra/newview/llpanellandmarkinfo.h b/indra/newview/llpanellandmarkinfo.h
index 46e2a1935bb037d5173910c5e76e26d5c36790f0..8802ce066e57fa28abf61834fbf0aff3b60b67d1 100644
--- a/indra/newview/llpanellandmarkinfo.h
+++ b/indra/newview/llpanellandmarkinfo.h
@@ -48,7 +48,7 @@ class LLPanelLandmarkInfo : public LLPanelPlaceInfo
 	/*virtual*/ void setInfoType(EInfoType type);
 
     // Sets CREATE_LANDMARK infotype and creates landmark at desired folder
-    void setInfoAndCreateLandmark(const LLUUID& fodler_id);
+    void setInfoAndCreateLandmark(const LLUUID& folder_id);
 
 	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);
 
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index d505d638f8a682a292b4bae5e3561ea9008fecb1..fcfac312b59d71eb64b4c0f87587a800607780ab 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -1099,11 +1099,6 @@ void LLPanelLogin::onRememberPasswordCheck(void*)
 
         std::string grid(LLGridManager::getInstance()->getGridId());
         std::string user_id(cred->userID());
-        if (!remember_password)
-        {
-            gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid, user_id);
-            gSecAPIHandler->syncProtectedMap();
-        }
     }
 }
 
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index 38b05088d5c2ee2325b7bcca9ce2547e9950ab89..6f2049ebc7e7ed08e5e116977ca8c9bbd38733ad 100644
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -37,8 +37,8 @@
 #include "llfilepicker.h"
 #include "llinventorybridge.h"
 #include "llinventoryfunctions.h"
+#include "llinventorygallery.h"
 #include "llinventorymodelbackgroundfetch.h"
-#include "llinventorypanel.h"
 #include "llfiltereditor.h"
 #include "llfloatersidepanelcontainer.h"
 #include "llfloaterreg.h"
@@ -53,12 +53,14 @@
 #include "llspinctrl.h"
 #include "lltoggleablemenu.h"
 #include "lltooldraganddrop.h"
+#include "lltrans.h"
 #include "llviewermenu.h"
 #include "llviewertexturelist.h"
 #include "llsidepanelinventory.h"
 #include "llfolderview.h"
 #include "llradiogroup.h"
 #include "llenvironment.h"
+#include "llweb.h"
 
 const std::string FILTERS_FILENAME("filters.xml");
 
@@ -113,7 +115,13 @@ LLPanelMainInventory::LLPanelMainInventory(const LLPanel::Params& p)
 	  mMenuGearDefault(NULL),
 	  mMenuVisibility(NULL),
 	  mMenuAddHandle(),
-	  mNeedUploadCost(true)
+	  mNeedUploadCost(true),
+      mMenuViewDefault(NULL),
+      mSingleFolderMode(false),
+      mForceShowInvLayout(false),
+      mViewMode(MODE_COMBINATION),
+      mListViewRootUpdatedConnection(),
+      mGalleryRootUpdatedConnection()
 {
 	// Menu Callbacks (non contex menus)
 	mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelMainInventory::doToSelected, this, _2));
@@ -125,7 +133,6 @@ LLPanelMainInventory::LLPanelMainInventory(const LLPanel::Params& p)
 	mCommitCallbackRegistrar.add("Inventory.ShowFilters", boost::bind(&LLPanelMainInventory::toggleFindOptions, this));
 	mCommitCallbackRegistrar.add("Inventory.ResetFilters", boost::bind(&LLPanelMainInventory::resetFilters, this));
 	mCommitCallbackRegistrar.add("Inventory.SetSortBy", boost::bind(&LLPanelMainInventory::setSortBy, this, _2));
-	mCommitCallbackRegistrar.add("Inventory.Share",  boost::bind(&LLAvatarActions::shareWithAvatars, this));
 
     mEnableCallbackRegistrar.add("Inventory.EnvironmentEnabled", [](LLUICtrl *, const LLSD &) { return LLPanelMainInventory::hasSettingsInventory(); });
     mEnableCallbackRegistrar.add("Inventory.MaterialsEnabled", [](LLUICtrl *, const LLSD &) { return LLPanelMainInventory::hasMaterialsInventory(); });
@@ -194,7 +201,7 @@ BOOL LLPanelMainInventory::postBuild()
 	}
 	// Now load the stored settings from disk, if available.
 	std::string filterSaveName(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, FILTERS_FILENAME));
-	LL_INFOS() << "LLPanelMainInventory::init: reading from " << filterSaveName << LL_ENDL;
+	LL_INFOS("Inventory") << "LLPanelMainInventory::init: reading from " << filterSaveName << LL_ENDL;
 	llifstream file(filterSaveName.c_str());
 	LLSD savedFilterState;
 	if (file.is_open())
@@ -239,6 +246,34 @@ BOOL LLPanelMainInventory::postBuild()
 
 	mGearMenuButton = getChild<LLMenuButton>("options_gear_btn");
 	mVisibilityMenuButton = getChild<LLMenuButton>("options_visibility_btn");
+    mViewMenuButton = getChild<LLMenuButton>("view_btn");
+
+    mBackBtn = getChild<LLButton>("back_btn");
+    mForwardBtn = getChild<LLButton>("forward_btn");
+    mUpBtn = getChild<LLButton>("up_btn");
+    mViewModeBtn = getChild<LLButton>("view_mode_btn");
+    mNavigationBtnsPanel = getChild<LLLayoutPanel>("nav_buttons");
+
+    mDefaultViewPanel = getChild<LLPanel>("default_inventory_panel");
+    mCombinationViewPanel = getChild<LLPanel>("combination_view_inventory");
+    mCombinationGalleryLayoutPanel = getChild<LLLayoutPanel>("comb_gallery_layout");
+    mCombinationListLayoutPanel = getChild<LLLayoutPanel>("comb_inventory_layout");
+    mCombinationLayoutStack = getChild<LLLayoutStack>("combination_view_stack");
+
+    mCombinationInventoryPanel = getChild<LLInventorySingleFolderPanel>("comb_single_folder_inv");
+    LLInventoryFilter& comb_inv_filter = mCombinationInventoryPanel->getFilter();
+    comb_inv_filter.setFilterThumbnails(LLInventoryFilter::FILTER_EXCLUDE_THUMBNAILS);
+    comb_inv_filter.markDefault();
+    mCombinationInventoryPanel->setSelectCallback(boost::bind(&LLPanelMainInventory::onCombinationInventorySelectionChanged, this, _1, _2));
+    mListViewRootUpdatedConnection = mCombinationInventoryPanel->setRootChangedCallback(boost::bind(&LLPanelMainInventory::onCombinationRootChanged, this, false));
+
+    mCombinationGalleryPanel = getChild<LLInventoryGallery>("comb_gallery_view_inv");
+    mCombinationGalleryPanel->setSortOrder(mCombinationInventoryPanel->getSortOrder());
+    LLInventoryFilter& comb_gallery_filter = mCombinationGalleryPanel->getFilter();
+    comb_gallery_filter.setFilterThumbnails(LLInventoryFilter::FILTER_ONLY_THUMBNAILS);
+    comb_gallery_filter.markDefault();
+    mGalleryRootUpdatedConnection = mCombinationGalleryPanel->setRootChangedCallback(boost::bind(&LLPanelMainInventory::onCombinationRootChanged, this, true));
+    mCombinationGalleryPanel->setSelectionChangeCallback(boost::bind(&LLPanelMainInventory::onCombinationGallerySelectionChanged, this, _1));
 
 	initListCommandsHandlers();
 
@@ -310,12 +345,21 @@ LLPanelMainInventory::~LLPanelMainInventory( void )
 	gInventory.removeObserver(this);
 	delete mSavedFolderState;
 
-	auto menu = mMenuAddHandle.get();
-	if(menu)
-	{
-		menu->die();
-		mMenuAddHandle.markDead();
-	}
+    auto menu = mMenuAddHandle.get();
+    if(menu)
+    {
+        menu->die();
+        mMenuAddHandle.markDead();
+    }
+
+    if (mListViewRootUpdatedConnection.connected())
+    {
+        mListViewRootUpdatedConnection.disconnect();
+    }
+    if (mGalleryRootUpdatedConnection.connected())
+    {
+        mGalleryRootUpdatedConnection.disconnect();
+    }
 }
 
 LLInventoryPanel* LLPanelMainInventory::getAllItemsPanel()
@@ -364,6 +408,10 @@ BOOL LLPanelMainInventory::handleKeyHere(KEY key, MASK mask)
 		{
 			startSearch();
 		}
+        if(mSingleFolderMode && key == KEY_LEFT)
+        {
+            onBackFolderClicked();
+        }
 	}
 
 	return LLPanel::handleKeyHere(key, mask);
@@ -388,27 +436,145 @@ void LLPanelMainInventory::closeAllFolders()
 	getPanel()->getRootFolder()->closeAllFolders();
 }
 
-void LLPanelMainInventory::newWindow()
+S32 get_instance_num()
+{
+    static S32 instance_num = 0;
+    instance_num = (instance_num + 1) % S32_MAX;
+
+    return instance_num;
+}
+
+LLFloaterSidePanelContainer* LLPanelMainInventory::newWindow()
 {
-	static S32 instance_num = 0;
-	instance_num = (instance_num + 1) % S32_MAX;
+    S32 instance_num = get_instance_num();
 
 	if (!gAgentCamera.cameraMouselook())
 	{
-		LLFloaterReg::showTypedInstance<LLFloaterSidePanelContainer>("inventory", LLSD(instance_num));
+        LLFloaterSidePanelContainer* floater = LLFloaterReg::showTypedInstance<LLFloaterSidePanelContainer>("inventory", LLSD(instance_num));
+        LLSidepanelInventory* sidepanel_inventory = floater->findChild<LLSidepanelInventory>("main_panel");
+        sidepanel_inventory->initInventoryViews();
+		return floater;
 	}
+    return NULL;
+}
+
+//static
+void LLPanelMainInventory::newFolderWindow(LLUUID folder_id, LLUUID item_to_select)
+{
+    LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
+    for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end();)
+    {
+        LLFloaterSidePanelContainer* inventory_container = dynamic_cast<LLFloaterSidePanelContainer*>(*iter++);
+        if (inventory_container)
+        {
+            LLSidepanelInventory* sidepanel_inventory = dynamic_cast<LLSidepanelInventory*>(inventory_container->findChild<LLPanel>("main_panel", true));
+            if (sidepanel_inventory)
+            {
+                LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
+                if (main_inventory && main_inventory->isSingleFolderMode()
+                    && (main_inventory->getCurrentSFVRoot() == folder_id))
+                {
+                    main_inventory->setFocus(true);
+                    if(item_to_select.notNull())
+                    {
+                        main_inventory->setGallerySelection(item_to_select);
+                    }
+                    return;
+                }
+            }
+        }
+    }
+    
+    S32 instance_num = get_instance_num();
+
+    LLFloaterSidePanelContainer* inventory_container = LLFloaterReg::showTypedInstance<LLFloaterSidePanelContainer>("inventory", LLSD(instance_num));
+    if(inventory_container)
+    {
+        LLSidepanelInventory* sidepanel_inventory = dynamic_cast<LLSidepanelInventory*>(inventory_container->findChild<LLPanel>("main_panel", true));
+        if (sidepanel_inventory)
+        {
+            LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
+            if (main_inventory)
+            {
+                main_inventory->initSingleFolderRoot(folder_id);
+                main_inventory->toggleViewMode();
+                if(folder_id.notNull())
+                {
+                    if(item_to_select.notNull())
+                    {
+                        main_inventory->setGallerySelection(item_to_select, true);
+                    }
+                }
+            }
+        }
+    }
 }
 
 void LLPanelMainInventory::doCreate(const LLSD& userdata)
 {
 	reset_inventory_filter();
-	menu_create_inventory_item(getPanel(), NULL, userdata);
+    if(mSingleFolderMode)
+    {
+        if(isListViewMode() || isCombinationViewMode())
+        {
+            LLFolderViewItem* current_folder = getActivePanel()->getRootFolder();
+            if (current_folder)
+            {
+                if(isCombinationViewMode())
+                {
+                    mForceShowInvLayout = true;
+                }
+
+                LLHandle<LLPanel> handle = getHandle();
+                std::function<void(const LLUUID&)> callback_created = [handle](const LLUUID& new_id)
+                {
+                    gInventory.notifyObservers(); // not really needed, should have been already done
+                    LLPanelMainInventory* panel = (LLPanelMainInventory*)handle.get();
+                    if (new_id.notNull() && panel)
+                    {
+                        // might need to refresh visibility, delay rename
+                        panel->mCombInvUUIDNeedsRename = new_id;
+
+                        if (panel->isCombinationViewMode())
+                        {
+                            panel->mForceShowInvLayout = true;
+                        }
+
+                        LL_DEBUGS("Inventory") << "Done creating inventory: " << new_id << LL_ENDL;
+                    }
+                };
+                menu_create_inventory_item(NULL, getCurrentSFVRoot(), userdata, LLUUID::null, callback_created);
+            }
+        }
+        else
+        {
+            LLHandle<LLPanel> handle = getHandle();
+            std::function<void(const LLUUID&)> callback_created = [handle](const LLUUID &new_id)
+            {
+                gInventory.notifyObservers(); // not really needed, should have been already done
+                if (new_id.notNull())
+                {
+                    LLPanelMainInventory* panel = (LLPanelMainInventory*)handle.get();
+                    if (panel)
+                    {
+                        panel->setGallerySelection(new_id);
+                        LL_DEBUGS("Inventory") << "Done creating inventory: " << new_id << LL_ENDL;
+                    }
+                }
+            };
+            menu_create_inventory_item(NULL, getCurrentSFVRoot(), userdata, LLUUID::null, callback_created);
+        }
+    }
+    else
+    {
+        menu_create_inventory_item(getPanel(), NULL, userdata);
+    }
 }
 
 void LLPanelMainInventory::resetFilters()
 {
 	LLFloaterInventoryFinder *finder = getFinder();
-	getActivePanel()->getFilter().resetDefault();
+	getCurrentFilter().resetDefault();
 	if (finder)
 	{
 		finder->updateElementsFromFilter();
@@ -429,6 +595,17 @@ void LLPanelMainInventory::resetAllItemsFilters()
     setFilterTextFromFilter();
 }
 
+void LLPanelMainInventory::findLinks(const LLUUID& item_id, const std::string& item_name)
+{
+    mFilterSubString = item_name;
+
+    LLInventoryFilter &filter = mActivePanel->getFilter();
+    filter.setFindAllLinksMode(item_name, item_id);
+
+    mFilterEditor->setText(item_name);
+    mFilterEditor->setFocus(TRUE);
+}
+
 void LLPanelMainInventory::setSortBy(const LLSD& userdata)
 {
 	U32 sort_order_mask = getActivePanel()->getSortOrder();
@@ -463,6 +640,10 @@ void LLPanelMainInventory::setSortBy(const LLSD& userdata)
 			sort_order_mask |= LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP;
 		}
 	}
+    if(mSingleFolderMode && !isListViewMode())
+    {
+        mCombinationGalleryPanel->setSortOrder(sort_order_mask, true);
+    }
 
 	getActivePanel()->setSortOrder(sort_order_mask);
     if (isRecentItemsPanelSelected())
@@ -480,25 +661,56 @@ void LLPanelMainInventory::onSelectSearchType()
 	std::string new_type = mSearchTypeCombo->getValue();
 	if (new_type == "search_by_name")
 	{
-		getActivePanel()->setSearchType(LLInventoryFilter::SEARCHTYPE_NAME);
+		setSearchType(LLInventoryFilter::SEARCHTYPE_NAME);
 	}
 	if (new_type == "search_by_creator")
 	{
-		getActivePanel()->setSearchType(LLInventoryFilter::SEARCHTYPE_CREATOR);
+		setSearchType(LLInventoryFilter::SEARCHTYPE_CREATOR);
 	}
 	if (new_type == "search_by_description")
 	{
-		getActivePanel()->setSearchType(LLInventoryFilter::SEARCHTYPE_DESCRIPTION);
+		setSearchType(LLInventoryFilter::SEARCHTYPE_DESCRIPTION);
 	}
 	if (new_type == "search_by_UUID")
 	{
-		getActivePanel()->setSearchType(LLInventoryFilter::SEARCHTYPE_UUID);
+		setSearchType(LLInventoryFilter::SEARCHTYPE_UUID);
 	}
 }
 
+void LLPanelMainInventory::setSearchType(LLInventoryFilter::ESearchType type)
+{
+    if(mSingleFolderMode && isGalleryViewMode())
+    {
+        mCombinationGalleryPanel->setSearchType(type);
+    }
+    if(mSingleFolderMode && isCombinationViewMode())
+    {
+        mCombinationInventoryPanel->setSearchType(type);
+        mCombinationGalleryPanel->setSearchType(type);
+    }
+    else
+    {
+        getActivePanel()->setSearchType(type);
+    }
+}
+
 void LLPanelMainInventory::updateSearchTypeCombo()
 {
-	LLInventoryFilter::ESearchType search_type = getActivePanel()->getSearchType();
+    LLInventoryFilter::ESearchType search_type(LLInventoryFilter::SEARCHTYPE_NAME);
+
+    if(mSingleFolderMode && isGalleryViewMode())
+    {
+        search_type = mCombinationGalleryPanel->getSearchType();
+    }
+    else if(mSingleFolderMode && isCombinationViewMode())
+    {
+        search_type = mCombinationGalleryPanel->getSearchType();
+    }
+    else
+    {
+        search_type = getActivePanel()->getSearchType();
+    }
+
 	switch(search_type)
 	{
 		case LLInventoryFilter::SEARCHTYPE_CREATOR:
@@ -544,7 +756,7 @@ void LLPanelMainInventory::onClearSearch()
 	}
 
 	// re-open folders that were initially open in case filter was active
-	if (mActivePanel && (mFilterSubString.size() || initially_active))
+	if (mActivePanel && (mFilterSubString.size() || initially_active) && !mSingleFolderMode)
 	{
 		mSavedFolderState->setApply(TRUE);
 		mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
@@ -554,7 +766,7 @@ void LLPanelMainInventory::onClearSearch()
 	}
 	mFilterSubString = "";
 
-	LLSidepanelInventory * sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
+	LLSidepanelInventory * sidepanel_inventory = getParentSidepanelInventory();
 	if (sidepanel_inventory)
 	{
 		LLPanelMarketplaceInbox* inbox_panel = sidepanel_inventory->getChild<LLPanelMarketplaceInbox>("marketplace_inbox");
@@ -567,16 +779,32 @@ void LLPanelMainInventory::onClearSearch()
 
 void LLPanelMainInventory::onFilterEdit(const std::string& search_string )
 {
+    if(mSingleFolderMode && isGalleryViewMode())
+    {
+        mFilterSubString = search_string;
+        mCombinationGalleryPanel->setFilterSubString(mFilterSubString);
+        return;
+    }
+    if(mSingleFolderMode && isCombinationViewMode())
+    {
+        mCombinationGalleryPanel->setFilterSubString(search_string);
+    }
+
 	if (search_string == "")
 	{
 		onClearSearch();
 	}
+
 	if (!mActivePanel)
 	{
 		return;
 	}
 
-	LLInventoryModelBackgroundFetch::instance().start();
+    if (!LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted())
+    {
+        llassert(false); // this should have been done on startup
+        LLInventoryModelBackgroundFetch::instance().start();
+    }
 
 	mFilterSubString = search_string;
 	if (mActivePanel->getFilterSubString().empty() && mFilterSubString.empty())
@@ -595,7 +823,7 @@ void LLPanelMainInventory::onFilterEdit(const std::string& search_string )
 	// set new filter string
 	setFilterSubString(mFilterSubString);
 
-	LLSidepanelInventory * sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
+    LLSidepanelInventory * sidepanel_inventory = getParentSidepanelInventory();
 	if (sidepanel_inventory)
 	{
 		LLPanelMarketplaceInbox* inbox_panel = sidepanel_inventory->getChild<LLPanelMarketplaceInbox>("marketplace_inbox");
@@ -650,7 +878,7 @@ void LLPanelMainInventory::onFilterEdit(const std::string& search_string )
 void LLPanelMainInventory::onFilterSelected()
 {
 	// Find my index
-	mActivePanel = (LLInventoryPanel*)getChild<LLTabContainer>("inventory filter tabs")->getCurrentPanel();
+    setActivePanel();
 
 	if (!mActivePanel)
 	{
@@ -663,15 +891,19 @@ void LLPanelMainInventory::onFilterSelected()
 	}
 	updateSearchTypeCombo();
 	setFilterSubString(mFilterSubString);
-	LLInventoryFilter& filter = mActivePanel->getFilter();
+	LLInventoryFilter& filter = getCurrentFilter();
 	LLFloaterInventoryFinder *finder = getFinder();
 	if (finder)
 	{
 		finder->changeFilter(&filter);
+        if (mSingleFolderMode)
+        {
+            finder->setTitle(getLocalizedRootName());
+        }
 	}
-	if (filter.isActive())
+	if (filter.isActive() && !LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted())
 	{
-		// If our filter is active we may be the first thing requiring a fetch so we better start it here.
+        llassert(false); // this should have been done on startup
 		LLInventoryModelBackgroundFetch::instance().start();
 	}
 	setFilterTextFromFilter();
@@ -743,6 +975,7 @@ void LLPanelMainInventory::draw()
 	}
 	LLPanel::draw();
 	updateItemcountText();
+    updateCombinationVisibility();
 }
 
 void LLPanelMainInventory::updateItemcountText()
@@ -788,6 +1021,21 @@ void LLPanelMainInventory::updateItemcountText()
 		itemcount_unknown_str.setArgList(string_args);
 		text = itemcount_unknown_str.getString();
 	}
+
+    if (mSingleFolderMode)
+    {
+        LLInventoryModel::cat_array_t *cats;
+        LLInventoryModel::item_array_t *items;
+
+        gInventory.getDirectDescendentsOf(getCurrentSFVRoot(), cats, items);
+
+        if (items && cats)
+        {
+            string_args["[ITEM_COUNT]"] = llformat("%d", items->size());
+            string_args["[CATEGORY_COUNT]"] = llformat("%d", cats->size());
+            text = getString("ItemcountCompleted", string_args);
+        }
+    }
 	
     mCounterCtrl->setValue(text);
     mCounterCtrl->setToolTip(text);
@@ -807,7 +1055,7 @@ void LLPanelMainInventory::onFocusReceived()
 
 void LLPanelMainInventory::setFilterTextFromFilter() 
 { 
-	mFilterText = mActivePanel->getFilter().getFilterText(); 
+	mFilterText = getCurrentFilter().getFilterText();
 }
 
 void LLPanelMainInventory::toggleFindOptions()
@@ -822,8 +1070,17 @@ void LLPanelMainInventory::toggleFindOptions()
 		LLFloater* parent_floater = gFloaterView->getParentFloater(this);
 		if (parent_floater)
 			parent_floater->addDependentFloater(mFinderHandle);
-		// start background fetch of folders
-		LLInventoryModelBackgroundFetch::instance().start();
+
+        if (!LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted())
+        {
+            llassert(false); // this should have been done on startup
+            LLInventoryModelBackgroundFetch::instance().start();
+        }
+
+        if (mSingleFolderMode)
+        {
+            finder->setTitle(getLocalizedRootName());
+        }
 	}
 	else
 	{
@@ -1070,10 +1327,27 @@ void LLFloaterInventoryFinder::draw()
 		filter &= ~(0x1 << LLInventoryType::IT_CATEGORY);
 	}
 
-	// update the panel, panel will update the filter
-	mPanelMainInventory->getPanel()->setShowFolderState(getCheckShowEmpty() ?
-		LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
-	mPanelMainInventory->getPanel()->setFilterTypes(filter);
+
+    bool is_sf_mode = mPanelMainInventory->isSingleFolderMode();
+    if(is_sf_mode && mPanelMainInventory->isGalleryViewMode())
+    {
+        mPanelMainInventory->mCombinationGalleryPanel->getFilter().setShowFolderState(getCheckShowEmpty() ?
+            LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
+        mPanelMainInventory->mCombinationGalleryPanel->getFilter().setFilterObjectTypes(filter);
+    }
+    else
+    {
+        if(is_sf_mode && mPanelMainInventory->isCombinationViewMode())
+        {
+            mPanelMainInventory->mCombinationGalleryPanel->getFilter().setShowFolderState(getCheckShowEmpty() ?
+                LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
+            mPanelMainInventory->mCombinationGalleryPanel->getFilter().setFilterObjectTypes(filter);
+        }
+        // update the panel, panel will update the filter
+        mPanelMainInventory->getPanel()->setShowFolderState(getCheckShowEmpty() ?
+            LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
+        mPanelMainInventory->getPanel()->setFilterTypes(filter);
+    }
 
 	if (getCheckSinceLogoff())
 	{
@@ -1095,10 +1369,26 @@ void LLFloaterInventoryFinder::draw()
 	}
 	hours += days * 24;
 
-	mPanelMainInventory->getPanel()->setHoursAgo(hours);
-	mPanelMainInventory->getPanel()->setSinceLogoff(getCheckSinceLogoff());
+
 	mPanelMainInventory->setFilterTextFromFilter();
-	mPanelMainInventory->getPanel()->setDateSearchDirection(getDateSearchDirection());
+    if(is_sf_mode && mPanelMainInventory->isGalleryViewMode())
+    {
+        mPanelMainInventory->mCombinationGalleryPanel->getFilter().setHoursAgo(hours);
+        mPanelMainInventory->mCombinationGalleryPanel->getFilter().setDateRangeLastLogoff(getCheckSinceLogoff());
+        mPanelMainInventory->mCombinationGalleryPanel->getFilter().setDateSearchDirection(getDateSearchDirection());
+    }
+    else
+    {
+        if(is_sf_mode && mPanelMainInventory->isCombinationViewMode())
+        {
+            mPanelMainInventory->mCombinationGalleryPanel->getFilter().setHoursAgo(hours);
+            mPanelMainInventory->mCombinationGalleryPanel->getFilter().setDateRangeLastLogoff(getCheckSinceLogoff());
+            mPanelMainInventory->mCombinationGalleryPanel->getFilter().setDateSearchDirection(getDateSearchDirection());
+        }
+        mPanelMainInventory->getPanel()->setHoursAgo(hours);
+        mPanelMainInventory->getPanel()->setSinceLogoff(getCheckSinceLogoff());
+        mPanelMainInventory->getPanel()->setDateSearchDirection(getDateSearchDirection());
+    }
 
 	LLPanel::draw();
 }
@@ -1110,15 +1400,15 @@ void LLFloaterInventoryFinder::onCreatorSelfFilterCommit()
 
 	if(show_creator_self && show_creator_other)
 	{
-		mFilter->setFilterCreator(LLInventoryFilter::FILTERCREATOR_ALL);
+        mPanelMainInventory->getCurrentFilter().setFilterCreator(LLInventoryFilter::FILTERCREATOR_ALL);
 	}
 	else if(show_creator_self)
 	{
-		mFilter->setFilterCreator(LLInventoryFilter::FILTERCREATOR_SELF);
+        mPanelMainInventory->getCurrentFilter().setFilterCreator(LLInventoryFilter::FILTERCREATOR_SELF);
 	}
 	else if(!show_creator_self || !show_creator_other)
 	{
-		mFilter->setFilterCreator(LLInventoryFilter::FILTERCREATOR_OTHERS);
+        mPanelMainInventory->getCurrentFilter().setFilterCreator(LLInventoryFilter::FILTERCREATOR_OTHERS);
 		mCreatorOthers->set(TRUE);
 	}
 }
@@ -1130,15 +1420,15 @@ void LLFloaterInventoryFinder::onCreatorOtherFilterCommit()
 
 	if(show_creator_self && show_creator_other)
 	{
-		mFilter->setFilterCreator(LLInventoryFilter::FILTERCREATOR_ALL);
+        mPanelMainInventory->getCurrentFilter().setFilterCreator(LLInventoryFilter::FILTERCREATOR_ALL);
 	}
 	else if(show_creator_other)
 	{
-		mFilter->setFilterCreator(LLInventoryFilter::FILTERCREATOR_OTHERS);
+        mPanelMainInventory->getCurrentFilter().setFilterCreator(LLInventoryFilter::FILTERCREATOR_OTHERS);
 	}
 	else if(!show_creator_other || !show_creator_self)
 	{
-		mFilter->setFilterCreator(LLInventoryFilter::FILTERCREATOR_SELF);
+        mPanelMainInventory->getCurrentFilter().setFilterCreator(LLInventoryFilter::FILTERCREATOR_SELF);
 		mCreatorSelf->set(TRUE);
 	}
 }
@@ -1213,26 +1503,25 @@ void LLFloaterInventoryFinder::selectNoTypes(void* user_data)
 
 void LLPanelMainInventory::initListCommandsHandlers()
 {
-	childSetAction("trash_btn", boost::bind(&LLPanelMainInventory::onTrashButtonClick, this));
 	childSetAction("add_btn", boost::bind(&LLPanelMainInventory::onAddButtonClick, this));
-
-	mTrashButton = getChild<LLDragAndDropButton>("trash_btn");
-	mTrashButton->setDragAndDropHandler(boost::bind(&LLPanelMainInventory::handleDragAndDropToTrash, this
-			,	_4 // BOOL drop
-			,	_5 // EDragAndDropType cargo_type
-			,	_7 // EAcceptance* accept
-			));
+    childSetAction("view_mode_btn", boost::bind(&LLPanelMainInventory::onViewModeClick, this));
+    childSetAction("up_btn", boost::bind(&LLPanelMainInventory::onUpFolderClicked, this));
+    childSetAction("back_btn", boost::bind(&LLPanelMainInventory::onBackFolderClicked, this));
+    childSetAction("forward_btn", boost::bind(&LLPanelMainInventory::onForwardFolderClicked, this));
 
 	mCommitCallbackRegistrar.add("Inventory.GearDefault.Custom.Action", boost::bind(&LLPanelMainInventory::onCustomAction, this, _2));
 	mEnableCallbackRegistrar.add("Inventory.GearDefault.Check", boost::bind(&LLPanelMainInventory::isActionChecked, this, _2));
 	mEnableCallbackRegistrar.add("Inventory.GearDefault.Enable", boost::bind(&LLPanelMainInventory::isActionEnabled, this, _2));
+    mEnableCallbackRegistrar.add("Inventory.GearDefault.Visible", boost::bind(&LLPanelMainInventory::isActionVisible, this, _2));
 	mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
-	mGearMenuButton->setMenu(mMenuGearDefault, LLMenuButton::MP_TOP_LEFT, true);
+	mGearMenuButton->setMenu(mMenuGearDefault, LLMenuButton::MP_BOTTOM_LEFT, true);
+    mMenuViewDefault = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_view_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+    mViewMenuButton->setMenu(mMenuViewDefault, LLMenuButton::MP_BOTTOM_LEFT, true);
 	LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_inventory_add.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 	mMenuAddHandle = menu->getHandle();
 
 	mMenuVisibility = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_search_visibility.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
-	mVisibilityMenuButton->setMenu(mMenuVisibility, LLMenuButton::MP_BOTTOM_LEFT, true);
+    mVisibilityMenuButton->setMenu(mMenuVisibility, LLMenuButton::MP_BOTTOM_LEFT, true);
 
 	// Update the trash button when selected item(s) get worn or taken off.
 	LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLPanelMainInventory::updateListCommands, this));
@@ -1240,9 +1529,6 @@ void LLPanelMainInventory::initListCommandsHandlers()
 
 void LLPanelMainInventory::updateListCommands()
 {
-	bool trash_enabled = isActionEnabled("delete");
-
-	mTrashButton->setEnabled(trash_enabled);
 }
 
 void LLPanelMainInventory::onAddButtonClick()
@@ -1253,7 +1539,7 @@ void LLPanelMainInventory::onAddButtonClick()
 	LLMenuGL* menu = (LLMenuGL*)mMenuAddHandle.get();
 	if (menu)
 	{
-		menu->getChild<LLMenuItemGL>("New Folder")->setEnabled(!isRecentItemsPanelSelected());
+        disableAddIfNeeded();
 
 		setUploadCostIfNeeded();
 
@@ -1261,6 +1547,215 @@ void LLPanelMainInventory::onAddButtonClick()
 	}
 }
 
+void LLPanelMainInventory::setActivePanel()
+{
+    // Todo: should cover gallery mode in some way
+    if(mSingleFolderMode && isListViewMode())
+    {
+        mActivePanel = getChild<LLInventoryPanel>("comb_single_folder_inv");
+    }
+    else if(mSingleFolderMode && isCombinationViewMode())
+    {
+        mActivePanel = getChild<LLInventoryPanel>("comb_single_folder_inv");
+    }
+    else
+    {
+        mActivePanel = (LLInventoryPanel*)getChild<LLTabContainer>("inventory filter tabs")->getCurrentPanel();
+    }
+    mViewModeBtn->setEnabled(mSingleFolderMode || (getAllItemsPanel() == getActivePanel()));
+}
+
+void LLPanelMainInventory::initSingleFolderRoot(const LLUUID& start_folder_id)
+{
+    mCombinationInventoryPanel->initFolderRoot(start_folder_id);
+}
+
+void LLPanelMainInventory::initInventoryViews()
+{
+    LLInventoryPanel* all_item = getChild<LLInventoryPanel>(ALL_ITEMS);
+    all_item->initializeViewBuilding();
+    LLInventoryPanel* recent_item = getChild<LLInventoryPanel>(RECENT_ITEMS);
+    recent_item->initializeViewBuilding();
+    LLInventoryPanel* worn_item = getChild<LLInventoryPanel>(WORN_ITEMS);
+    worn_item->initializeViewBuilding();
+}
+
+void LLPanelMainInventory::toggleViewMode()
+{
+    if(mSingleFolderMode && isCombinationViewMode())
+    {
+        mCombinationInventoryPanel->getRootFolder()->setForceArrange(false);
+    }
+
+    mSingleFolderMode = !mSingleFolderMode;
+    mReshapeInvLayout = true;
+
+    if (mCombinationGalleryPanel->getRootFolder().isNull())
+    {
+        mCombinationGalleryPanel->setRootFolder(mCombinationInventoryPanel->getSingleFolderRoot());
+        mCombinationGalleryPanel->updateRootFolder();
+    }
+
+    updatePanelVisibility();
+    setActivePanel();
+    updateTitle();
+    onFilterSelected();
+
+    LLSidepanelInventory* sidepanel_inventory = getParentSidepanelInventory();
+    if (sidepanel_inventory)
+    {
+        if(mSingleFolderMode)
+        {
+            sidepanel_inventory->hideInbox();
+        }
+        else
+        {
+            sidepanel_inventory->toggleInbox();
+        }
+    }
+}
+
+void LLPanelMainInventory::onViewModeClick()
+{
+    LLUUID selected_folder;
+    LLUUID new_root_folder;
+    if(mSingleFolderMode)
+    {
+        selected_folder = getCurrentSFVRoot();
+    }
+    else
+    {
+        LLFolderView* root = getActivePanel()->getRootFolder();
+        std::set<LLFolderViewItem*> selection_set = root->getSelectionList();
+        if (selection_set.size() == 1)
+        {
+            LLFolderViewItem* current_item = *selection_set.begin();
+            if (current_item)
+            {
+                const LLUUID& id = static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getUUID();
+                if(gInventory.getCategory(id) != NULL)
+                {
+                    new_root_folder = id;
+                }
+                else
+                {
+                    const LLViewerInventoryItem* selected_item = gInventory.getItem(id);
+                    if (selected_item && selected_item->getParentUUID().notNull())
+                    {
+                        new_root_folder = selected_item->getParentUUID();
+                        selected_folder = id;
+                    }
+                }
+            }
+        }
+        mCombinationInventoryPanel->initFolderRoot(new_root_folder);
+    }
+
+    toggleViewMode();
+
+    if (mSingleFolderMode && new_root_folder.notNull())
+    {
+        setSingleFolderViewRoot(new_root_folder, true);
+        if(selected_folder.notNull() && isListViewMode())
+        {
+            getActivePanel()->setSelection(selected_folder, TAKE_FOCUS_YES);
+        }
+    }
+    else
+    {
+        if(selected_folder.notNull())
+        {
+            selectAllItemsPanel();
+            getActivePanel()->setSelection(selected_folder, TAKE_FOCUS_YES);
+        }
+    }
+}
+
+void LLPanelMainInventory::onUpFolderClicked()
+{
+    const LLViewerInventoryCategory* cat = gInventory.getCategory(getCurrentSFVRoot());
+    if (cat)
+    {
+        if (cat->getParentUUID().notNull())
+        {
+            if(isListViewMode())
+            {
+                mCombinationInventoryPanel->changeFolderRoot(cat->getParentUUID());
+            }
+            if(isGalleryViewMode())
+            {
+                mCombinationGalleryPanel->setRootFolder(cat->getParentUUID());
+            }
+            if(isCombinationViewMode())
+            {
+                mCombinationInventoryPanel->changeFolderRoot(cat->getParentUUID());
+            }
+        }
+    }
+}
+
+void LLPanelMainInventory::onBackFolderClicked()
+{
+    if(isListViewMode())
+    {
+        mCombinationInventoryPanel->onBackwardFolder();
+    }
+    if(isGalleryViewMode())
+    {
+        mCombinationGalleryPanel->onBackwardFolder();
+    }
+    if(isCombinationViewMode())
+    {
+        mCombinationInventoryPanel->onBackwardFolder();
+    }
+}
+
+void LLPanelMainInventory::onForwardFolderClicked()
+{
+    if(isListViewMode())
+    {
+        mCombinationInventoryPanel->onForwardFolder();
+    }
+    if(isGalleryViewMode())
+    {
+        mCombinationGalleryPanel->onForwardFolder();
+    }
+    if(isCombinationViewMode())
+    {
+        mCombinationInventoryPanel->onForwardFolder();
+    }
+}
+
+void LLPanelMainInventory::setSingleFolderViewRoot(const LLUUID& folder_id, bool clear_nav_history)
+{
+    if(isListViewMode())
+    {
+        mCombinationInventoryPanel->changeFolderRoot(folder_id);
+        if(clear_nav_history)
+        {
+            mCombinationInventoryPanel->clearNavigationHistory();
+        }
+    }
+    else if(isGalleryViewMode())
+    {
+        mCombinationGalleryPanel->setRootFolder(folder_id);
+        if(clear_nav_history)
+        {
+            mCombinationGalleryPanel->clearNavigationHistory();
+        }
+    }
+    else if(isCombinationViewMode())
+    {
+        mCombinationInventoryPanel->changeFolderRoot(folder_id);
+    }
+    updateNavButtons();
+}
+
+LLUUID LLPanelMainInventory::getSingleFolderViewRoot()
+{
+    return mCombinationInventoryPanel->getSingleFolderRoot();
+}
+
 void LLPanelMainInventory::showActionMenu(LLMenuGL* menu, std::string spawning_view_name)
 {
 	if (menu)
@@ -1270,17 +1765,11 @@ void LLPanelMainInventory::showActionMenu(LLMenuGL* menu, std::string spawning_v
 		LLView* spawning_view = getChild<LLView> (spawning_view_name);
 		S32 menu_x, menu_y;
 		//show menu in co-ordinates of panel
-		spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this);
-		menu_y += menu->getRect().getHeight();
+		spawning_view->localPointToOtherView(0, 0, &menu_x, &menu_y, this);
 		LLMenuGL::showPopup(this, menu, menu_x, menu_y);
 	}
 }
 
-void LLPanelMainInventory::onTrashButtonClick()
-{
-	onClipboardAction("delete");
-}
-
 void LLPanelMainInventory::onClipboardAction(const LLSD& userdata)
 {
 	std::string command_name = userdata.asString();
@@ -1289,13 +1778,22 @@ void LLPanelMainInventory::onClipboardAction(const LLSD& userdata)
 
 void LLPanelMainInventory::saveTexture(const LLSD& userdata)
 {
-	LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem();
-	if (!current_item)
-	{
-		return;
-	}
-	
-	const LLUUID& item_id = static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getUUID();
+    LLUUID item_id;
+    if(mSingleFolderMode && isGalleryViewMode())
+    {
+        item_id = mCombinationGalleryPanel->getFirstSelectedItemID();
+        if (item_id.isNull()) return;
+    }
+    else
+    {
+        LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem();
+        if (!current_item)
+        {
+            return;
+        }
+        item_id = static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getUUID();
+    }
+
 	LLPreviewTexture* preview_texture = LLFloaterReg::showTypedInstance<LLPreviewTexture>("preview_texture", LLSD(item_id), TAKE_FOCUS_YES);
 	if (preview_texture)
 	{
@@ -1309,6 +1807,7 @@ void LLPanelMainInventory::onCustomAction(const LLSD& userdata)
 		return;
 
 	const std::string command_name = userdata.asString();
+
 	if (command_name == "new_window")
 	{
 		newWindow();
@@ -1382,35 +1881,69 @@ void LLPanelMainInventory::onCustomAction(const LLSD& userdata)
 	}
 	if (command_name == "find_original")
 	{
+        if(mSingleFolderMode && isGalleryViewMode())
+        {
+            LLInventoryObject *obj = gInventory.getObject(mCombinationGalleryPanel->getFirstSelectedItemID());
+            if (obj && obj->getIsLinkType())
+            {
+                show_item_original(obj->getUUID());
+            }
+        }
+        else
+        {
 		LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem();
 		if (!current_item)
 		{
 			return;
 		}
 		static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->performAction(getActivePanel()->getModel(), "goto");
+        }
 	}
 
 	if (command_name == "find_links")
 	{
-		LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem();
-		if (!current_item)
-		{
-			return;
-		}
-		const LLUUID& item_id = static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getUUID();
-		const std::string &item_name = current_item->getViewModelItem()->getName();
-		mFilterSubString = item_name;
-
-		LLInventoryFilter &filter = mActivePanel->getFilter();
-		filter.setFindAllLinksMode(item_name, item_id);
-
-		mFilterEditor->setText(item_name);
-		mFilterEditor->setFocus(TRUE);
+        if(mSingleFolderMode && isGalleryViewMode())
+        {
+            LLFloaterSidePanelContainer* inventory_container = newWindow();
+            if (inventory_container)
+            {
+                LLSidepanelInventory* sidepanel_inventory = dynamic_cast<LLSidepanelInventory*>(inventory_container->findChild<LLPanel>("main_panel", true));
+                if (sidepanel_inventory)
+                {
+                    LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
+                    if (main_inventory)
+                    {
+                        LLInventoryObject *obj = gInventory.getObject(mCombinationGalleryPanel->getFirstSelectedItemID());
+                        if (obj)
+                        {
+                            main_inventory->findLinks(obj->getUUID(), obj->getName());
+                        }
+                    }
+                }
+            }
+        }
+        else
+        {
+            LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem();
+            if (!current_item)
+            {
+                return;
+            }
+            const LLUUID& item_id = static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getUUID();
+            const std::string &item_name = current_item->getViewModelItem()->getName();
+            findLinks(item_id, item_name);
+        }
 	}
 
 	if (command_name == "replace_links")
 	{
-		LLSD params;
+        LLSD params;
+        if(mSingleFolderMode && isGalleryViewMode())
+        {
+            params = LLSD(mCombinationGalleryPanel->getFirstSelectedItemID());
+        }
+        else
+        {
 		LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem();
 		if (current_item)
 		{
@@ -1425,23 +1958,72 @@ void LLPanelMainInventory::onCustomAction(const LLSD& userdata)
 				}
 			}
 		}
+        }
 		LLFloaterReg::showInstance("linkreplace", params);
 	}
 
+    if (command_name == "close_inv_windows")
+    {
+        LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
+        for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end();)
+        {
+            LLFloaterSidePanelContainer* iv = dynamic_cast<LLFloaterSidePanelContainer*>(*iter++);
+            if (iv)
+            {
+                iv->closeFloater();
+            }
+        }
+        LLFloaterReg::hideInstance("inventory_settings");
+    }
+
+    if (command_name == "toggle_search_outfits")
+    {
+        getCurrentFilter().toggleSearchVisibilityOutfits();
+    }
+
 	if (command_name == "toggle_search_trash")
 	{
-		mActivePanel->getFilter().toggleSearchVisibilityTrash();
+        getCurrentFilter().toggleSearchVisibilityTrash();
 	}
 
 	if (command_name == "toggle_search_library")
 	{
-		mActivePanel->getFilter().toggleSearchVisibilityLibrary();
+        getCurrentFilter().toggleSearchVisibilityLibrary();
 	}
 
 	if (command_name == "include_links")
 	{
-		mActivePanel->getFilter().toggleSearchVisibilityLinks();
-	}		
+        getCurrentFilter().toggleSearchVisibilityLinks();
+	}
+
+    if (command_name == "share")
+    {
+        if(mSingleFolderMode && isGalleryViewMode())
+        {
+            std::set<LLUUID> uuids{ mCombinationGalleryPanel->getFirstSelectedItemID()};
+            LLAvatarActions::shareWithAvatars(uuids, gFloaterView->getParentFloater(this));
+        }
+        else
+        {
+            LLAvatarActions::shareWithAvatars(this);
+        }
+    }
+    if (command_name == "shop")
+    {
+        LLWeb::loadURL(gSavedSettings.getString("MarketplaceURL"));
+    }
+    if (command_name == "list_view")
+    {
+        setViewMode(MODE_LIST);
+    }
+    if (command_name == "gallery_view")
+    {
+        setViewMode(MODE_GALLERY);
+    }
+    if (command_name == "combination_view")
+    {
+        setViewMode(MODE_COMBINATION);
+    }
 }
 
 void LLPanelMainInventory::onVisibilityChange( BOOL new_visibility )
@@ -1459,17 +2041,26 @@ void LLPanelMainInventory::onVisibilityChange( BOOL new_visibility )
 
 bool LLPanelMainInventory::isSaveTextureEnabled(const LLSD& userdata)
 {
-	LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem();
-	if (current_item) 
-	{
-		LLViewerInventoryItem *inv_item = dynamic_cast<LLViewerInventoryItem*>(static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getInventoryObject());
+    LLViewerInventoryItem *inv_item = NULL;
+    if(mSingleFolderMode && isGalleryViewMode())
+    {
+        inv_item = gInventory.getItem(mCombinationGalleryPanel->getFirstSelectedItemID());
+    }
+    else
+    {
+        LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem();
+        if (current_item)
+        {
+            inv_item = dynamic_cast<LLViewerInventoryItem*>(static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getInventoryObject());
+        }
+    }
 		if(inv_item)
 		{
 			bool can_save = inv_item->checkPermissionsSet(PERM_ITEM_UNRESTRICTED);
-			LLInventoryType::EType curr_type = static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getInventoryType();
+            LLInventoryType::EType curr_type = inv_item->getInventoryType();
 			return can_save && (curr_type == LLInventoryType::IT_TEXTURE || curr_type == LLInventoryType::IT_SNAPSHOT);
 		}
-	}
+
 	return false;
 }
 
@@ -1500,9 +2091,16 @@ BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata)
 	}
 	if (command_name == "find_original")
 	{
+        LLUUID item_id;
+        if(mSingleFolderMode && isGalleryViewMode())
+        {
+            item_id = mCombinationGalleryPanel->getFirstSelectedItemID();
+        }
+        else{
 		LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem();
 		if (!current_item) return FALSE;
-		const LLUUID& item_id = static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getUUID();
+        item_id = static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getUUID();
+        }
 		const LLViewerInventoryItem *item = gInventory.getItem(item_id);
 		if (item && item->getIsLinkType() && !item->getIsBrokenLink())
 		{
@@ -1513,12 +2111,19 @@ BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata)
 
 	if (command_name == "find_links")
 	{
+        LLUUID item_id;
+        if(mSingleFolderMode && isGalleryViewMode())
+        {
+            item_id = mCombinationGalleryPanel->getFirstSelectedItemID();
+        }
+        else{
 		LLFolderView* root = getActivePanel()->getRootFolder();
 		std::set<LLFolderViewItem*> selection_set = root->getSelectionList();
 		if (selection_set.size() != 1) return FALSE;
 		LLFolderViewItem* current_item = root->getCurSelectedItem();
 		if (!current_item) return FALSE;
-		const LLUUID& item_id = static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getUUID();
+		item_id = static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getUUID();
+        }
 		const LLInventoryObject *obj = gInventory.getObject(item_id);
 		if (obj && !obj->getIsLinkType() && LLAssetType::lookupCanLink(obj->getType()))
 		{
@@ -1542,10 +2147,16 @@ BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata)
 
 	if (command_name == "share")
 	{
+        if(mSingleFolderMode && isGalleryViewMode())
+        {
+            return can_share_item(mCombinationGalleryPanel->getFirstSelectedItemID());
+        }
+        else{
 		LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem();
 		if (!current_item) return FALSE;
 		LLSidepanelInventory* parent = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
 		return parent ? parent->canShare() : FALSE;
+        }
 	}
 	if (command_name == "empty_trash")
 	{
@@ -1563,9 +2174,24 @@ BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata)
 	return TRUE;
 }
 
+bool LLPanelMainInventory::isActionVisible(const LLSD& userdata)
+{
+    const std::string param_str = userdata.asString();
+    if (param_str == "single_folder_view")
+    {
+        return mSingleFolderMode;
+    }
+    if (param_str == "multi_folder_view")
+    {
+        return !mSingleFolderMode;
+    }
+
+    return true;
+}
+
 BOOL LLPanelMainInventory::isActionChecked(const LLSD& userdata)
 {
-	U32 sort_order_mask = getActivePanel()->getSortOrder();
+	U32 sort_order_mask = (mSingleFolderMode && isGalleryViewMode()) ? mCombinationGalleryPanel->getSortOrder() :  getActivePanel()->getSortOrder();
 	const std::string command_name = userdata.asString();
 	if (command_name == "sort_by_name")
 	{
@@ -1587,36 +2213,40 @@ BOOL LLPanelMainInventory::isActionChecked(const LLSD& userdata)
 		return sort_order_mask & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP;
 	}
 
+    if (command_name == "toggle_search_outfits")
+    {
+        return (getCurrentFilter().getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_OUTFITS) != 0;
+    }
+
 	if (command_name == "toggle_search_trash")
 	{
-		return (mActivePanel->getFilter().getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_TRASH) != 0;
+		return (getCurrentFilter().getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_TRASH) != 0;
 	}
 
 	if (command_name == "toggle_search_library")
 	{
-		return (mActivePanel->getFilter().getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_LIBRARY) != 0;
+		return (getCurrentFilter().getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_LIBRARY) != 0;
 	}
 
 	if (command_name == "include_links")
 	{
-		return (mActivePanel->getFilter().getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_LINKS) != 0;	
+        return (getCurrentFilter().getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_LINKS) != 0;
 	}	
 
-	return FALSE;
-}
-
-bool LLPanelMainInventory::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept)
-{
-	*accept = ACCEPT_NO;
-
-	const bool is_enabled = isActionEnabled("delete");
-	if (is_enabled) *accept = ACCEPT_YES_MULTI;
+    if (command_name == "list_view")
+    {
+        return isListViewMode();
+    }
+    if (command_name == "gallery_view")
+    {
+        return isGalleryViewMode();
+    }
+    if (command_name == "combination_view")
+    {
+        return isCombinationViewMode();
+    }
 
-	if (is_enabled && drop)
-	{
-		onClipboardAction("delete");
-	}
-	return true;
+	return FALSE;
 }
 
 void LLPanelMainInventory::setUploadCostIfNeeded()
@@ -1634,6 +2264,55 @@ void LLPanelMainInventory::setUploadCostIfNeeded()
 	}
 }
 
+bool is_add_allowed(LLUUID folder_id)
+{
+    if(!gInventory.isObjectDescendentOf(folder_id, gInventory.getRootFolderID()))
+    {
+        return false;
+    }
+
+    std::vector<LLFolderType::EType> not_allowed_types;
+    not_allowed_types.push_back(LLFolderType::FT_LOST_AND_FOUND);
+    not_allowed_types.push_back(LLFolderType::FT_FAVORITE);
+    not_allowed_types.push_back(LLFolderType::FT_MARKETPLACE_LISTINGS);
+    not_allowed_types.push_back(LLFolderType::FT_TRASH);
+    not_allowed_types.push_back(LLFolderType::FT_CURRENT_OUTFIT);
+    not_allowed_types.push_back(LLFolderType::FT_INBOX);
+
+    for (std::vector<LLFolderType::EType>::const_iterator it = not_allowed_types.begin();
+         it != not_allowed_types.end(); ++it)
+    {
+        if(gInventory.isObjectDescendentOf(folder_id, gInventory.findCategoryUUIDForType(*it)))
+        {
+            return false;
+        }
+    }
+
+    LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id);
+    if (cat && (cat->getPreferredType() == LLFolderType::FT_OUTFIT))
+    {
+        return false;
+    }
+    return true;
+}
+
+void LLPanelMainInventory::disableAddIfNeeded()
+{
+    LLMenuGL* menu = (LLMenuGL*)mMenuAddHandle.get();
+    if (menu)
+    {
+        bool enable = !mSingleFolderMode || is_add_allowed(getCurrentSFVRoot());
+
+        menu->getChild<LLMenuItemGL>("New Folder")->setEnabled(enable && !isRecentItemsPanelSelected());
+        menu->getChild<LLMenuItemGL>("New Script")->setEnabled(enable);
+        menu->getChild<LLMenuItemGL>("New Note")->setEnabled(enable);
+        menu->getChild<LLMenuItemGL>("New Gesture")->setEnabled(enable);
+        menu->setItemEnabled("New Clothes", enable);
+        menu->setItemEnabled("New Body Parts", enable);
+        menu->setItemEnabled("New Settings", enable);
+    }
+}
+
 bool LLPanelMainInventory::hasSettingsInventory()
 {
     return LLEnvironment::instance().isInventoryEnabled();
@@ -1647,5 +2326,356 @@ bool LLPanelMainInventory::hasMaterialsInventory()
     return (!agent_url.empty() && !task_url.empty());
 }
 
+void LLPanelMainInventory::updateTitle()
+{
+    LLFloater* inventory_floater = gFloaterView->getParentFloater(this);
+    if(inventory_floater)
+    {
+        if(mSingleFolderMode)
+        {
+            inventory_floater->setTitle(getLocalizedRootName());
+            LLFloaterInventoryFinder *finder = getFinder();
+            if (finder)
+            {
+                finder->setTitle(getLocalizedRootName());
+            }
+        }
+        else
+        {
+            inventory_floater->setTitle(getString("inventory_title"));
+        }
+    }
+    updateNavButtons();
+}
+
+void LLPanelMainInventory::onCombinationRootChanged(bool gallery_clicked)
+{
+    if(gallery_clicked)
+    {
+        mCombinationInventoryPanel->changeFolderRoot(mCombinationGalleryPanel->getRootFolder());
+    }
+    else
+    {
+        mCombinationGalleryPanel->setRootFolder(mCombinationInventoryPanel->getSingleFolderRoot());
+    }
+    mForceShowInvLayout = false;
+    updateTitle();
+    mReshapeInvLayout = true;
+}
+
+void LLPanelMainInventory::onCombinationGallerySelectionChanged(const LLUUID& category_id)
+{
+}
+
+void LLPanelMainInventory::onCombinationInventorySelectionChanged(const std::deque<LLFolderViewItem*>& items, BOOL user_action)
+{
+    onSelectionChange(mCombinationInventoryPanel, items, user_action);
+}
+
+void LLPanelMainInventory::updatePanelVisibility()
+{
+    mDefaultViewPanel->setVisible(!mSingleFolderMode);
+    mCombinationViewPanel->setVisible(mSingleFolderMode);
+    mNavigationBtnsPanel->setVisible(mSingleFolderMode);
+    mViewModeBtn->setImageOverlay(mSingleFolderMode ? getString("default_mode_btn") : getString("single_folder_mode_btn"));
+    mViewModeBtn->setEnabled(mSingleFolderMode || (getAllItemsPanel() == getActivePanel()));
+    if (mSingleFolderMode)
+    {
+        if (isCombinationViewMode())
+        {
+            LLInventoryFilter& comb_inv_filter = mCombinationInventoryPanel->getFilter();
+            comb_inv_filter.setFilterThumbnails(LLInventoryFilter::FILTER_EXCLUDE_THUMBNAILS);
+            comb_inv_filter.markDefault();
+
+            LLInventoryFilter& comb_gallery_filter = mCombinationGalleryPanel->getFilter();
+            comb_gallery_filter.setFilterThumbnails(LLInventoryFilter::FILTER_ONLY_THUMBNAILS);
+            comb_gallery_filter.markDefault();
+
+            // visibility will be controled by updateCombinationVisibility()
+            mCombinationGalleryLayoutPanel->setVisible(true);
+            mCombinationGalleryPanel->setVisible(true);
+            mCombinationListLayoutPanel->setVisible(true);
+        }
+        else
+        {
+            LLInventoryFilter& comb_inv_filter = mCombinationInventoryPanel->getFilter();
+            comb_inv_filter.setFilterThumbnails(LLInventoryFilter::FILTER_INCLUDE_THUMBNAILS);
+            comb_inv_filter.markDefault();
+
+            LLInventoryFilter& comb_gallery_filter = mCombinationGalleryPanel->getFilter();
+            comb_gallery_filter.setFilterThumbnails(LLInventoryFilter::FILTER_INCLUDE_THUMBNAILS);
+            comb_gallery_filter.markDefault();
+
+            mCombinationLayoutStack->setPanelSpacing(0);
+            mCombinationGalleryLayoutPanel->setVisible(mSingleFolderMode && isGalleryViewMode());
+            mCombinationGalleryPanel->setVisible(mSingleFolderMode && isGalleryViewMode()); // to prevent or process updates
+            mCombinationListLayoutPanel->setVisible(mSingleFolderMode && isListViewMode());
+        }
+    }
+    else
+    {
+        mCombinationGalleryLayoutPanel->setVisible(false);
+        mCombinationGalleryPanel->setVisible(false); // to prevent updates
+        mCombinationListLayoutPanel->setVisible(false);
+    }
+}
+
+void LLPanelMainInventory::updateCombinationVisibility()
+{
+    if(mSingleFolderMode && isCombinationViewMode())
+    {
+        bool is_gallery_empty = !mCombinationGalleryPanel->hasVisibleItems();
+        bool show_inv_pane = mCombinationInventoryPanel->hasVisibleItems() || is_gallery_empty || mForceShowInvLayout;
+
+        const S32 DRAG_HANDLE_PADDING = 12; // for drag handle to not overlap gallery when both inventories are visible
+        mCombinationLayoutStack->setPanelSpacing(show_inv_pane ? DRAG_HANDLE_PADDING : 0);
+
+        mCombinationGalleryLayoutPanel->setVisible(!is_gallery_empty);
+        mCombinationListLayoutPanel->setVisible(show_inv_pane);
+        mCombinationInventoryPanel->getRootFolder()->setForceArrange(!show_inv_pane);
+        if(mCombinationInventoryPanel->hasVisibleItems())
+        {
+            mForceShowInvLayout = false;
+        }
+        if(is_gallery_empty)
+        {
+            mCombinationGalleryPanel->handleModifiedFilter();
+        }
+        
+        getActivePanel()->getRootFolder();
+
+        if (mReshapeInvLayout
+            && show_inv_pane
+            && (mCombinationGalleryPanel->hasVisibleItems() || mCombinationGalleryPanel->areViewsInitialized())
+            && mCombinationInventoryPanel->areViewsInitialized())
+        {
+            mReshapeInvLayout = false;
+
+            // force drop previous shape (because panel doesn't decrease shape properly)
+            LLRect list_latout = mCombinationListLayoutPanel->getRect();
+            list_latout.mTop = list_latout.mBottom; // min height is at 100, so it should snap to be bigger
+            mCombinationListLayoutPanel->setShape(list_latout, false);
+
+            LLRect inv_inner_rect = mCombinationInventoryPanel->getScrollableContainer()->getScrolledViewRect();
+            S32 inv_height = inv_inner_rect.getHeight()
+                + (mCombinationInventoryPanel->getScrollableContainer()->getBorderWidth() * 2)
+                + mCombinationInventoryPanel->getScrollableContainer()->getSize();
+            LLRect inner_galery_rect = mCombinationGalleryPanel->getScrollableContainer()->getScrolledViewRect();
+            S32 gallery_height = inner_galery_rect.getHeight()
+                + (mCombinationGalleryPanel->getScrollableContainer()->getBorderWidth() * 2)
+                + mCombinationGalleryPanel->getScrollableContainer()->getSize();
+            LLRect layout_rect = mCombinationViewPanel->getRect();
+
+            // by default make it take 1/3 of the panel
+            S32 list_default_height = layout_rect.getHeight() / 3;
+            // Don't set height from gallery_default_height - needs to account for a resizer in such case
+            S32 gallery_default_height = layout_rect.getHeight() - list_default_height;
+
+            if (inv_height > list_default_height
+                && gallery_height < gallery_default_height)
+            {
+                LLRect gallery_latout = mCombinationGalleryLayoutPanel->getRect();
+                gallery_latout.mTop = gallery_latout.mBottom + gallery_height;
+                mCombinationGalleryLayoutPanel->setShape(gallery_latout, true /*tell stack to account for new shape*/);
+            }
+            else if (inv_height < list_default_height
+                     && gallery_height > gallery_default_height)
+            {
+                LLRect list_latout = mCombinationListLayoutPanel->getRect();
+                list_latout.mTop = list_latout.mBottom + inv_height;
+                mCombinationListLayoutPanel->setShape(list_latout, true /*tell stack to account for new shape*/);
+            }
+            else
+            {
+                LLRect list_latout = mCombinationListLayoutPanel->getRect();
+                list_latout.mTop = list_latout.mBottom + list_default_height;
+                mCombinationListLayoutPanel->setShape(list_latout, true /*tell stack to account for new shape*/);
+            }
+        }
+    }
+
+    if (mSingleFolderMode
+        && !isGalleryViewMode()
+        && mCombInvUUIDNeedsRename.notNull()
+        && mCombinationInventoryPanel->areViewsInitialized())
+    {
+        mCombinationInventoryPanel->setSelectionByID(mCombInvUUIDNeedsRename, TRUE);
+        mCombinationInventoryPanel->getRootFolder()->scrollToShowSelection();
+        mCombinationInventoryPanel->getRootFolder()->setNeedsAutoRename(TRUE);
+        mCombInvUUIDNeedsRename.setNull();
+    }
+}
+
+void LLPanelMainInventory::updateNavButtons()
+{
+    if(isListViewMode())
+    {
+        mBackBtn->setEnabled(mCombinationInventoryPanel->isBackwardAvailable());
+        mForwardBtn->setEnabled(mCombinationInventoryPanel->isForwardAvailable());
+    }
+    if(isGalleryViewMode())
+    {
+        mBackBtn->setEnabled(mCombinationGalleryPanel->isBackwardAvailable());
+        mForwardBtn->setEnabled(mCombinationGalleryPanel->isForwardAvailable());
+    }
+    if(isCombinationViewMode())
+    {
+        mBackBtn->setEnabled(mCombinationInventoryPanel->isBackwardAvailable());
+        mForwardBtn->setEnabled(mCombinationInventoryPanel->isForwardAvailable());
+    }
+
+    const LLViewerInventoryCategory* cat = gInventory.getCategory(getCurrentSFVRoot());
+    bool up_enabled = (cat && cat->getParentUUID().notNull());
+    mUpBtn->setEnabled(up_enabled);
+}
+
+LLSidepanelInventory* LLPanelMainInventory::getParentSidepanelInventory()
+{
+    LLFloaterSidePanelContainer* inventory_container = dynamic_cast<LLFloaterSidePanelContainer*>(gFloaterView->getParentFloater(this));
+    if(inventory_container)
+    {
+        return dynamic_cast<LLSidepanelInventory*>(inventory_container->findChild<LLPanel>("main_panel", true));
+    }
+    return NULL;
+}
+
+void LLPanelMainInventory::setViewMode(EViewModeType mode)
+{
+    if(mode != mViewMode)
+    {
+        std::list<LLUUID> forward_history;
+        std::list<LLUUID> backward_history;
+        U32 sort_order = 0;
+        switch(mViewMode)
+        {
+            case MODE_LIST:
+                forward_history = mCombinationInventoryPanel->getNavForwardList();
+                backward_history = mCombinationInventoryPanel->getNavBackwardList();
+                sort_order = mCombinationInventoryPanel->getSortOrder();
+                break;
+            case MODE_GALLERY:
+                forward_history = mCombinationGalleryPanel->getNavForwardList();
+                backward_history = mCombinationGalleryPanel->getNavBackwardList();
+                sort_order = mCombinationGalleryPanel->getSortOrder();
+                break;
+            case MODE_COMBINATION:
+                forward_history = mCombinationInventoryPanel->getNavForwardList();
+                backward_history = mCombinationInventoryPanel->getNavBackwardList();
+                mCombinationInventoryPanel->getRootFolder()->setForceArrange(false);
+                sort_order = mCombinationInventoryPanel->getSortOrder();
+                break;
+        }
+            
+        LLUUID cur_root = getCurrentSFVRoot();
+        mViewMode = mode;
+
+        updatePanelVisibility();
+
+        if(isListViewMode())
+        {
+            mCombinationInventoryPanel->changeFolderRoot(cur_root);
+            mCombinationInventoryPanel->setNavForwardList(forward_history);
+            mCombinationInventoryPanel->setNavBackwardList(backward_history);
+            mCombinationInventoryPanel->setSortOrder(sort_order);
+        }
+        if(isGalleryViewMode())
+        {
+            mCombinationGalleryPanel->setRootFolder(cur_root);
+            mCombinationGalleryPanel->setNavForwardList(forward_history);
+            mCombinationGalleryPanel->setNavBackwardList(backward_history);
+            mCombinationGalleryPanel->setSortOrder(sort_order, true);
+        }
+        if(isCombinationViewMode())
+        {
+            mCombinationInventoryPanel->changeFolderRoot(cur_root);
+            mCombinationGalleryPanel->setRootFolder(cur_root);
+            mCombinationInventoryPanel->setNavForwardList(forward_history);
+            mCombinationInventoryPanel->setNavBackwardList(backward_history);
+            mCombinationGalleryPanel->setNavForwardList(forward_history);
+            mCombinationGalleryPanel->setNavBackwardList(backward_history);
+            mCombinationInventoryPanel->setSortOrder(sort_order);
+            mCombinationGalleryPanel->setSortOrder(sort_order, true);
+        }
+
+        updateNavButtons();
+
+        onFilterSelected();
+        if((isListViewMode() && (mActivePanel->getFilterSubString() != mFilterSubString)) ||
+           (isGalleryViewMode() && (mCombinationGalleryPanel->getFilterSubString() != mFilterSubString)))
+        {
+            onFilterEdit(mFilterSubString);
+        }
+    }
+}
+
+std::string LLPanelMainInventory::getLocalizedRootName()
+{
+    return mSingleFolderMode ? get_localized_folder_name(getCurrentSFVRoot()) : "";
+}
+
+LLUUID LLPanelMainInventory::getCurrentSFVRoot()
+{
+    if(isListViewMode())
+    {
+        return mCombinationInventoryPanel->getSingleFolderRoot();
+    }
+    if(isGalleryViewMode())
+    {
+        return mCombinationGalleryPanel->getRootFolder();
+    }
+    if(isCombinationViewMode())
+    {
+        return mCombinationInventoryPanel->getSingleFolderRoot();
+    }
+    return LLUUID::null;
+}
+
+LLInventoryFilter& LLPanelMainInventory::getCurrentFilter()
+{
+    if(mSingleFolderMode && isGalleryViewMode())
+    {
+        return mCombinationGalleryPanel->getFilter();
+    }
+    else
+    {
+        return mActivePanel->getFilter();
+    }
+}
+
+void LLPanelMainInventory::setGallerySelection(const LLUUID& item_id, bool new_window)
+{
+    if(mSingleFolderMode && isGalleryViewMode())
+    {
+        mCombinationGalleryPanel->changeItemSelection(item_id, true);
+    }
+    else if(mSingleFolderMode && isCombinationViewMode())
+    {
+        if(mCombinationGalleryPanel->getFilter().checkAgainstFilterThumbnails(item_id))
+        {
+            mCombinationGalleryPanel->changeItemSelection(item_id, false);
+            scrollToGallerySelection();
+        }
+        else
+        {
+            mCombinationInventoryPanel->setSelection(item_id, true);
+            scrollToInvPanelSelection();
+        }
+    }
+    else if (mSingleFolderMode && isListViewMode())
+    {
+        mCombinationInventoryPanel->setSelection(item_id, true);
+    }
+}
+
+void LLPanelMainInventory::scrollToGallerySelection()
+{
+    mCombinationGalleryPanel->scrollToShowItem(mCombinationGalleryPanel->getFirstSelectedItemID());
+}
+
+void LLPanelMainInventory::scrollToInvPanelSelection()
+{
+    mCombinationInventoryPanel->getRootFolder()->scrollToShowSelection();
+}
+
 // List Commands                                                              //
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h
index 3b411f4e028d174d5d674bb3c20651b5b2f52fa5..6fd6b38c80b7483925c796e9b25238340bd0e879 100644
--- a/indra/newview/llpanelmaininventory.h
+++ b/indra/newview/llpanelmaininventory.h
@@ -30,6 +30,7 @@
 
 #include "llpanel.h"
 #include "llinventoryobserver.h"
+#include "llinventorypanel.h"
 #include "lldndbutton.h"
 
 #include "llfolderview.h"
@@ -37,14 +38,17 @@
 class LLComboBox;
 class LLFolderViewItem;
 class LLInventoryPanel;
+class LLInventoryGallery;
 class LLSaveFolderState;
 class LLFilterEditor;
 class LLTabContainer;
 class LLFloaterInventoryFinder;
 class LLMenuButton;
 class LLMenuGL;
+class LLSidepanelInventory;
 class LLToggleableMenu;
 class LLFloater;
+class LLFloaterSidePanelContainer;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLPanelMainInventory
@@ -63,6 +67,13 @@ class LLPanelMainInventory : public LLPanel, LLInventoryObserver
 
 	BOOL postBuild();
 
+    enum EViewModeType
+    {
+        MODE_LIST,
+        MODE_GALLERY,
+        MODE_COMBINATION
+    };
+
 	virtual BOOL handleKeyHere(KEY key, MASK mask);
 
 	// Inherited functionality
@@ -80,6 +91,7 @@ class LLPanelMainInventory : public LLPanel, LLInventoryObserver
 	LLInventoryPanel* getAllItemsPanel();
 	void selectAllItemsPanel();
 	const LLInventoryPanel* getActivePanel() const { return mActivePanel; }
+    void setActivePanel();
 
 	bool isRecentItemsPanelSelected();
 
@@ -91,13 +103,40 @@ class LLPanelMainInventory : public LLPanel, LLInventoryObserver
 
 	void setFocusFilterEditor();
 
-	static void newWindow();
+	static LLFloaterSidePanelContainer* newWindow();
+    static void newFolderWindow(LLUUID folder_id = LLUUID(), LLUUID item_to_select = LLUUID());
 
 	void toggleFindOptions();
 
     void resetFilters();
     void resetAllItemsFilters();
 
+    void findLinks(const LLUUID& item_id, const std::string& item_name);
+
+    void onViewModeClick();
+    void toggleViewMode();
+    void initSingleFolderRoot(const LLUUID& start_folder_id = LLUUID::null);
+    void initInventoryViews();
+    void onUpFolderClicked();
+    void onBackFolderClicked();
+    void onForwardFolderClicked();
+    void setSingleFolderViewRoot(const LLUUID& folder_id, bool clear_nav_history = true);
+    void setGallerySelection(const LLUUID& item_id, bool new_window = false);
+    LLUUID getSingleFolderViewRoot();
+    bool isSingleFolderMode() { return mSingleFolderMode; }
+
+    void scrollToGallerySelection();
+    void scrollToInvPanelSelection();
+
+    void setViewMode(EViewModeType mode);
+    bool isListViewMode() { return (mViewMode == MODE_LIST); }
+    bool isGalleryViewMode() { return (mViewMode == MODE_GALLERY); }
+    bool isCombinationViewMode() { return (mViewMode == MODE_COMBINATION); }
+    LLUUID getCurrentSFVRoot();
+    std::string getLocalizedRootName();
+
+    LLInventoryFilter& getCurrentFilter();
+
 protected:
 	//
 	// Misc functions
@@ -128,9 +167,15 @@ class LLPanelMainInventory : public LLPanel, LLInventoryObserver
 	bool isSaveTextureEnabled(const LLSD& userdata);
 	void updateItemcountText();
 
+    void updatePanelVisibility();
+    void updateCombinationVisibility();
+
 	void onFocusReceived();
 	void onSelectSearchType();
 	void updateSearchTypeCombo();
+    void setSearchType(LLInventoryFilter::ESearchType type);
+
+    LLSidepanelInventory* getParentSidepanelInventory();
 
 private:
 	LLFloaterInventoryFinder* getFinder();
@@ -151,7 +196,26 @@ class LLPanelMainInventory : public LLPanel, LLInventoryObserver
 	std::string					mCategoryCountString;
 	LLComboBox*					mSearchTypeCombo;
 
+    LLButton* mBackBtn;
+    LLButton* mForwardBtn;
+    LLButton* mUpBtn;
+    LLButton* mViewModeBtn;
+    LLLayoutPanel* mNavigationBtnsPanel;
+
+    LLPanel* mDefaultViewPanel;
+    LLPanel* mCombinationViewPanel;
 
+    bool mSingleFolderMode;
+    EViewModeType mViewMode;
+
+    LLInventorySingleFolderPanel* mCombinationInventoryPanel;
+    LLInventoryGallery* mCombinationGalleryPanel;
+    LLPanel* mCombinationGalleryLayoutPanel;
+    LLLayoutPanel* mCombinationListLayoutPanel;
+    LLLayoutStack* mCombinationLayoutStack;
+
+    boost::signals2::connection mListViewRootUpdatedConnection;
+    boost::signals2::connection mGalleryRootUpdatedConnection;
 
 	//////////////////////////////////////////////////////////////////////////////////
 	// List Commands                                                                //
@@ -160,27 +224,38 @@ class LLPanelMainInventory : public LLPanel, LLInventoryObserver
 	void updateListCommands();
 	void onAddButtonClick();
 	void showActionMenu(LLMenuGL* menu, std::string spawning_view_name);
-	void onTrashButtonClick();
 	void onClipboardAction(const LLSD& userdata);
 	BOOL isActionEnabled(const LLSD& command_name);
 	BOOL isActionChecked(const LLSD& userdata);
 	void onCustomAction(const LLSD& command_name);
-	bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept);
+    bool isActionVisible(const LLSD& userdata);
     static bool hasSettingsInventory();
     static bool hasMaterialsInventory();
+    void updateTitle();
+    void updateNavButtons();
+    
+    void onCombinationRootChanged(bool gallery_clicked);
+    void onCombinationGallerySelectionChanged(const LLUUID& category_id);
+    void onCombinationInventorySelectionChanged(const std::deque<LLFolderViewItem*>& items, BOOL user_action);
 	/**
 	 * Set upload cost in "Upload" sub menu.
 	 */
 	void setUploadCostIfNeeded();
+    void disableAddIfNeeded();
 private:
-	LLDragAndDropButton*		mTrashButton;
 	LLToggleableMenu*			mMenuGearDefault;
+    LLToggleableMenu*           mMenuViewDefault;
 	LLToggleableMenu*			mMenuVisibility;
 	LLMenuButton*				mGearMenuButton;
+    LLMenuButton*               mViewMenuButton;
 	LLMenuButton*				mVisibilityMenuButton;
 	LLHandle<LLView>			mMenuAddHandle;
 
 	bool						mNeedUploadCost;
+
+    bool                        mForceShowInvLayout;
+    bool                        mReshapeInvLayout;
+    LLUUID                      mCombInvUUIDNeedsRename;
 	// List Commands                                                              //
 	////////////////////////////////////////////////////////////////////////////////
 };
diff --git a/indra/newview/llpanelmarketplaceinbox.cpp b/indra/newview/llpanelmarketplaceinbox.cpp
index 8a86f4f63d2f43931c9267affb2c978594d7e9d1..3638ee14fcff95d837c6b9420cc8d2b467ef5999 100644
--- a/indra/newview/llpanelmarketplaceinbox.cpp
+++ b/indra/newview/llpanelmarketplaceinbox.cpp
@@ -75,9 +75,6 @@ BOOL LLPanelMarketplaceInbox::postBuild()
 
 void LLPanelMarketplaceInbox::onSelectionChange()
 {
-	LLSidepanelInventory* sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
-		
-	sidepanel_inventory->updateVerbs();
 }
 
 
diff --git a/indra/newview/llpanelmarketplaceinboxinventory.cpp b/indra/newview/llpanelmarketplaceinboxinventory.cpp
index 8701f8bc260b26f752c07114025ba69eecb0bb3b..a5d9f8761812314e03d9515a0c58cb4984c0b9b4 100644
--- a/indra/newview/llpanelmarketplaceinboxinventory.cpp
+++ b/indra/newview/llpanelmarketplaceinboxinventory.cpp
@@ -62,10 +62,13 @@ LLInboxInventoryPanel::LLInboxInventoryPanel(const LLInboxInventoryPanel::Params
 :	LLInventoryPanel(p)
 {
 	LLInboxNewItemsStorage::getInstance()->load();
+    LLInboxNewItemsStorage::getInstance()->addInboxPanel(this);
 }
 
 LLInboxInventoryPanel::~LLInboxInventoryPanel()
-{}
+{
+    LLInboxNewItemsStorage::getInstance()->removeInboxPanel(this);
+}
 
 void LLInboxInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)
 {
@@ -108,6 +111,21 @@ LLFolderViewItem * LLInboxInventoryPanel::createFolderViewItem(LLInvFVBridge * b
 	return LLUICtrlFactory::create<LLInboxFolderViewItem>(params);
 }
 
+void LLInboxInventoryPanel::onRemoveItemFreshness(const LLUUID& item_id)
+{
+    LLInboxFolderViewFolder* inbox_folder_view = dynamic_cast<LLInboxFolderViewFolder*>(getFolderByID(item_id));
+    if(inbox_folder_view)
+    {
+        inbox_folder_view->setFresh(false);
+    }
+
+    LLInboxFolderViewItem* inbox_item_view = dynamic_cast<LLInboxFolderViewItem*>(getItemByID(item_id));
+    if(inbox_item_view)
+    {
+        inbox_item_view->setFresh(false);
+    }
+}
+
 //
 // LLInboxFolderViewFolder Implementation
 //
@@ -340,4 +358,18 @@ void LLInboxNewItemsStorage::load()
 		}
 	}
 }
+
+void LLInboxNewItemsStorage::removeItem(const LLUUID& id)
+{
+    mNewItemsIDs.erase(id);
+
+    //notify inbox panels
+    for (auto inbox : mInboxPanels)
+    {
+        if(inbox)
+        {
+            inbox->onRemoveItemFreshness(id);
+        }
+    }
+}
 // eof
diff --git a/indra/newview/llpanelmarketplaceinboxinventory.h b/indra/newview/llpanelmarketplaceinboxinventory.h
index 3e508e801bab77fce0baf8a090e752b54d5200d8..9eef5f209c9154f1ea36858f33edfe0deb90fa67 100644
--- a/indra/newview/llpanelmarketplaceinboxinventory.h
+++ b/indra/newview/llpanelmarketplaceinboxinventory.h
@@ -49,6 +49,8 @@ class LLInboxInventoryPanel : public LLInventoryPanel
 	void initFromParams(const LLInventoryPanel::Params&);
 	LLFolderViewFolder*	createFolderViewFolder(LLInvFVBridge * bridge, bool allow_drop);
 	LLFolderViewItem * createFolderViewItem(LLInvFVBridge * bridge);
+
+    void onRemoveItemFreshness(const LLUUID& item_id);
 };
 
 
@@ -77,6 +79,7 @@ class LLInboxFolderViewFolder : public LLFolderViewFolder, public LLBadgeOwner
 	void deFreshify();
 
 	bool isFresh() const { return mFresh; }
+    void setFresh(bool is_fresh)  { mFresh = is_fresh; }
 	
 protected:
 	bool mFresh;
@@ -108,6 +111,7 @@ class LLInboxFolderViewItem : public LLFolderViewItem, public LLBadgeOwner
 	void deFreshify();
 
 	bool isFresh() const { return mFresh; }
+    void setFresh(bool is_fresh)  { mFresh = is_fresh; }
 
 protected:
 	bool mFresh;
@@ -125,11 +129,16 @@ class LLInboxNewItemsStorage : public LLSingleton<LLInboxNewItemsStorage>
 	void load();
 	
 	void addFreshItem(const LLUUID& id) { mNewItemsIDs.insert(id); }
-	void removeItem(const LLUUID& id) { mNewItemsIDs.erase(id); }
+    void removeItem(const LLUUID& id);
 	bool isItemFresh(const LLUUID& id) { return (mNewItemsIDs.find(id) != mNewItemsIDs.end()); }
 
+    void addInboxPanel(LLInboxInventoryPanel* inbox) { mInboxPanels.insert(inbox); }
+    void removeInboxPanel(LLInboxInventoryPanel* inbox) { mInboxPanels.erase(inbox); }
+
 private:
 	std::set<LLUUID> mNewItemsIDs;
+
+    std::set<LLInboxInventoryPanel*> mInboxPanels;
 };
 
 #endif //LL_INBOXINVENTORYPANEL_H
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index af1d0a544a58f7386026cc77c2015886ca0282c3..554dd74ccfe16305d1732b5252307dc12fd45497 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -122,6 +122,7 @@ class LLTaskInvFVBridge : public LLFolderViewModelItemInventory
 	virtual PermissionMask getPermissionMask() const { return PERM_NONE; }
 	/*virtual*/ LLFolderType::EType getPreferredType() const { return LLFolderType::FT_NONE; }
 	virtual const LLUUID& getUUID() const { return mUUID; }
+    virtual const LLUUID& getThumbnailUUID() const { return LLUUID::null;}
 	virtual time_t getCreationDate() const;
 	virtual void setCreationDate(time_t creation_date_utc);
 
@@ -130,6 +131,7 @@ class LLTaskInvFVBridge : public LLFolderViewModelItemInventory
 	virtual BOOL canOpenItem() const { return FALSE; }
 	virtual void closeItem() {}
 	virtual void selectItem() {}
+    virtual void navigateToFolder(bool new_window = false, bool change_mode = false) {}
 	virtual BOOL isItemRenameable() const;
 	virtual BOOL renameItem(const std::string& new_name);
 	virtual BOOL isItemMovable() const;
@@ -638,8 +640,7 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 // [/RLVa:KB]
 	}
 	items.push_back(std::string("Task Properties"));
-	// If multiple items are selected, only disable properties if we're not showing them in a multi-floater
-	if ( ((flags & FIRST_SELECTED_ITEM) == 0) && (!gSavedSettings.getBOOL("ShowPropertiesFloaters")) )
+	if ((flags & FIRST_SELECTED_ITEM) == 0)
 	{
 		disabled_items.push_back(std::string("Task Properties"));
 	}
@@ -1663,21 +1664,6 @@ void LLPanelObjectInventory::inventoryChanged(LLViewerObject* object,
 	{
 		mInventoryNeedsUpdate = TRUE;
 	}
-
-	// refresh any properties floaters that are hanging around.
-	if(inventory)
-	{
-		for (LLInventoryObject::object_list_t::const_iterator iter = inventory->begin();
-			 iter != inventory->end(); )
-		{
-			LLInventoryObject* item = *iter++;
-			LLFloaterProperties* floater = LLFloaterReg::findTypedInstance<LLFloaterProperties>("properties", item->getUUID());
-			if(floater)
-			{
-				floater->refresh();
-			}
-		}
-	}
 }
 
 void LLPanelObjectInventory::updateInventory()
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index e1c7aaf3107e01d197d9c208fff067a542fc79da..419a5919bde7b1761b181a8371de908c32ce8fc8 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -714,8 +714,12 @@ void LLPanelOutfitEdit::onFolderViewFilterCommitted(LLUICtrl* ctrl)
 	LLOpenFoldersWithSelection opener;
 	mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(opener);
 	mInventoryItemsPanel->getRootFolder()->scrollToShowSelection();
-	
-	LLInventoryModelBackgroundFetch::instance().start();
+
+    if (!LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted())
+    {
+        llassert(false); // this should have been done on startup
+        LLInventoryModelBackgroundFetch::instance().start();
+    }
 }
 
 void LLPanelOutfitEdit::onListViewFilterCommitted(LLUICtrl* ctrl)
@@ -752,8 +756,12 @@ void LLPanelOutfitEdit::onSearchEdit(const std::string& string)
 		mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(opener);
 		mInventoryItemsPanel->getRootFolder()->scrollToShowSelection();
 	}
-	
-	LLInventoryModelBackgroundFetch::instance().start();
+
+    if (!LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted())
+    {
+        llassert(false); // this should have been done on startup
+        LLInventoryModelBackgroundFetch::instance().start();
+    }
 	
 	if (mInventoryItemsPanel->getFilterSubString().empty() && mSearchString.empty())
 	{
diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp
index d439dadfd706c54902bda80dcb046870a5a0a008..f824682c04ea3eeb5ac043207937286c46349a6f 100644
--- a/indra/newview/llpaneloutfitsinventory.cpp
+++ b/indra/newview/llpaneloutfitsinventory.cpp
@@ -96,7 +96,7 @@ BOOL LLPanelOutfitsInventory::postBuild()
 	// ( This is only necessary if we want to show a warning if a user deletes an item that has a
 	// a link in an outfit, see "ConfirmItemDeleteHasLinks". )
 
-	const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+	const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
 	if (outfits_cat.notNull())
 	{
 		LLInventoryModelBackgroundFetch::instance().start(outfits_cat);
@@ -181,7 +181,11 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string)
 		mActivePanel->setFilterSubString(LLStringUtil::null);
 	}
 
-	LLInventoryModelBackgroundFetch::instance().start();
+    if (!LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted())
+    {
+        llassert(false); // this should have been done on startup
+        LLInventoryModelBackgroundFetch::instance().start();
+    }
 
 	if (mActivePanel->getFilterSubString().empty() && string.empty())
 	{
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index 02b21c1d9c5d3ced76f760c3410fb8a1f2e4963c..44dce1ad568a10d3de863beb97dabd7d75c531d4 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -72,6 +72,7 @@
 #include "llpanelblockedlist.h"
 #include "llpanelprofileclassifieds.h"
 #include "llpanelprofilepicks.h"
+#include "llthumbnailctrl.h"
 #include "lltrans.h"
 #include "llviewercontrol.h"
 #include "llviewermenu.h" //is_agent_mappable
@@ -616,7 +617,7 @@ BOOL LLPanelProfileSecondLife::postBuild()
 {
     mGroupList              = getChild<LLGroupList>("group_list");
     mShowInSearchCombo      = getChild<LLComboBox>("show_in_search");
-    mSecondLifePic          = getChild<LLIconCtrl>("2nd_life_pic");
+    mSecondLifePic          = getChild<LLThumbnailCtrl>("2nd_life_pic");
     mSecondLifePicLayout    = getChild<LLPanel>("image_panel");
     mDescriptionEdit        = getChild<LLTextEditor>("sl_description_edit");
     mAgentActionMenuButton  = getChild<LLMenuButton>("agent_actions_menu");
@@ -1593,30 +1594,16 @@ void LLPanelProfileSecondLife::onShowTexturePicker()
 
             mFloaterTexturePickerHandle = texture_floaterp->getHandle();
 
-            texture_floaterp->setOnFloaterCommitCallback([this](LLTextureCtrl::ETexturePickOp op, LLUUID id)
+            texture_floaterp->setOnFloaterCommitCallback([this](LLTextureCtrl::ETexturePickOp op, LLPickerSource source, const LLUUID& asset_id, const LLUUID&)
             {
                 if (op == LLTextureCtrl::TEXTURE_SELECT)
                 {
-                    LLUUID image_asset_id;
-                    LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterTexturePickerHandle.get();
-                    if (floaterp)
-                    {
-                        if (id.notNull())
-                        {
-                            image_asset_id = id;
-                        }
-                        else
-                        {
-                            image_asset_id = floaterp->getAssetID();
-                        }
-                    }
-
-                    onCommitProfileImage(image_asset_id);
+                    onCommitProfileImage(asset_id);
                 }
             });
             texture_floaterp->setLocalTextureEnabled(FALSE);
             texture_floaterp->setBakeTextureEnabled(FALSE);
-            texture_floaterp->setCanApply(false, true);
+            texture_floaterp->setCanApply(false, true, false);
 
             parent_floater->addDependentFloater(mFloaterTexturePickerHandle);
 
@@ -1829,7 +1816,7 @@ LLPanelProfileFirstLife::~LLPanelProfileFirstLife()
 BOOL LLPanelProfileFirstLife::postBuild()
 {
     mDescriptionEdit = getChild<LLTextEditor>("fl_description_edit");
-    mPicture = getChild<LLIconCtrl>("real_world_pic");
+    mPicture = getChild<LLThumbnailCtrl>("real_world_pic");
 
     mUploadPhoto = getChild<LLButton>("fl_upload_image");
     mChangePhoto = getChild<LLButton>("fl_change_image");
@@ -1933,29 +1920,15 @@ void LLPanelProfileFirstLife::onChangePhoto()
 
             mFloaterTexturePickerHandle = texture_floaterp->getHandle();
 
-            texture_floaterp->setOnFloaterCommitCallback([this](LLTextureCtrl::ETexturePickOp op, LLUUID id)
+            texture_floaterp->setOnFloaterCommitCallback([this](LLTextureCtrl::ETexturePickOp op, LLPickerSource source, const LLUUID& asset_id, const LLUUID&)
             {
                 if (op == LLTextureCtrl::TEXTURE_SELECT)
                 {
-                    LLUUID image_asset_id;
-                    LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterTexturePickerHandle.get();
-                    if (floaterp)
-                    {
-                        if (id.notNull())
-                        {
-                            image_asset_id = id;
-                        }
-                        else
-                        {
-                            image_asset_id = floaterp->getAssetID();
-                        }
-                    }
-
-                    onCommitPhoto(image_asset_id);
+                    onCommitPhoto(asset_id);
                 }
             });
             texture_floaterp->setLocalTextureEnabled(FALSE);
-            texture_floaterp->setCanApply(false, true);
+            texture_floaterp->setCanApply(false, true, false);
 
             parent_floater->addDependentFloater(mFloaterTexturePickerHandle);
 
diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h
index a3e7be9cc4c2cf83694235fa633b400f5df7013b..5a2edd0715d0bacf07d4e91d97d980db3e69ded6 100644
--- a/indra/newview/llpanelprofile.h
+++ b/indra/newview/llpanelprofile.h
@@ -59,6 +59,7 @@ class LLTextBase;
 class LLMenuButton;
 class LLLineEditor;
 class LLTextEditor;
+class LLThumbnailCtrl;
 class LLPanelProfileClassifieds;
 class LLPanelProfilePicks;
 class LLViewerFetchedTexture;
@@ -193,7 +194,7 @@ class LLPanelProfileSecondLife
 
 	LLGroupList*		mGroupList;
     LLComboBox*			mShowInSearchCombo;
-    LLIconCtrl*			mSecondLifePic;
+    LLThumbnailCtrl*	mSecondLifePic;
 	LLPanel*			mSecondLifePicLayout;
     LLTextEditor*		mDescriptionEdit;
     LLMenuButton*		mAgentActionMenuButton;
@@ -303,7 +304,7 @@ class LLPanelProfileFirstLife
     void onDiscardDescriptionChanges();
 
 	LLTextEditor*	mDescriptionEdit;
-    LLIconCtrl*		mPicture;
+    LLThumbnailCtrl* mPicture;
     LLButton* mUploadPhoto;
     LLButton* mChangePhoto;
     LLButton* mRemovePhoto;
diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp
index 042ff74b6ad16714899449f6f9dab2611b9f9d2a..6bb106fb43942e74bdfbb9fc85cbaefb704b3a0d 100644
--- a/indra/newview/llpanelwearing.cpp
+++ b/indra/newview/llpanelwearing.cpp
@@ -40,6 +40,7 @@
 #include "llinventorymodel.h"
 #include "llinventoryobserver.h"
 #include "llmenubutton.h"
+#include "lloutfitobserver.h"
 #include "llscrolllistctrl.h"
 #include "llviewermenu.h"
 #include "llviewerregion.h"
@@ -242,8 +243,6 @@ LLPanelWearing::LLPanelWearing()
 	,	mIsInitialized(false)
 	,	mAttachmentsChangedConnection()
 {
-	mCategoriesObserver = new LLInventoryCategoriesObserver();
-
 	mGearMenu = new LLWearingGearMenu(this);
 	mContextMenu = new LLWearingContextMenu();
 	mAttachmentsMenu = new LLTempAttachmentsContextMenu(this);
@@ -255,12 +254,6 @@ LLPanelWearing::~LLPanelWearing()
 	delete mContextMenu;
 	delete mAttachmentsMenu;
 
-	if (gInventory.containsObserver(mCategoriesObserver))
-	{
-		gInventory.removeObserver(mCategoriesObserver);
-	}
-	delete mCategoriesObserver;
-
 	if (mAttachmentsChangedConnection.connected())
 	{
 		mAttachmentsChangedConnection.disconnect();
@@ -307,10 +300,8 @@ void LLPanelWearing::onOpen(const LLSD& /*info*/)
 		if (!category)
 			return;
 
-		gInventory.addObserver(mCategoriesObserver);
-
 		// Start observing changes in Current Outfit category.
-		mCategoriesObserver->addCategory(cof, boost::bind(&LLWearableItemsList::updateList, mCOFItemsList, cof));
+        LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLWearableItemsList::updateList, mCOFItemsList, cof));
 
 		// Fetch Current Outfit contents and refresh the list to display
 		// initially fetched items. If not all items are fetched now
diff --git a/indra/newview/llpanelwearing.h b/indra/newview/llpanelwearing.h
index e6765dc18f6b46af5ab740875e970898e6ded477..880d5fb7d6eb2f36466e0881bb553dbecfeba340 100644
--- a/indra/newview/llpanelwearing.h
+++ b/indra/newview/llpanelwearing.h
@@ -93,7 +93,6 @@ class LLPanelWearing : public LLPanelAppearanceTab
 
 	void getAttachmentLimitsCoro(std::string url);
 
-	LLInventoryCategoriesObserver* 	mCategoriesObserver;
 	LLWearableItemsList* 			mCOFItemsList;
 	LLScrollListCtrl*				mTempItemsList;
 	LLWearingGearMenu*				mGearMenu;
diff --git a/indra/newview/llprofileimagepicker.cpp b/indra/newview/llprofileimagepicker.cpp
index 769b3680dba007eb886c9d8f5cb12adc8e3516ac..eb40cdcc105fa6c59264acf01ec7cb12e4fce190 100644
--- a/indra/newview/llprofileimagepicker.cpp
+++ b/indra/newview/llprofileimagepicker.cpp
@@ -29,6 +29,7 @@
 
 #include "llagent.h"
 #include "llloadingindicator.h"
+#include "llnotificationsutil.h"
 #include "llpanel.h"
 #include "llviewertexturelist.h"
 
@@ -74,7 +75,9 @@ void LLProfileImagePicker::notify(const std::vector<std::string>& filenames)
     const S32 MAX_DIM = 256;
     if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, MAX_DIM))
     {
-        //todo: image not supported notification
+        LLSD notif_args;
+        notif_args["REASON"] = LLImage::getLastError().c_str();
+        LLNotificationsUtil::add("CannotUploadTexture", notif_args);
         LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", failed to open image" << LL_ENDL;
         return;
     }
@@ -82,6 +85,9 @@ void LLProfileImagePicker::notify(const std::vector<std::string>& filenames)
     std::string cap_url = gAgent.getRegionCapability(PROFILE_IMAGE_UPLOAD_CAP);
     if (cap_url.empty())
     {
+        LLSD args;
+        args["CAPABILITY"] = std::string(PROFILE_IMAGE_UPLOAD_CAP);
+        LLNotificationsUtil::add("RegionCapabilityRequestError", args);
         LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", no cap found" << LL_ENDL;
         return;
     }
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index f25fa0bb74d8c85d02601bf22a7d39d41e954a3a..9e95f57b309299c3254f305c0b5fbea2c39afb74 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -57,7 +57,6 @@
 #include "llviewerwindow.h"
 #include "lldrawable.h"
 #include "llfloaterinspect.h"
-#include "llfloaterproperties.h"
 #include "llfloaterreporter.h"
 #include "llfloaterreg.h"
 #include "llfloatertools.h"
@@ -7070,8 +7069,6 @@ void dialog_refresh_all()
 		gMenuAttachmentOther->arrange();
 	}
 
-	LLFloaterProperties::dirtyAll();
-
 	LLFloaterInspect* inspect_instance = LLFloaterReg::findTypedInstance<LLFloaterInspect>("inspect");
 	if(inspect_instance)
 	{
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index b7e84c121657d0f7aa67f918de2df7270b643c3a..7a57a4f6816a392c05f144544e0c95de2fe3de9d 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -99,6 +99,20 @@ namespace
 
 
 //=========================================================================
+void LLSettingsVOBase::createNewInventoryItem(LLSettingsType::type_e stype, const LLUUID& parent_id, std::function<void(const LLUUID&)> created_cb)
+{
+    inventory_result_fn cb = NULL;
+
+    if (created_cb != NULL)
+    {
+        cb = [created_cb](LLUUID asset_id, LLUUID inventory_id, LLUUID object_id, LLSD results)
+        {
+            created_cb(inventory_id);
+        };
+    }
+    createNewInventoryItem(stype, parent_id, cb);
+}
+
 void LLSettingsVOBase::createNewInventoryItem(LLSettingsType::type_e stype, const LLUUID &parent_id, inventory_result_fn callback)
 {
     LLTransactionID tid;
diff --git a/indra/newview/llsettingsvo.h b/indra/newview/llsettingsvo.h
index e6bac012aa334a445f796d89701eab96b60fe0b1..1fb3005950e02642643b4dbab0e4d44ea3a2c7e2 100644
--- a/indra/newview/llsettingsvo.h
+++ b/indra/newview/llsettingsvo.h
@@ -49,6 +49,7 @@ class LLSettingsVOBase : public LLSettingsBase
     typedef std::function<void(LLInventoryItem *inv_item, LLSettingsBase::ptr_t settings, S32 status, LLExtStat extstat)> inventory_download_fn;
     typedef std::function<void(LLUUID asset_id, LLUUID inventory_id, LLUUID object_id, LLSD results)>           inventory_result_fn;
 
+    static void     createNewInventoryItem(LLSettingsType::type_e stype, const LLUUID& parent_id, std::function<void(const LLUUID&)> created_cb);
     static void     createNewInventoryItem(LLSettingsType::type_e stype, const LLUUID &parent_id, inventory_result_fn callback = inventory_result_fn());
     static void     createInventoryItem(const LLSettingsBase::ptr_t &settings, const LLUUID &parent_id, std::string settings_name, inventory_result_fn callback = inventory_result_fn());
     static void     createInventoryItem(const LLSettingsBase::ptr_t &settings, U32 next_owner_perm, const LLUUID &parent_id, std::string settings_name, inventory_result_fn callback = inventory_result_fn());
diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp
index 833935564a7306964fc67568215148528dc8c64f..aa225fa0ec32432fe08e874d653e52bdfa19574e 100644
--- a/indra/newview/llsidepanelinventory.cpp
+++ b/indra/newview/llsidepanelinventory.cpp
@@ -73,6 +73,8 @@ static const char * const INBOX_LAYOUT_PANEL_NAME = "inbox_layout_panel";
 static const char * const INVENTORY_LAYOUT_STACK_NAME = "inventory_layout_stack";
 static const char * const MARKETPLACE_INBOX_PANEL = "marketplace_inbox";
 
+static bool sLoginCompleted = false;
+
 //
 // Helpers
 //
@@ -115,21 +117,19 @@ class LLInboxAddedObserver : public LLInventoryCategoryAddedObserver
 
 LLSidepanelInventory::LLSidepanelInventory()
 	: LLPanel()
-	, mItemPanel(NULL)
 	, mPanelMainInventory(NULL)
 	, mInboxEnabled(false)
 	, mCategoriesObserver(NULL)
 	, mInboxAddedObserver(NULL)
+    , mInboxLayoutPanel(NULL)
 {
 	//buildFromFile( "panel_inventory.xml"); // Called from LLRegisterPanelClass::defaultPanelClassBuilder()
 }
 
 LLSidepanelInventory::~LLSidepanelInventory()
 {
-	LLLayoutPanel* inbox_layout_panel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME);
-
 	// Save the InventoryMainPanelHeight in settings per account
-	gSavedPerAccountSettings.setS32("InventoryInboxHeight", inbox_layout_panel->getTargetDim());
+	gSavedPerAccountSettings.setS32("InventoryInboxHeight", mInboxLayoutPanel->getTargetDim());
 
 	if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver))
 	{
@@ -158,29 +158,11 @@ BOOL LLSidepanelInventory::postBuild()
 	// UI elements from inventory panel
 	{
 		mInventoryPanel = getChild<LLPanel>("sidepanel_inventory_panel");
-
-		mInfoBtn = mInventoryPanel->getChild<LLButton>("info_btn");
-		mInfoBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onInfoButtonClicked, this));
-		
-		mShareBtn = mInventoryPanel->getChild<LLButton>("share_btn");
-		mShareBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onShareButtonClicked, this));
-		
-		mShopBtn = mInventoryPanel->getChild<LLButton>("shop_btn");
-		mShopBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onShopButtonClicked, this));
-
-		mWearBtn = mInventoryPanel->getChild<LLButton>("wear_btn");
-		mWearBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onWearButtonClicked, this));
-		
-		mPlayBtn = mInventoryPanel->getChild<LLButton>("play_btn");
-		mPlayBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onPlayButtonClicked, this));
-		
-		mTeleportBtn = mInventoryPanel->getChild<LLButton>("teleport_btn");
-		mTeleportBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onTeleportButtonClicked, this));
 		
 		mPanelMainInventory = mInventoryPanel->getChild<LLPanelMainInventory>("panel_main_inventory");
 		mPanelMainInventory->setSelectCallback(boost::bind(&LLSidepanelInventory::onSelectionChange, this, _1, _2));
-		LLTabContainer* tabs = mPanelMainInventory->getChild<LLTabContainer>("inventory filter tabs");
-		tabs->setCommitCallback(boost::bind(&LLSidepanelInventory::updateVerbs, this));
+		//LLTabContainer* tabs = mPanelMainInventory->getChild<LLTabContainer>("inventory filter tabs");
+		//tabs->setCommitCallback(boost::bind(&LLSidepanelInventory::updateVerbs, this));
 
 		/* 
 		   EXT-4846 : "Can we suppress the "Landmarks" and "My Favorites" folder since they have their own Task Panel?"
@@ -190,25 +172,7 @@ BOOL LLSidepanelInventory::postBuild()
 		my_inventory_panel->addHideFolderType(LLFolderType::FT_FAVORITE);
 		*/
 
-		LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLSidepanelInventory::updateVerbs, this));
-	}
-
-	// UI elements from item panel
-	{
-		mItemPanel = getChild<LLSidepanelItemInfo>("sidepanel__item_panel");
-		
-		LLButton* back_btn = mItemPanel->getChild<LLButton>("back_btn");
-		back_btn->setClickedCallback(boost::bind(&LLSidepanelInventory::onBackButtonClicked, this));
-	}
-
-	// UI elements from task panel
-	{
-		mTaskPanel = findChild<LLSidepanelTaskInfo>("sidepanel__task_panel");
-		if (mTaskPanel)
-		{
-			LLButton* back_btn = mTaskPanel->getChild<LLButton>("back_btn");
-			back_btn->setClickedCallback(boost::bind(&LLSidepanelInventory::onBackButtonClicked, this));
-		}
+		//LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLSidepanelInventory::updateVerbs, this));
 	}
 	
 	// Received items inbox setup
@@ -220,38 +184,55 @@ BOOL LLSidepanelInventory::postBuild()
 
 		mInboxBtn->setCommitCallback(boost::bind(&LLSidepanelInventory::onToggleInboxBtn, this));
 
-		// Get the previous inbox state from "InventoryInboxToggleState" setting.
-		bool is_inbox_collapsed = !mInboxBtn->getToggleState();
+		// For main Inventory floater: Get the previous inbox state from "InventoryInboxToggleState" setting. 
+        // For additional Inventory floaters: Collapsed state is default.
+		bool is_inbox_collapsed = !mInboxBtn->getToggleState() || sLoginCompleted;
 
 		// Restore the collapsed inbox panel state
-		LLLayoutPanel* inbox_panel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME);
-		inv_stack->collapsePanel(inbox_panel, is_inbox_collapsed);
-		if (!is_inbox_collapsed)
-		{
-			inbox_panel->setTargetDim(gSavedPerAccountSettings.getS32("InventoryInboxHeight"));
-		}
-
-		// Set the inbox visible based on debug settings (final setting comes from http request below)
-		enableInbox(gSavedSettings.getBOOL("InventoryDisplayInbox"));
-
-		// Trigger callback for after login so we can setup to track inbox changes after initial inventory load
-		LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLSidepanelInventory::updateInbox, this));
+        mInboxLayoutPanel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME);
+        inv_stack->collapsePanel(mInboxLayoutPanel, is_inbox_collapsed);
+        if (!is_inbox_collapsed)
+        {
+            mInboxLayoutPanel->setTargetDim(gSavedPerAccountSettings.getS32("InventoryInboxHeight"));
+        }
+
+        if (sLoginCompleted)
+        {
+            //save the state of Inbox panel only for main Inventory floater
+			mInboxBtn->removeControlVariable();
+			mInboxBtn->setToggleState(false);
+            updateInbox();
+        }
+        else
+        {
+            // Trigger callback for after login so we can setup to track inbox changes after initial inventory load
+            LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLSidepanelInventory::updateInbox, this));
+        }
 	}
 
 	gSavedSettings.getControl("InventoryDisplayInbox")->getCommitSignal()->connect(boost::bind(&handleInventoryDisplayInboxChanged));
 
-	// Update the verbs buttons state.
-	updateVerbs();
+    LLFloater *floater = dynamic_cast<LLFloater*>(getParent());
+    if (floater && floater->getKey().isUndefined() && !sLoginCompleted)
+    {
+        // Prefill inventory for primary inventory floater
+        // Other floaters should fill on visibility change
+        // 
+        // see get_instance_num();
+        // Primary inventory floater will have undefined key
+        initInventoryViews();
+    }
 
 	return TRUE;
 }
 
 void LLSidepanelInventory::updateInbox()
 {
+    sLoginCompleted = true;
 	//
 	// Track inbox folder changes
 	//
-	const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, true);
+	const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
 	
 	// Set up observer to listen for creation of inbox if it doesn't exist
 	if (inbox_id.isNull())
@@ -336,8 +317,20 @@ void LLSidepanelInventory::enableInbox(bool enabled)
 {
 	mInboxEnabled = enabled;
 	
-	LLLayoutPanel * inbox_layout_panel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME);
-	inbox_layout_panel->setVisible(enabled);
+    if(!enabled || !mPanelMainInventory->isSingleFolderMode())
+    {
+        toggleInbox();
+    }
+}
+
+void LLSidepanelInventory::hideInbox()
+{
+    mInboxLayoutPanel->setVisible(false);
+}
+
+void LLSidepanelInventory::toggleInbox()
+{
+    mInboxLayoutPanel->setVisible(mInboxEnabled);
 }
 
 void LLSidepanelInventory::openInbox()
@@ -366,25 +359,25 @@ void LLSidepanelInventory::onInboxChanged(const LLUUID& inbox_id)
 
 void LLSidepanelInventory::onToggleInboxBtn()
 {
-	LLLayoutPanel* inboxPanel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME);
+	LLButton* inboxButton = getChild<LLButton>(INBOX_BUTTON_NAME);
 	LLLayoutStack* inv_stack = getChild<LLLayoutStack>(INVENTORY_LAYOUT_STACK_NAME);
 	
-	const bool inbox_expanded = mInboxBtn->getToggleState();
+	const bool inbox_expanded = inboxButton->getToggleState();
 	
 	// Expand/collapse the indicated panel
-	inv_stack->collapsePanel(inboxPanel, !inbox_expanded);
+	inv_stack->collapsePanel(mInboxLayoutPanel, !inbox_expanded);
 
 	if (inbox_expanded)
 	{
-		inboxPanel->setTargetDim(gSavedPerAccountSettings.getS32("InventoryInboxHeight"));
-		if (inboxPanel->isInVisibleChain())
+        mInboxLayoutPanel->setTargetDim(gSavedPerAccountSettings.getS32("InventoryInboxHeight"));
+		if (mInboxLayoutPanel->isInVisibleChain())
 	{
 		gSavedPerAccountSettings.setU32("LastInventoryInboxActivity", time_corrected());
 	}
 }
 	else
 	{
-		gSavedPerAccountSettings.setS32("InventoryInboxHeight", inboxPanel->getTargetDim());
+		gSavedPerAccountSettings.setS32("InventoryInboxHeight", mInboxLayoutPanel->getTargetDim());
 	}
 
 }
@@ -408,47 +401,7 @@ void LLSidepanelInventory::onOpen(const LLSD& key)
 	}
 #endif
 
-	if(key.size() == 0)
-		return;
-
-	mItemPanel->reset();
-
-	if (key.has("id"))
-	{
-		mItemPanel->setItemID(key["id"].asUUID());
-		if (key.has("object"))
-		{
-			mItemPanel->setObjectID(key["object"].asUUID());
-		}
-		showItemInfoPanel();
-	}
-	if (key.has("task"))
-	{
-		if (mTaskPanel)
-			mTaskPanel->setObjectSelection(LLSelectMgr::getInstance()->getSelection());
-		showTaskInfoPanel();
-	}
-}
-
-void LLSidepanelInventory::onInfoButtonClicked()
-{
-	LLInventoryItem *item = getSelectedItem();
-	if (item)
-	{
-		mItemPanel->reset();
-		mItemPanel->setItemID(item->getUUID());
-		showItemInfoPanel();
-	}
-}
-
-void LLSidepanelInventory::onShareButtonClicked()
-{
-	LLAvatarActions::shareWithAvatars(this);
-}
-
-void LLSidepanelInventory::onShopButtonClicked()
-{
-	LLWeb::loadURL(gSavedSettings.getString("MarketplaceURL"));
+    gAgent.showLatestFeatureNotification("inventory");
 }
 
 void LLSidepanelInventory::performActionOnSelection(const std::string &action)
@@ -470,47 +423,6 @@ void LLSidepanelInventory::performActionOnSelection(const std::string &action)
 	static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->performAction(mPanelMainInventory->getActivePanel()->getModel(), action);
 }
 
-void LLSidepanelInventory::onWearButtonClicked()
-{
-	// Get selected items set.
-	const std::set<LLUUID> selected_uuids_set = LLAvatarActions::getInventorySelectedUUIDs();
-	if (selected_uuids_set.empty()) return; // nothing selected
-
-	// Convert the set to a vector.
-	uuid_vec_t selected_uuids_vec;
-	for (std::set<LLUUID>::const_iterator it = selected_uuids_set.begin(); it != selected_uuids_set.end(); ++it)
-	{
-		selected_uuids_vec.push_back(*it);
-	}
-
-	// Wear all selected items.
-	wear_multiple(selected_uuids_vec, true);
-}
-
-void LLSidepanelInventory::onPlayButtonClicked()
-{
-	const LLInventoryItem *item = getSelectedItem();
-	if (!item)
-	{
-		return;
-	}
-
-	switch(item->getInventoryType())
-	{
-	case LLInventoryType::IT_GESTURE:
-		performActionOnSelection("play");
-		break;
-	default:
-		performActionOnSelection("open");
-		break;
-	}
-}
-
-void LLSidepanelInventory::onTeleportButtonClicked()
-{
-	performActionOnSelection("teleport");
-}
-
 void LLSidepanelInventory::onBackButtonClicked()
 {
 	showInventoryPanel();
@@ -518,102 +430,17 @@ void LLSidepanelInventory::onBackButtonClicked()
 
 void LLSidepanelInventory::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action)
 {
-	updateVerbs();
-}
-
-void LLSidepanelInventory::showItemInfoPanel()
-{
-	mItemPanel->setVisible(TRUE);
-	if (mTaskPanel)
-		mTaskPanel->setVisible(FALSE);
-	mInventoryPanel->setVisible(FALSE);
 
-	mItemPanel->dirty();
-	mItemPanel->setIsEditing(FALSE);
-}
-
-void LLSidepanelInventory::showTaskInfoPanel()
-{
-	mItemPanel->setVisible(FALSE);
-	mInventoryPanel->setVisible(FALSE);
-
-	if (mTaskPanel)
-	{
-		mTaskPanel->setVisible(TRUE);
-		mTaskPanel->dirty();
-		mTaskPanel->setIsEditing(FALSE);
-	}
 }
 
 void LLSidepanelInventory::showInventoryPanel()
 {
-	mItemPanel->setVisible(FALSE);
-	if (mTaskPanel)
-		mTaskPanel->setVisible(FALSE);
 	mInventoryPanel->setVisible(TRUE);
-	updateVerbs();
 }
 
-void LLSidepanelInventory::updateVerbs()
+void LLSidepanelInventory::initInventoryViews()
 {
-	mInfoBtn->setEnabled(FALSE);
-	mShareBtn->setEnabled(FALSE);
-
-	mWearBtn->setVisible(FALSE);
-	mWearBtn->setEnabled(FALSE);
-	mPlayBtn->setVisible(FALSE);
-	mPlayBtn->setEnabled(FALSE);
-	mPlayBtn->setToolTip(std::string(""));
- 	mTeleportBtn->setVisible(FALSE);
- 	mTeleportBtn->setEnabled(FALSE);
- 	mShopBtn->setVisible(TRUE);
-
-	mShareBtn->setEnabled(canShare());
-
-	const LLInventoryItem *item = getSelectedItem();
-	if (!item)
-		return;
-
-	bool is_single_selection = getSelectedCount() == 1;
-
-	mInfoBtn->setEnabled(is_single_selection);
-
-	switch(item->getInventoryType())
-	{
-		case LLInventoryType::IT_WEARABLE:
-		case LLInventoryType::IT_OBJECT:
-		case LLInventoryType::IT_ATTACHMENT:
-			mWearBtn->setVisible(TRUE);
-			mWearBtn->setEnabled(canWearSelected());
-		 	mShopBtn->setVisible(FALSE);
-			break;
-		case LLInventoryType::IT_SOUND:
-			mPlayBtn->setVisible(TRUE);
-			mPlayBtn->setEnabled(TRUE);
-			mPlayBtn->setToolTip(LLTrans::getString("InventoryPlaySoundTooltip"));
-			mShopBtn->setVisible(FALSE);
-			break;
-		case LLInventoryType::IT_GESTURE:
-			mPlayBtn->setVisible(TRUE);
-			mPlayBtn->setEnabled(TRUE);
-			mPlayBtn->setToolTip(LLTrans::getString("InventoryPlayGestureTooltip"));
-			mShopBtn->setVisible(FALSE);
-			break;
-		case LLInventoryType::IT_ANIMATION:
-			mPlayBtn->setVisible(TRUE);
-			mPlayBtn->setEnabled(TRUE);
-			mPlayBtn->setEnabled(TRUE);
-			mPlayBtn->setToolTip(LLTrans::getString("InventoryPlayAnimationTooltip"));
-			mShopBtn->setVisible(FALSE);
-			break;
-		case LLInventoryType::IT_LANDMARK:
-			mTeleportBtn->setVisible(TRUE);
-			mTeleportBtn->setEnabled(TRUE);
-		 	mShopBtn->setVisible(FALSE);
-			break;
-		default:
-			break;
-	}
+    mPanelMainInventory->initInventoryViews();
 }
 
 bool LLSidepanelInventory::canShare()
@@ -736,12 +563,10 @@ void LLSidepanelInventory::clearSelections(bool clearMain, bool clearInbox)
 		}
 	}
 	
-	if (clearInbox && mInboxEnabled && mInventoryPanelInbox.get())
+	if (clearInbox && mInboxEnabled && !mInventoryPanelInbox.isDead())
 	{
 		mInventoryPanelInbox.get()->getRootFolder()->clearSelection();
 	}
-	
-	updateVerbs();
 }
 
 std::set<LLFolderViewItem*> LLSidepanelInventory::getInboxSelectionList()
diff --git a/indra/newview/llsidepanelinventory.h b/indra/newview/llsidepanelinventory.h
index 33a4ea8c3839082e1520123ec91134870346e441..1fa4520c4e6a5322fe955abbf3d015c5defbea83 100644
--- a/indra/newview/llsidepanelinventory.h
+++ b/indra/newview/llsidepanelinventory.h
@@ -66,9 +66,8 @@ class LLSidepanelInventory : public LLPanel
 	void clearSelections(bool clearMain, bool clearInbox);
     std::set<LLFolderViewItem*> getInboxSelectionList();
 
-	void showItemInfoPanel();
-	void showTaskInfoPanel();
 	void showInventoryPanel();
+    void initInventoryViews();
 
 	// checks can share selected item(s)
 	bool canShare();
@@ -76,13 +75,13 @@ class LLSidepanelInventory : public LLPanel
 	void onToggleInboxBtn();
 
 	void enableInbox(bool enabled);
+    void toggleInbox();
+    void hideInbox();
 	
 	void openInbox();
 	
 	bool isInboxEnabled() const { return mInboxEnabled; }
 
-	void updateVerbs();
-
 	static void cleanup();
 
 protected:
@@ -103,28 +102,15 @@ class LLSidepanelInventory : public LLPanel
 private:
 	LLPanel*					mInventoryPanel; // Main inventory view
 	LLHandle<LLInventoryPanel>	mInventoryPanelInbox;
-	LLSidepanelItemInfo*		mItemPanel; // Individual item view
-	LLSidepanelTaskInfo*		mTaskPanel; // Individual in-world object view
 	LLPanelMainInventory*		mPanelMainInventory;
 
+    LLLayoutPanel* mInboxLayoutPanel;
+
 protected:
-	void 						onInfoButtonClicked();
-	void 						onShareButtonClicked();
-	void 						onShopButtonClicked();
-	void 						onWearButtonClicked();
-	void 						onPlayButtonClicked();
-	void 						onTeleportButtonClicked();
 	void 						onBackButtonClicked();
 
 private:
-	LLButton*					mInfoBtn;
-	LLButton*					mShareBtn;
-	LLButton*					mWearBtn;
-	LLButton*					mPlayBtn;
-	LLButton*					mTeleportBtn;
-	LLButton*					mShopBtn;
 	LLButton*					mInboxBtn = nullptr;
-
 	bool						mInboxEnabled;
 
 	LLInventoryCategoriesObserver* 	mCategoriesObserver;
diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp
index 3815dee928fc8c287a0f05098ff4f1ffa624a20a..83cd01bd449495b0e4cb7c8667ae7f80b5e268d8 100644
--- a/indra/newview/llsidepaneliteminfo.cpp
+++ b/indra/newview/llsidepaneliteminfo.cpp
@@ -31,16 +31,23 @@
 
 #include "llagent.h"
 #include "llavataractions.h"
+#include "llavatarnamecache.h"
 #include "llbutton.h"
+#include "llcallbacklist.h"
 #include "llcombobox.h"
+#include "llfloater.h"
 #include "llfloaterreg.h"
 #include "llgroupactions.h"
+#include "llgroupmgr.h"
+#include "lliconctrl.h"
 #include "llinventorydefines.h"
+#include "llinventoryicon.h"
 #include "llinventorymodel.h"
 #include "llinventoryobserver.h"
 #include "lllineeditor.h"
 #include "llradiogroup.h"
 #include "llslurl.h"
+#include "lltexteditor.h"
 #include "llviewercontrol.h"
 #include "llviewerinventory.h"
 #include "llviewerobjectlist.h"
@@ -52,58 +59,6 @@
 #include "rlvcommon.h"
 // [/RLVa:KB]
 
-extern bool can_set_export(const U32& base, const U32& own, const U32& next);
-
-static const std::array<std::string, 21> perm_and_sale_items{{
-	"perms_inv",
-	"perm_modify",
-	"CheckOwnerModify",
-	"CheckOwnerCopy",
-	"CheckOwnerTransfer",
-	"CheckOwnerExport",
-	"GroupLabel",
-	"CheckShareWithGroup",
-	"AnyoneLabel",
-	"CheckEveryoneCopy",
-	"NextOwnerLabel",
-	"CheckNextOwnerModify",
-	"CheckNextOwnerCopy",
-	"CheckNextOwnerTransfer",
-	"CheckNextOwnerExport",
-	"CheckPurchase",
-	"ComboBoxSaleType",
-	"Edit Cost"
-}};
-
-static const std::array<std::string, 16> no_item_names{{
-	"LabelItemName",
-	"LabelItemDesc",
-	"LabelCreatorName",
-	"LabelOwnerName"
-}};
-
-static const std::array<std::string, 12> property_fields{{
-	"CheckOwnerModify",
-	"CheckOwnerCopy",
-	"CheckOwnerTransfer",
-	"CheckOwnerExport",
-	"CheckShareWithGroup",
-	"CheckEveryoneCopy",
-	"CheckNextOwnerModify",
-	"CheckNextOwnerCopy",
-	"CheckNextOwnerTransfer",
-	"CheckNextOwnerExport",
-	"CheckPurchase",
-	"Edit Cost"
-}};
-
-static const std::array<std::string, 5> debug_items{{
-	"BaseMaskDebug",
-	"OwnerMaskDebug",
-	"GroupMaskDebug",
-	"EveryoneMaskDebug",
-	"NextMaskDebug"
-}};
 
 class PropertiesChangedCallback : public LLInventoryCallback
 {
@@ -128,49 +83,6 @@ class PropertiesChangedCallback : public LLInventoryCallback
     S32 mId;
 };
 
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLItemPropertiesObserver
-//
-// Helper class to watch for changes to the item.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLItemPropertiesObserver : public LLInventoryObserver
-{
-public:
-	LLItemPropertiesObserver(LLSidepanelItemInfo* floater)
-		: mFloater(floater)
-	{
-		gInventory.addObserver(this);
-	}
-	virtual ~LLItemPropertiesObserver()
-	{
-		gInventory.removeObserver(this);
-	}
-	virtual void changed(U32 mask);
-private:
-	LLSidepanelItemInfo* mFloater; // Not a handle because LLSidepanelItemInfo is managing LLItemPropertiesObserver
-};
-
-void LLItemPropertiesObserver::changed(U32 mask)
-{
-	const std::set<LLUUID>& mChangedItemIDs = gInventory.getChangedIDs();
-	std::set<LLUUID>::const_iterator it;
-
-	const LLUUID& item_id = mFloater->getItemID();
-
-	for (it = mChangedItemIDs.begin(); it != mChangedItemIDs.end(); it++)
-	{
-		// set dirty for 'item profile panel' only if changed item is the item for which 'item profile panel' is shown (STORM-288)
-		if (*it == item_id)
-		{
-			// if there's a change we're interested in.
-			if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
-			{
-				mFloater->dirty();
-			}
-		}
-	}
-}
-
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLObjectInventoryObserver
 //
@@ -214,36 +126,48 @@ static LLPanelInjector<LLSidepanelItemInfo> t_item_info("sidepanel_item_info");
 
 // Default constructor
 LLSidepanelItemInfo::LLSidepanelItemInfo(const LLPanel::Params& p)
-	: LLSidepanelInventorySubpanel(p)
+	: LLPanel(p)
 	, mItemID(LLUUID::null)
 	, mObjectInventoryObserver(NULL)
 	, mUpdatePendingId(-1)
+    , mIsDirty(false) /*Not ready*/
+    , mParentFloater(NULL)
 {
-	mPropertiesObserver = new LLItemPropertiesObserver(this);
+    gInventory.addObserver(this);
+    gIdleCallbacks.addFunction(&LLSidepanelItemInfo::onIdle, (void*)this);
 }
 
 // Destroys the object
 LLSidepanelItemInfo::~LLSidepanelItemInfo()
 {
-	delete mPropertiesObserver;
-	mPropertiesObserver = NULL;
+    gInventory.removeObserver(this);
+    gIdleCallbacks.deleteFunction(&LLSidepanelItemInfo::onIdle, (void*)this);
 
 	stopObjectInventoryObserver();
+    
+    if (mOwnerCacheConnection.connected())
+    {
+        mOwnerCacheConnection.disconnect();
+    }
+    if (mCreatorCacheConnection.connected())
+    {
+        mCreatorCacheConnection.disconnect();
+    }
 }
 
 // virtual
 BOOL LLSidepanelItemInfo::postBuild()
 {
-	LLSidepanelInventorySubpanel::postBuild();
-
+    mChangeThumbnailBtn = getChild<LLUICtrl>("change_thumbnail_btn");
+    mItemTypeIcon = getChild<LLIconCtrl>("item_type_icon");
+    mLabelOwnerName = getChild<LLTextBox>("LabelOwnerName");
+    mLabelCreatorName = getChild<LLTextBox>("LabelCreatorName");
+    
 	getChild<LLLineEditor>("LabelItemName")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
 	getChild<LLUICtrl>("LabelItemName")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitName,this));
-	getChild<LLLineEditor>("LabelItemDesc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
 	getChild<LLUICtrl>("LabelItemDesc")->setCommitCallback(boost::bind(&LLSidepanelItemInfo:: onCommitDescription, this));
-	// Creator information
-	getChild<LLUICtrl>("BtnCreator")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onClickCreator,this));
-	// owner information
-	getChild<LLUICtrl>("BtnOwner")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onClickOwner,this));
+    // Thumnail edition
+    mChangeThumbnailBtn->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onEditThumbnail, this));
 	// acquired date
 	// owner permissions
 	// Permissions debug text
@@ -255,7 +179,6 @@ BOOL LLSidepanelItemInfo::postBuild()
 	getChild<LLUICtrl>("CheckNextOwnerModify")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1));
 	getChild<LLUICtrl>("CheckNextOwnerCopy")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1));
 	getChild<LLUICtrl>("CheckNextOwnerTransfer")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1));
-	getChild<LLUICtrl>("CheckNextOwnerExport")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1));
 	// Mark for sale or not, and sale info
 	getChild<LLUICtrl>("CheckPurchase")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitSaleInfo, this, _1));
 	// Change sale type, and sale info
@@ -283,6 +206,12 @@ void LLSidepanelItemInfo::setItemID(const LLUUID& item_id)
         mItemID = item_id;
         mUpdatePendingId = -1;
     }
+    dirty();
+}
+
+void LLSidepanelItemInfo::setParentFloater(LLFloater* parent)
+{
+    mParentFloater = parent;
 }
 
 const LLUUID& LLSidepanelItemInfo::getObjectID() const
@@ -306,12 +235,11 @@ void LLSidepanelItemInfo::onUpdateCallback(const LLUUID& item_id, S32 received_u
 
 void LLSidepanelItemInfo::reset()
 {
-	LLSidepanelInventorySubpanel::reset();
-
 	mObjectID = LLUUID::null;
 	mItemID = LLUUID::null;
 
 	stopObjectInventoryObserver();
+    dirty();
 }
 
 void LLSidepanelItemInfo::refresh()
@@ -319,40 +247,37 @@ void LLSidepanelItemInfo::refresh()
 	LLViewerInventoryItem* item = findItem();
 	if(item)
 	{
-		refreshFromItem(item);
-		updateVerbs();
+        const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+        bool in_trash = (item->getUUID() == trash_id) || gInventory.isObjectDescendentOf(item->getUUID(), trash_id);
+        if (in_trash && mParentFloater)
+        {
+            // Close properties when moving to trash
+            // Aren't supposed to view properties from trash
+            mParentFloater->closeFloater();
+        }
+        else
+        {
+            refreshFromItem(item);
+        }
 		return;
 	}
-	else
-	{
-		if (getIsEditing())
-		{
-			setIsEditing(FALSE);
-		}
-	}
-
-	if (!getIsEditing())
-	{
-		for(auto const& item : no_item_names)
-		{
-			getChildView(item)->setEnabled(false);
-		}
-
-		setPropertiesFieldsEnabled(false);
-
-		for(auto const& item : debug_items)
-		{
-			getChildView(item)->setVisible(false);
-		}
-	}
 
-	if (!item)
-	{
-		getChildView("BtnCreator")->setEnabled(false);
-		getChildView("BtnOwner")->setEnabled(false);
-	}
-
-	updateVerbs();
+    if (mObjectID.notNull())
+    {
+        LLViewerObject* object = gObjectList.findObject(mObjectID);
+        if (object)
+        {
+            // Object exists, but object's content is not nessesary
+            // loaded, so assume item exists as well
+            return;
+        }
+    }
+    
+    if (mParentFloater)
+    {
+        // if we failed to get item, it likely no longer exists
+        mParentFloater->closeFloater();
+    }
 }
 
 void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
@@ -370,7 +295,7 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
     }
 
 	// do not enable the UI for incomplete items.
-	BOOL is_complete = item->isFinished();
+	bool is_complete = item->isFinished();
 	const BOOL cannot_restrict_permissions = LLInventoryType::cannotRestrictPermissions(item->getInventoryType());
 	const BOOL is_calling_card = (item->getInventoryType() == LLInventoryType::IT_CALLINGCARD);
 	const BOOL is_settings = (item->getInventoryType() == LLInventoryType::IT_SETTINGS);
@@ -422,8 +347,22 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 	getChild<LLUICtrl>("LabelItemName")->setValue(item->getName());
 	getChildView("LabelItemDescTitle")->setEnabled(TRUE);
 	getChildView("LabelItemDesc")->setEnabled(is_modifiable);
-	getChildView("IconLocked")->setVisible(!is_modifiable);
 	getChild<LLUICtrl>("LabelItemDesc")->setValue(item->getDescription());
+    getChild<LLUICtrl>("item_thumbnail")->setValue(item->getThumbnailUUID());
+
+    LLUIImagePtr icon_img = LLInventoryIcon::getIcon(item->getType(), item->getInventoryType(), item->getFlags(), FALSE);
+    mItemTypeIcon->setImage(icon_img);
+ 
+    // Style for creator and owner links
+    LLStyle::Params style_params;
+    LLColor4 link_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+    style_params.color = link_color;
+    style_params.readonly_color = link_color;
+    style_params.is_link = true; // link will be added later
+    const LLFontGL* fontp = mLabelCreatorName->getFont();
+    style_params.font.name = LLFontGL::nameFromFont(fontp);
+    style_params.font.size = LLFontGL::sizeFromFont(fontp);
+    style_params.font.style = "UNDERLINE";
 
 	//////////////////
 	// CREATOR NAME //
@@ -434,30 +373,34 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 	if (item->getCreatorUUID().notNull())
 	{
 		LLUUID creator_id = item->getCreatorUUID();
-//		std::string name =
-//			LLSLURL("agent", creator_id, "completename").getSLURLString();
-//		getChildView("BtnCreator")->setEnabled(TRUE);
-// [RLVa:KB] - Checked: RLVa-2.0.1
-		// If the object creator matches the object owner we need to anonymize the creator field as well
-		bool fRlvCanShowCreator = true;
-		if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, creator_id)) &&
-		     ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == creator_id) ) || (RlvUtil::isNearbyAgent(item->getCreatorUUID())) ) )
-		{
-			fRlvCanShowCreator = false;
-		}
-		std::string name = LLSLURL("agent", creator_id, (fRlvCanShowCreator) ? "completename" : "rlvanonym").getSLURLString();
-		getChildView("BtnCreator")->setEnabled(fRlvCanShowCreator);
-// [/RLVa:KB]
+		std::string slurl =
+			LLSLURL("agent", creator_id, "inspect").getSLURLString();
+
+        style_params.link_href = slurl;
+        
+        LLAvatarName av_name;
+        if (LLAvatarNameCache::get(creator_id, &av_name))
+        {
+            updateCreatorName(creator_id, av_name, style_params);
+        }
+        else
+        {
+            if (mCreatorCacheConnection.connected())
+            {
+                mCreatorCacheConnection.disconnect();
+            }
+            mLabelCreatorName->setText(LLTrans::getString("None"));
+            mCreatorCacheConnection = LLAvatarNameCache::get(creator_id, boost::bind(&LLSidepanelItemInfo::updateCreatorName, this, _1, _2, style_params));
+        }
+        
 		getChildView("LabelCreatorTitle")->setEnabled(TRUE);
-		getChildView("LabelCreatorName")->setEnabled(FALSE);
-		getChild<LLUICtrl>("LabelCreatorName")->setValue(name);
+        mLabelCreatorName->setEnabled(TRUE);
 	}
 	else
 	{
-		getChildView("BtnCreator")->setEnabled(FALSE);
 		getChildView("LabelCreatorTitle")->setEnabled(FALSE);
-		getChildView("LabelCreatorName")->setEnabled(FALSE);
-		getChild<LLUICtrl>("LabelCreatorName")->setValue(getString("unknown_multiple"));
+        mLabelCreatorName->setEnabled(FALSE);
+        mLabelCreatorName->setValue(getString("unknown_multiple"));
 	}
 
 	////////////////
@@ -465,38 +408,60 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 	////////////////
 	if(perm.isOwned())
 	{
-// [RLVa:KB] - Checked: RVLa-2.0.1
-		bool fRlvCanShowOwner = true;
-// [/RLVa:KB]
-		std::string name;
+        std::string slurl;
 		if (perm.isGroupOwned())
 		{
-			gCacheName->getGroupName(perm.getGroup(), name);
+            LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(perm.getGroup());
+            
+            slurl = LLSLURL("group", perm.getGroup(), "inspect").getSLURLString();
+            style_params.link_href = slurl;
+            if (group_data && group_data->isGroupPropertiesDataComplete())
+            {
+                mLabelOwnerName->setText(group_data->mName, style_params);
+            }
+            else
+            {
+                // Triggers refresh
+                LLGroupMgr::getInstance()->sendGroupPropertiesRequest(perm.getGroup());
+                
+                std::string name;
+                gCacheName->getGroupName(perm.getGroup(), name);
+                mLabelOwnerName->setText(name, style_params);
+            }
 		}
 		else
 		{
 			LLUUID owner_id = perm.getOwner();
-//			name = LLSLURL("agent", owner_id, "completename").getSLURLString();
-// [RLVa:KB] - Checked: RLVa-2.0.1
-			fRlvCanShowOwner = RlvActions::canShowName(RlvActions::SNC_DEFAULT, owner_id);
-			name = LLSLURL("agent", owner_id, (fRlvCanShowOwner) ? "completename" : "rlvanonym").getSLURLString();
-// [/RLVa:KB]
+            slurl = LLSLURL("agent", owner_id, "inspect").getSLURLString();
+            
+            style_params.link_href = slurl;
+            LLAvatarName av_name;
+            if (LLAvatarNameCache::get(owner_id, &av_name))
+            {
+                updateOwnerName(owner_id, av_name, style_params);
+            }
+            else
+            {
+                if (mOwnerCacheConnection.connected())
+                {
+                    mOwnerCacheConnection.disconnect();
+                }
+                mLabelOwnerName->setText(LLTrans::getString("None"));
+                mOwnerCacheConnection = LLAvatarNameCache::get(owner_id, boost::bind(&LLSidepanelItemInfo::updateOwnerName, this, _1, _2, style_params));
+            }
 		}
-//		getChildView("BtnOwner")->setEnabled(TRUE);
-// [RLVa:KB] - Checked: RLVa-2.0.1
-		getChildView("BtnOwner")->setEnabled(fRlvCanShowOwner);
-// [/RLVa:KB]
 		getChildView("LabelOwnerTitle")->setEnabled(TRUE);
-		getChildView("LabelOwnerName")->setEnabled(FALSE);
-		getChild<LLUICtrl>("LabelOwnerName")->setValue(name);
+        mLabelOwnerName->setEnabled(TRUE);
 	}
 	else
 	{
-		getChildView("BtnOwner")->setEnabled(FALSE);
 		getChildView("LabelOwnerTitle")->setEnabled(FALSE);
-		getChildView("LabelOwnerName")->setEnabled(FALSE);
-		getChild<LLUICtrl>("LabelOwnerName")->setValue(getString("public"));
+        mLabelOwnerName->setEnabled(FALSE);
+        mLabelOwnerName->setValue(getString("public"));
 	}
+
+    // Not yet supported for task inventories
+    mChangeThumbnailBtn->setEnabled(mObjectID.isNull() && ALEXANDRIA_LINDEN_ID != perm.getOwner());
 	
 	////////////
 	// ORIGIN //
@@ -533,26 +498,53 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 	// PERMISSIONS AND SALE ITEM HIDING //
 	//////////////////////////////////////
 	
+	const std::string perm_and_sale_items[]={
+		"perms_inv",
+		"perm_modify",
+		"CheckOwnerModify",
+		"CheckOwnerCopy",
+		"CheckOwnerTransfer",
+		"GroupLabel",
+		"CheckShareWithGroup",
+		"AnyoneLabel",
+		"CheckEveryoneCopy",
+		"NextOwnerLabel",
+		"CheckNextOwnerModify",
+		"CheckNextOwnerCopy",
+		"CheckNextOwnerTransfer",
+		"CheckPurchase",
+		"ComboBoxSaleType",
+		"Edit Cost"
+	};
+	
+	const std::string debug_items[]={
+		"BaseMaskDebug",
+		"OwnerMaskDebug",
+		"GroupMaskDebug",
+		"EveryoneMaskDebug",
+		"NextMaskDebug"
+	};
+	
 	// Hide permissions checkboxes and labels and for sale info if in the trash
 	// or ui elements don't apply to these objects and return from function
 	if (!not_in_trash || cannot_restrict_permissions)
 	{
-		for(const std::string& item : perm_and_sale_items)
+		for(size_t t=0; t<LL_ARRAY_SIZE(perm_and_sale_items); ++t)
 		{
-			getChildView(item)->setVisible(false);
+			getChildView(perm_and_sale_items[t])->setVisible(false);
 		}
 		
-		for(const std::string& item : debug_items)
+		for(size_t t=0; t<LL_ARRAY_SIZE(debug_items); ++t)
 		{
-			getChildView(item)->setVisible(false);
+			getChildView(debug_items[t])->setVisible(false);
 		}
 		return;
 	}
 	else // Make sure perms and sale ui elements are visible
 	{
-		for(const std::string& item : perm_and_sale_items)
+		for(size_t t=0; t<LL_ARRAY_SIZE(perm_and_sale_items); ++t)
 		{
-			getChildView(item)->setVisible(true);
+			getChildView(perm_and_sale_items[t])->setVisible(true);
 		}
 	}
 
@@ -572,12 +564,6 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 	getChild<LLUICtrl>("CheckOwnerCopy")->setValue(LLSD((BOOL)(owner_mask & PERM_COPY)));
 	getChildView("CheckOwnerTransfer")->setEnabled(FALSE);
 	getChild<LLUICtrl>("CheckOwnerTransfer")->setValue(LLSD((BOOL)(owner_mask & PERM_TRANSFER)));
-	getChildView("CheckOwnerExport")->setEnabled(FALSE);
-	getChild<LLUICtrl>("CheckOwnerExport")->setValue(LLSD((BOOL)(owner_mask & PERM_EXPORT)));
-
-	bool supports_export = gAgent.getRegion() && gAgent.getRegion()->getRegionAllowsExport();
-	if (!supports_export)
-		getChildView("CheckOwnerExport")->setVisible(false);
 
 	///////////////////////
 	// DEBUG PERMISSIONS //
@@ -585,6 +571,8 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 
 	if( gSavedSettings.getBOOL("DebugPermissions") )
 	{
+        childSetVisible("layout_debug_permissions", true);
+        
 		BOOL slam_perm 			= FALSE;
 		BOOL overwrite_group	= FALSE;
 		BOOL overwrite_everyone	= FALSE;
@@ -601,45 +589,30 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 
 		perm_string = "B: ";
 		perm_string += mask_to_string(base_mask);
-		if (!supports_export && base_mask & PERM_EXPORT) // Hide Export when not available
-			perm_string.erase(perm_string.find_last_of("E"));
 		getChild<LLUICtrl>("BaseMaskDebug")->setValue(perm_string);
-		getChildView("BaseMaskDebug")->setVisible(TRUE);
 		
 		perm_string = "O: ";
 		perm_string += mask_to_string(owner_mask);
-		if (!supports_export && owner_mask & PERM_EXPORT) // Hide Export when not available
-			perm_string.erase(perm_string.find_last_of("E"));
 		getChild<LLUICtrl>("OwnerMaskDebug")->setValue(perm_string);
-		getChildView("OwnerMaskDebug")->setVisible(TRUE);
 		
 		perm_string = "G";
 		perm_string += overwrite_group ? "*: " : ": ";
 		perm_string += mask_to_string(group_mask);
 		getChild<LLUICtrl>("GroupMaskDebug")->setValue(perm_string);
-		getChildView("GroupMaskDebug")->setVisible(TRUE);
 		
 		perm_string = "E";
 		perm_string += overwrite_everyone ? "*: " : ": ";
 		perm_string += mask_to_string(everyone_mask);
-		if (!supports_export && everyone_mask & PERM_EXPORT) // Hide Export when not available
-			perm_string.erase(perm_string.find_last_of("E"));
 		getChild<LLUICtrl>("EveryoneMaskDebug")->setValue(perm_string);
-		getChildView("EveryoneMaskDebug")->setVisible(TRUE);
 		
 		perm_string = "N";
 		perm_string += slam_perm ? "*: " : ": ";
 		perm_string += mask_to_string(next_owner_mask);
 		getChild<LLUICtrl>("NextMaskDebug")->setValue(perm_string);
-		getChildView("NextMaskDebug")->setVisible(TRUE);
 	}
 	else
 	{
-		getChildView("BaseMaskDebug")->setVisible(FALSE);
-		getChildView("OwnerMaskDebug")->setVisible(FALSE);
-		getChildView("GroupMaskDebug")->setVisible(FALSE);
-		getChildView("EveryoneMaskDebug")->setVisible(FALSE);
-		getChildView("NextMaskDebug")->setVisible(FALSE);
+        childSetVisible("layout_debug_permissions", false);
 	}
 
 	/////////////
@@ -662,8 +635,6 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 		getChildView("CheckShareWithGroup")->setEnabled(FALSE);
 		getChildView("CheckEveryoneCopy")->setEnabled(FALSE);
 	}
-	getChild<LLUICtrl>("CheckNextOwnerExport")->setEnabled(supports_export && item->getType() != LLAssetType::AT_OBJECT && gAgentID == item->getCreatorUUID()
-									&& can_set_export(base_mask, owner_mask, next_owner_mask));
 
 	// Set values.
 	BOOL is_group_copy = (group_mask & PERM_COPY) ? TRUE : FALSE;
@@ -700,7 +671,6 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 	}
 	
 	getChild<LLUICtrl>("CheckEveryoneCopy")->setValue(LLSD((BOOL)(everyone_mask & PERM_COPY)));
-	getChild<LLUICtrl>("CheckNextOwnerExport")->setValue(LLSD((BOOL)(supports_export && everyone_mask & PERM_EXPORT)));
 
 	///////////////
 	// SALE INFO //
@@ -717,11 +687,10 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 	{
 		getChildView("CheckPurchase")->setEnabled(is_complete);
 
-		bool no_export = !(everyone_mask & PERM_EXPORT); // Next owner perms can't be changed if set
-		getChildView("NextOwnerLabel")->setEnabled(no_export);
-		getChildView("CheckNextOwnerModify")->setEnabled(no_export && (base_mask & PERM_MODIFY) && !cannot_restrict_permissions);
-		getChildView("CheckNextOwnerCopy")->setEnabled(no_export && (base_mask & PERM_COPY) && !cannot_restrict_permissions && !is_settings);
-		getChildView("CheckNextOwnerTransfer")->setEnabled(no_export && (next_owner_mask & PERM_COPY) && !cannot_restrict_permissions);
+		getChildView("NextOwnerLabel")->setEnabled(TRUE);
+		getChildView("CheckNextOwnerModify")->setEnabled((base_mask & PERM_MODIFY) && !cannot_restrict_permissions);
+		getChildView("CheckNextOwnerCopy")->setEnabled((base_mask & PERM_COPY) && !cannot_restrict_permissions && !is_settings);
+		getChildView("CheckNextOwnerTransfer")->setEnabled((next_owner_mask & PERM_COPY) && !cannot_restrict_permissions);
 
 		combo_sale_type->setEnabled(is_complete && is_for_sale);
 		edit_cost->setEnabled(is_complete && is_for_sale);
@@ -778,6 +747,68 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 	}
 }
 
+void LLSidepanelItemInfo::updateCreatorName(const LLUUID& creator_id, const LLAvatarName& creator_name, const LLStyle::Params& style_params)
+{
+    if (mCreatorCacheConnection.connected())
+    {
+        mCreatorCacheConnection.disconnect();
+    }
+    std::string name = creator_name.getCompleteName();
+    mLabelCreatorName->setText(name, style_params);
+}
+
+void LLSidepanelItemInfo::updateOwnerName(const LLUUID& owner_id, const LLAvatarName& owner_name, const LLStyle::Params& style_params)
+{
+    if (mOwnerCacheConnection.connected())
+    {
+        mOwnerCacheConnection.disconnect();
+    }
+    std::string name = owner_name.getCompleteName();
+    mLabelOwnerName->setText(name, style_params);
+}
+
+void LLSidepanelItemInfo::changed(U32 mask)
+{
+    const LLUUID& item_id = getItemID();
+    if (getObjectID().notNull() || item_id.isNull())
+    {
+        // Task inventory or not set up yet
+        return;
+    }
+    
+    const std::set<LLUUID>& mChangedItemIDs = gInventory.getChangedIDs();
+    std::set<LLUUID>::const_iterator it;
+
+    for (it = mChangedItemIDs.begin(); it != mChangedItemIDs.end(); it++)
+    {
+        // set dirty for 'item profile panel' only if changed item is the item for which 'item profile panel' is shown (STORM-288)
+        if (*it == item_id)
+        {
+            // if there's a change we're interested in.
+            if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
+            {
+                dirty();
+            }
+        }
+    }
+}
+
+void LLSidepanelItemInfo::dirty()
+{
+    mIsDirty = true;
+}
+
+// static
+void LLSidepanelItemInfo::onIdle( void* user_data )
+{
+    LLSidepanelItemInfo* self = reinterpret_cast<LLSidepanelItemInfo*>(user_data);
+
+    if( self->mIsDirty )
+    {
+        self->refresh();
+        self->mIsDirty = false;
+    }
+}
 
 void LLSidepanelItemInfo::setAssociatedExperience( LLHandle<LLSidepanelItemInfo> hInfo, const LLSD& experience )
 {
@@ -825,14 +856,26 @@ void LLSidepanelItemInfo::startObjectInventoryObserver()
 void LLSidepanelItemInfo::stopObjectInventoryObserver()
 {
 	delete mObjectInventoryObserver;
-	mObjectInventoryObserver = nullptr;
+	mObjectInventoryObserver = NULL;
 }
 
 void LLSidepanelItemInfo::setPropertiesFieldsEnabled(bool enabled)
 {
-    for(auto const& item : property_fields)
+    const std::string fields[] = {
+        "CheckOwnerModify",
+        "CheckOwnerCopy",
+        "CheckOwnerTransfer",
+        "CheckShareWithGroup",
+        "CheckEveryoneCopy",
+        "CheckNextOwnerModify",
+        "CheckNextOwnerCopy",
+        "CheckNextOwnerTransfer",
+        "CheckPurchase",
+        "Edit Cost"
+    };
+    for (size_t t = 0; t<LL_ARRAY_SIZE(fields); ++t)
     {
-        getChildView(item)->setEnabled(false);
+        getChildView(fields[t])->setEnabled(false);
     }
 }
 
@@ -903,7 +946,7 @@ void LLSidepanelItemInfo::onCommitDescription()
 	LLViewerInventoryItem* item = findItem();
 	if(!item) return;
 
-	LLLineEditor* labelItemDesc = getChild<LLLineEditor>("LabelItemDesc");
+    LLTextEditor* labelItemDesc = getChild<LLTextEditor>("LabelItemDesc");
 	if(!labelItemDesc)
 	{
 		return;
@@ -958,6 +1001,7 @@ void LLSidepanelItemInfo::updatePermissions()
 		perm.setEveryoneBits(gAgent.getID(), group_id,
 						 CheckEveryoneCopy->get(), PERM_COPY);
 	}
+
 	LLCheckBoxCtrl* CheckNextOwnerModify = getChild<LLCheckBoxCtrl>("CheckNextOwnerModify");
 	if(CheckNextOwnerModify)
 	{
@@ -975,14 +1019,7 @@ void LLSidepanelItemInfo::updatePermissions()
 	{
 		perm.setNextOwnerBits(gAgent.getID(), group_id,
 							CheckNextOwnerTransfer->get(), PERM_TRANSFER);
-	LLCheckBoxCtrl* CheckNextOwnerExport = getChild<LLCheckBoxCtrl>("CheckNextOwnerExport");
-	if(CheckNextOwnerExport && CheckNextOwnerExport->getVisible())
-	{
-		perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(),
-							  CheckNextOwnerExport->get(), PERM_EXPORT);
 	}
-	}
-
 	if(perm != item->getPermissions()
 		&& item->isFinished())
 	{
@@ -1022,7 +1059,14 @@ void LLSidepanelItemInfo::updatePermissions()
 	}
 }
 
-// static
+void LLSidepanelItemInfo::onEditThumbnail()
+{
+    LLSD data;
+    data["task_id"] = mObjectID;
+    data["item_id"] = mItemID;
+    LLFloaterReg::showInstance("change_item_thumbnail", data);
+}
+
 void LLSidepanelItemInfo::onCommitSaleInfo(LLUICtrl* ctrl)
 {
     if (ctrl)
diff --git a/indra/newview/llsidepaneliteminfo.h b/indra/newview/llsidepaneliteminfo.h
index 5f29254182f9dfd5934f8efc232e1494494ae187..b916f4452061f56a07094ffcc043c9e7bdd185b6 100644
--- a/indra/newview/llsidepaneliteminfo.h
+++ b/indra/newview/llsidepaneliteminfo.h
@@ -27,42 +27,55 @@
 #ifndef LL_LLSIDEPANELITEMINFO_H
 #define LL_LLSIDEPANELITEMINFO_H
 
-#include "llsidepanelinventorysubpanel.h"
+#include "llinventoryobserver.h"
+#include "llpanel.h"
+#include "llstyle.h"
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLSidepanelItemInfo
 // Object properties for inventory side panel.
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+class LLAvatarName;
 class LLButton;
+class LLFloater;
+class LLIconCtrl;
 class LLViewerInventoryItem;
 class LLItemPropertiesObserver;
 class LLObjectInventoryObserver;
 class LLViewerObject;
 class LLPermissions;
+class LLTextBox;
 
-class LLSidepanelItemInfo : public LLSidepanelInventorySubpanel
+class LLSidepanelItemInfo : public LLPanel, public LLInventoryObserver
 {
 public:
 	LLSidepanelItemInfo(const LLPanel::Params& p = getDefaultParams());
 	virtual ~LLSidepanelItemInfo();
 	
-	/*virtual*/ BOOL postBuild();
+	/*virtual*/ BOOL postBuild() override;
 	/*virtual*/ void reset();
 
 	void setObjectID(const LLUUID& object_id);
 	void setItemID(const LLUUID& item_id);
-	void setEditMode(BOOL edit);
+    void setParentFloater(LLFloater* parent); // For simplicity
 
 	const LLUUID& getObjectID() const;
 	const LLUUID& getItemID() const;
 
 	// if received update and item id (from callback) matches internal ones, update UI
 	void onUpdateCallback(const LLUUID& item_id, S32 received_update_id);
+    
+    void changed(U32 mask) override;
+    void dirty();
+    
+    static void onIdle( void* user_data );
+    void updateOwnerName(const LLUUID& owner_id, const LLAvatarName& owner_name, const LLStyle::Params& style_params);
+    void updateCreatorName(const LLUUID& creator_id, const LLAvatarName& creator_name, const LLStyle::Params& style_params);
 
 protected:
-	/*virtual*/ void refresh();
-	/*virtual*/ void save();
+	void refresh() override;
+	void save();
 
 	LLViewerInventoryItem* findItem() const;
 	LLViewerObject*  findObject() const;
@@ -75,14 +88,23 @@ class LLSidepanelItemInfo : public LLSidepanelInventorySubpanel
 	void startObjectInventoryObserver();
 	void stopObjectInventoryObserver();
 	void setPropertiesFieldsEnabled(bool enabled);
+    
+    boost::signals2::connection mOwnerCacheConnection;
+    boost::signals2::connection mCreatorCacheConnection;
 
 	LLUUID mItemID; 	// inventory UUID for the inventory item.
 	LLUUID mObjectID; 	// in-world task UUID, or null if in agent inventory.
-	LLItemPropertiesObserver* mPropertiesObserver; // for syncing changes to item
 	LLObjectInventoryObserver* mObjectInventoryObserver; // for syncing changes to items inside an object
 
 	// We can send multiple properties updates simultaneously, make sure only last response counts and there won't be a race condition.
 	S32 mUpdatePendingId;
+    bool mIsDirty;         // item properties need to be updated
+    LLFloater* mParentFloater;
+
+    LLUICtrl* mChangeThumbnailBtn;
+    LLIconCtrl* mItemTypeIcon;
+    LLTextBox* mLabelOwnerName;
+    LLTextBox* mLabelCreatorName;
 
 	//
 	// UI Elements
@@ -94,6 +116,7 @@ class LLSidepanelItemInfo : public LLSidepanelInventorySubpanel
 	void 						onCommitDescription();
 	void 						onCommitPermissions(LLUICtrl* ctrl);
 	void 						updatePermissions();
+    void 						onEditThumbnail();
 	void 						onCommitSaleInfo(LLUICtrl* ctrl);
 	void 						updateSaleInfo();
 	void 						onCommitChanges(LLPointer<LLViewerInventoryItem> item);
diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp
index 6ae9f0ac2304b3ed8310378e5d7ede0fd8b6a35c..38a84a30d1f8ccbaf60e61f6da7d3eb64c5162e3 100644
--- a/indra/newview/llsidepaneltaskinfo.cpp
+++ b/indra/newview/llsidepaneltaskinfo.cpp
@@ -42,6 +42,7 @@
 #include "llresmgr.h"
 #include "lltextbox.h"
 #include "llbutton.h"
+#include "llcallbacklist.h"
 #include "llcheckboxctrl.h"
 #include "llviewerobject.h"
 #include "llselectmgr.h"
@@ -70,10 +71,6 @@
 #include "rlvhandler.h"
 // [/RLVa:KB]
 
-extern bool can_set_export(const U32& base, const U32& own, const U32& next);
-extern bool perms_allow_export(const LLPermissions& perms);
-extern bool is_asset_exportable(const LLUUID& asset_id);
-
 ///----------------------------------------------------------------------------
 /// Class llsidepaneltaskinfo
 ///----------------------------------------------------------------------------
@@ -84,9 +81,11 @@ static LLPanelInjector<LLSidepanelTaskInfo> t_task_info("sidepanel_task_info");
 
 // Default constructor
 LLSidepanelTaskInfo::LLSidepanelTaskInfo()
+    : mVisibleDebugPermissions(true) // space was allocated by default
 {
 	setMouseOpaque(FALSE);
     mSelectionUpdateSlot = LLSelectMgr::instance().mUpdateSignal.connect(boost::bind(&LLSidepanelTaskInfo::refreshAll, this));
+    gIdleCallbacks.addFunction(&LLSidepanelTaskInfo::onIdle, (void*)this);
 }
 
 
@@ -94,6 +93,7 @@ LLSidepanelTaskInfo::~LLSidepanelTaskInfo()
 {
 	if (sActivePanel == this)
 		sActivePanel = NULL;
+    gIdleCallbacks.deleteFunction(&LLSidepanelTaskInfo::onIdle, (void*)this);
 
     if (mSelectionUpdateSlot.connected())
     {
@@ -104,8 +104,6 @@ LLSidepanelTaskInfo::~LLSidepanelTaskInfo()
 // virtual
 BOOL LLSidepanelTaskInfo::postBuild()
 {
-	LLSidepanelInventorySubpanel::postBuild();
-
 	mOpenBtn = getChild<LLButton>("open_btn");
 	mOpenBtn->setClickedCallback(boost::bind(&LLSidepanelTaskInfo::onOpenButtonClicked, this));
 	mPayBtn = getChild<LLButton>("pay_btn");
@@ -128,7 +126,6 @@ BOOL LLSidepanelTaskInfo::postBuild()
 	childSetAction("button deed",								&LLSidepanelTaskInfo::onClickDeedToGroup,this);
 	childSetCommitCallback("checkbox allow everyone move",		&LLSidepanelTaskInfo::onCommitEveryoneMove,this);
 	childSetCommitCallback("checkbox allow everyone copy",		&LLSidepanelTaskInfo::onCommitEveryoneCopy,this);
-	childSetCommitCallback("checkbox allow export",				&LLSidepanelTaskInfo::onCommitNextOwnerExport,this);
 	childSetCommitCallback("checkbox for sale",					&LLSidepanelTaskInfo::onCommitSaleInfo,this);
 	childSetCommitCallback("sale type",							&LLSidepanelTaskInfo::onCommitSaleType,this);
 	childSetCommitCallback("Edit Cost", 						&LLSidepanelTaskInfo::onCommitSaleInfo, this);
@@ -151,7 +148,6 @@ BOOL LLSidepanelTaskInfo::postBuild()
 	mDAButtonDeed = getChildView("button deed");
 	mDACheckboxAllowEveryoneMove = getChild<LLUICtrl>("checkbox allow everyone move");
 	mDACheckboxAllowEveryoneCopy = getChild<LLUICtrl>("checkbox allow everyone copy");
-	mDACheckboxAllowExport = getChild<LLUICtrl>("checkbox allow export");
 	mDACheckboxNextOwnerCanModify = getChild<LLUICtrl>("checkbox next owner can modify");
 	mDACheckboxNextOwnerCanCopy = getChild<LLUICtrl>("checkbox next owner can copy");
 	mDACheckboxNextOwnerCanTransfer = getChild<LLUICtrl>("checkbox next owner can transfer");
@@ -162,12 +158,12 @@ BOOL LLSidepanelTaskInfo::postBuild()
 	mDALabelClickAction = getChildView("label click action");
 	mDAComboClickAction = getChild<LLComboBox>("clickaction");
 	mDAPathfindingAttributes = getChild<LLTextBase>("pathfinding_attributes_value");
-	mDAB = getChildView("B:");
-	mDAO = getChildView("O:");
-	mDAG = getChildView("G:");
-	mDAE = getChildView("E:");
-	mDAN = getChildView("N:");
-	mDAF = getChildView("F:");
+	mDAB = getChild<LLUICtrl>("B:");
+	mDAO = getChild<LLUICtrl>("O:");
+	mDAG = getChild<LLUICtrl>("G:");
+	mDAE = getChild<LLUICtrl>("E:");
+	mDAN = getChild<LLUICtrl>("N:");
+	mDAF = getChild<LLUICtrl>("F:");
 	
 	return TRUE;
 }
@@ -217,12 +213,22 @@ void LLSidepanelTaskInfo::disableAll()
 
 	disablePermissions();
 
-	mDAB->setVisible(FALSE);
-	mDAO->setVisible(FALSE);
-	mDAG->setVisible(FALSE);
-	mDAE->setVisible(FALSE);
-	mDAN->setVisible(FALSE);
-	mDAF->setVisible(FALSE);
+    if (mVisibleDebugPermissions)
+    {
+        mDAB->setVisible(FALSE);
+        mDAO->setVisible(FALSE);
+        mDAG->setVisible(FALSE);
+        mDAE->setVisible(FALSE);
+        mDAN->setVisible(FALSE);
+        mDAF->setVisible(FALSE);
+
+        LLFloater* parent_floater = gFloaterView->getParentFloater(this);
+        LLRect parent_rect = parent_floater->getRect();
+        LLRect debug_rect = mDAB->getRect();
+        // use double the debug rect for padding (since it isn't trivial to extract top_pad)
+        parent_floater->reshape(parent_rect.getWidth(), parent_rect.getHeight() - (debug_rect.getHeight() * 2));
+        mVisibleDebugPermissions = false;
+    }
 
 	mOpenBtn->setEnabled(FALSE);
 	mPayBtn->setEnabled(FALSE);
@@ -239,9 +245,6 @@ void LLSidepanelTaskInfo::disablePermissions()
 	mDACheckboxAllowEveryoneCopy->setValue(FALSE);
 	mDACheckboxAllowEveryoneCopy->setEnabled(FALSE);
 
-	mDACheckboxAllowExport->setValue(FALSE);
-	mDACheckboxAllowExport->setEnabled(FALSE);
-
 	//Next owner can:
 	mDACheckboxNextOwnerCanModify->setValue(FALSE);
 	mDACheckboxNextOwnerCanModify->setEnabled(FALSE);
@@ -272,6 +275,8 @@ void LLSidepanelTaskInfo::disablePermissions()
 
 void LLSidepanelTaskInfo::refresh()
 {
+    mIsDirty = false;
+    
 	LLButton* btn_deed_to_group = mDeedBtn; 
 	if (btn_deed_to_group)
 	{	
@@ -313,7 +318,6 @@ void LLSidepanelTaskInfo::refresh()
 	}
 
 	// figure out a few variables
-	const bool export_perm_supported = objectp->getRegion() && objectp->getRegion()->getRegionAllowsExport();
 	const BOOL is_one_object = (object_count == 1);
 	
 	// BUG: fails if a root and non-root are both single-selected.
@@ -646,29 +650,23 @@ void LLSidepanelTaskInfo::refresh()
 	
 	if (gSavedSettings.getBOOL("DebugPermissions") )
 	{
-		if (valid_base_perms)
-		{
-			std::string perm_string = mask_to_string(base_mask_on);
-			if (!export_perm_supported && base_mask_on & PERM_EXPORT) // Hide Export when not available
-				perm_string.erase(perm_string.find_last_of("E"));
-			getChild<LLUICtrl>("B:")->setValue("B: " + perm_string);
-			getChildView("B:")->setVisible(TRUE);
-			perm_string = mask_to_string(owner_mask_on);
-			if (!export_perm_supported && owner_mask_on & PERM_EXPORT) // Hide Export when not available
-				perm_string.erase(perm_string.find_last_of("E"));
-			getChild<LLUICtrl>("O:")->setValue("O: " + perm_string);
-			getChildView("O:")->setVisible(TRUE);
-			getChild<LLUICtrl>("G:")->setValue("G: " + mask_to_string(group_mask_on));
-			getChildView("G:")->setVisible(TRUE);
-			perm_string = mask_to_string(everyone_mask_on);
-			if (!export_perm_supported && everyone_mask_on & PERM_EXPORT) // Hide Export when not available
-				perm_string.erase(perm_string.find_last_of("E"));
-			getChild<LLUICtrl>("E:")->setValue("E: " + perm_string);
-			getChildView("E:")->setVisible(TRUE);
-		
-			getChild<LLUICtrl>("N:")->setValue("N: " + mask_to_string(next_owner_mask_on));
-			getChildView("N:")->setVisible(							TRUE);
-		}
+        if (valid_base_perms)
+        {
+            mDAB->setValue("B: " + mask_to_string(base_mask_on));
+            mDAB->setVisible(							TRUE);
+
+            mDAO->setValue("O: " + mask_to_string(owner_mask_on));
+            mDAO->setVisible(							TRUE);
+
+            mDAG->setValue("G: " + mask_to_string(group_mask_on));
+            mDAG->setVisible(							TRUE);
+
+            mDAE->setValue("E: " + mask_to_string(everyone_mask_on));
+            mDAE->setVisible(							TRUE);
+
+            mDAN->setValue("N: " + mask_to_string(next_owner_mask_on));
+            mDAN->setVisible(							TRUE);
+        }
 
 		U32 flag_mask = 0x0;
 		if (objectp->permMove()) 		flag_mask |= PERM_MOVE;
@@ -676,18 +674,35 @@ void LLSidepanelTaskInfo::refresh()
 		if (objectp->permCopy()) 		flag_mask |= PERM_COPY;
 		if (objectp->permTransfer()) 	flag_mask |= PERM_TRANSFER;
 
-		getChild<LLUICtrl>("F:")->setValue("F:" + mask_to_string(flag_mask));
-		getChildView("F:")->setVisible(								TRUE);
-	}
-	else
-	{
-		getChildView("B:")->setVisible(								FALSE);
-		getChildView("O:")->setVisible(								FALSE);
-		getChildView("G:")->setVisible(								FALSE);
-		getChildView("E:")->setVisible(								FALSE);
-		getChildView("N:")->setVisible(								FALSE);
-		getChildView("F:")->setVisible(								FALSE);
-	}
+        mDAF->setValue("F:" + mask_to_string(flag_mask));
+        mDAF->setVisible(TRUE);
+
+        if (!mVisibleDebugPermissions)
+        {
+            LLFloater* parent_floater = gFloaterView->getParentFloater(this);
+            LLRect parent_rect = parent_floater->getRect();
+            LLRect debug_rect = mDAB->getRect();
+            // use double the debug rect for padding (since it isn't trivial to extract top_pad)
+            parent_floater->reshape(parent_rect.getWidth(), parent_rect.getHeight() + (debug_rect.getHeight() * 2));
+            mVisibleDebugPermissions = true;
+        }
+    }
+    else if (mVisibleDebugPermissions)
+    {
+        mDAB->setVisible(FALSE);
+        mDAO->setVisible(FALSE);
+        mDAG->setVisible(FALSE);
+        mDAE->setVisible(FALSE);
+        mDAN->setVisible(FALSE);
+        mDAF->setVisible(FALSE);
+
+        LLFloater* parent_floater = gFloaterView->getParentFloater(this);
+        LLRect parent_rect = parent_floater->getRect();
+        LLRect debug_rect = mDAB->getRect();
+        // use double the debug rect for padding (since it isn't trivial to extract top_pad)
+        parent_floater->reshape(parent_rect.getWidth(), parent_rect.getHeight() - (debug_rect.getHeight() * 2));
+        mVisibleDebugPermissions = false;
+    }
 
 	BOOL has_change_perm_ability = FALSE;
 	BOOL has_change_sale_ability = FALSE;
@@ -722,44 +737,6 @@ void LLSidepanelTaskInfo::refresh()
 		getChildView("checkbox allow everyone copy")->setEnabled(FALSE);
 	}
 
-	if (export_perm_supported && self_owned && mCreatorID == mOwnerID
-		&& can_set_export(base_mask_on, owner_mask_on, next_owner_mask_on))
-	{
-		bool can_export = false;
-		LLInventoryObject::object_list_t objects;
-		objectp->getInventoryContents(objects);
-		if (!objects.empty())
-		{
-			for (LLInventoryObject::object_list_t::iterator i = objects.begin(); i != objects.end(); ++i) //The object's inventory must have EXPORT.
-			{
-				LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(i->get()); //getInventoryContents() filters out categories, static_cast.
-				can_export = perms_allow_export(item->getPermissions());
-				if (!can_export) break;
-			}
-		}
-		else
-			can_export = true;
-
-		if(can_export)
-		{
-			for (U8 i = 0; i < objectp->getNumTEs(); ++i) // Can the textures be exported?
-			{
-				if (LLTextureEntry* texture = objectp->getTE(i))
-				{
-					can_export = is_asset_exportable(texture->getID());
-					if(!can_export) break;
-				}
-			}
-		}
-		mDACheckboxAllowExport->setEnabled(can_export);
-		mDACheckboxAllowExport->setVisible(true);
-	}
-	else
-	{
-		mDACheckboxAllowExport->setEnabled(false);
-		mDACheckboxAllowExport->setVisible(export_perm_supported);
-	}
-
 	if (has_change_sale_ability && (owner_mask_on & PERM_TRANSFER))
 	{
 		getChildView("checkbox for sale")->setEnabled(can_transfer || (!can_transfer && num_for_sale));
@@ -768,10 +745,9 @@ void LLSidepanelTaskInfo::refresh()
 		getChild<LLUICtrl>("checkbox for sale")->setTentative( 				is_for_sale_mixed);
 		getChildView("sale type")->setEnabled(num_for_sale && can_transfer && !is_sale_price_mixed);
 
-		bool no_export = everyone_mask_off & PERM_EXPORT; // Next owner perms can't be changed if set
-		getChildView("checkbox next owner can modify")->setEnabled(no_export && base_mask_on & PERM_MODIFY);
-		getChildView("checkbox next owner can copy")->setEnabled(no_export && base_mask_on & PERM_COPY);
-		getChildView("checkbox next owner can transfer")->setEnabled(no_export && next_owner_mask_on & PERM_COPY);
+		getChildView("checkbox next owner can modify")->setEnabled(base_mask_on & PERM_MODIFY);
+		getChildView("checkbox next owner can copy")->setEnabled(base_mask_on & PERM_COPY);
+		getChildView("checkbox next owner can transfer")->setEnabled(next_owner_mask_on & PERM_COPY);
 	}
 	else 
 	{
@@ -840,31 +816,6 @@ void LLSidepanelTaskInfo::refresh()
 			getChild<LLUICtrl>("checkbox allow everyone copy")->setValue(TRUE);
 			getChild<LLUICtrl>("checkbox allow everyone copy")->setTentative(	TRUE);
 		}
-
-		// Export == next owner cannot export
-		if (export_perm_supported)
-		{
-			if(everyone_mask_on & PERM_EXPORT)
-			{
-				mDACheckboxAllowExport->setValue(TRUE);
-				mDACheckboxAllowExport->setTentative(	FALSE);
-			}
-			else if(everyone_mask_off & PERM_EXPORT)
-			{
-				mDACheckboxAllowExport->setValue(FALSE);
-				mDACheckboxAllowExport->setTentative(FALSE);
-			}
-			else
-			{
-				mDACheckboxAllowExport->setValue(TRUE);
-				mDACheckboxAllowExport->setTentative(TRUE);
-			}
-		}
-		else
-		{
-			mDACheckboxAllowExport->setValue(FALSE);
-			mDACheckboxAllowExport->setTentative(FALSE);
-		}
 	}
 
 	if (valid_next_perms)
@@ -974,34 +925,6 @@ void LLSidepanelTaskInfo::refresh()
 	getChildView("label click action")->setEnabled(is_perm_modify && is_nonpermanent_enforced && all_volume);
 	getChildView("clickaction")->setEnabled(is_perm_modify && is_nonpermanent_enforced && all_volume);
 
-	if (!getIsEditing())
-	{
-		const std::string no_item_names[] = 
-			{
-				"Object Name",
-				"Object Description",
-				"button set group",
-				"checkbox share with group",
-				"button deed",
-				"checkbox allow everyone move",
-				"checkbox allow everyone copy",
-				"checkbox allow export",
-				"checkbox for sale",
-				"sale type",
-				"Edit Cost",
-				"checkbox next owner can modify",
-				"checkbox next owner can copy",
-				"checkbox next owner can transfer",
-				"clickaction",
-				"search_check",
-				"perm_modify",
-				"Group Name",
-			};
-		for (size_t t=0; t<LL_ARRAY_SIZE(no_item_names); ++t)
-		{
-			getChildView(no_item_names[t])->setEnabled(	FALSE);
-		}
-	}
 	updateVerbs();
 }
 
@@ -1136,11 +1059,6 @@ void LLSidepanelTaskInfo::onCommitNextOwnerTransfer(LLUICtrl* ctrl, void* data)
 	onCommitPerm(ctrl, data, PERM_NEXT_OWNER, PERM_TRANSFER);
 }
 
-void LLSidepanelTaskInfo::onCommitNextOwnerExport(LLUICtrl* ctrl, void* data)
-{
-	onCommitPerm(ctrl, data, PERM_EVERYONE, PERM_EXPORT);
-}
-
 // static
 void LLSidepanelTaskInfo::onCommitName(LLUICtrl*, void* data)
 {
@@ -1319,16 +1237,6 @@ void LLSidepanelTaskInfo::onCommitIncludeInSearch(LLUICtrl* ctrl, void* data)
 // virtual
 void LLSidepanelTaskInfo::updateVerbs()
 {
-	LLSidepanelInventorySubpanel::updateVerbs();
-
-	/*
-	mOpenBtn->setVisible(!getIsEditing());
-	mPayBtn->setVisible(!getIsEditing());
-	mBuyBtn->setVisible(!getIsEditing());
-	//const LLViewerObject *obj = getFirstSelectedObject();
-	//mEditBtn->setEnabled(obj && obj->permModify());
-	*/
-
 	LLSafeHandle<LLObjectSelection> object_selection = LLSelectMgr::getInstance()->getSelection();
 	const BOOL any_selected = (object_selection->getNumNodes() > 0);
 
@@ -1372,7 +1280,6 @@ void LLSidepanelTaskInfo::save()
 	onCommitGroupShare(getChild<LLCheckBoxCtrl>("checkbox share with group"), this);
 	onCommitEveryoneMove(getChild<LLCheckBoxCtrl>("checkbox allow everyone move"), this);
 	onCommitEveryoneCopy(getChild<LLCheckBoxCtrl>("checkbox allow everyone copy"), this);
-	onCommitNextOwnerExport(getChild<LLCheckBoxCtrl>("checkbox allow export"), this);
 	onCommitNextOwnerModify(getChild<LLCheckBoxCtrl>("checkbox next owner can modify"), this);
 	onCommitNextOwnerCopy(getChild<LLCheckBoxCtrl>("checkbox next owner can copy"), this);
 	onCommitNextOwnerTransfer(getChild<LLCheckBoxCtrl>("checkbox next owner can transfer"), this);
@@ -1414,6 +1321,23 @@ LLSidepanelTaskInfo* LLSidepanelTaskInfo::getActivePanel()
 	return sActivePanel;
 }
 
+void LLSidepanelTaskInfo::dirty()
+{
+    mIsDirty = true;
+}
+
+// static
+void LLSidepanelTaskInfo::onIdle( void* user_data )
+{
+    LLSidepanelTaskInfo* self = reinterpret_cast<LLSidepanelTaskInfo*>(user_data);
+
+    if( self->mIsDirty )
+    {
+        self->refresh();
+        self->mIsDirty = false;
+    }
+}
+
 LLViewerObject* LLSidepanelTaskInfo::getObject()
 {
 	if (!mObject->isDead())
diff --git a/indra/newview/llsidepaneltaskinfo.h b/indra/newview/llsidepaneltaskinfo.h
index 99a983cf677d5251962a19cdf720453661df4b7b..2baafc67e7cf61d55a428451f165de8573b5c16a 100644
--- a/indra/newview/llsidepaneltaskinfo.h
+++ b/indra/newview/llsidepaneltaskinfo.h
@@ -27,8 +27,8 @@
 #ifndef LL_LLSIDEPANELTASKINFO_H
 #define LL_LLSIDEPANELTASKINFO_H
 
-#include "llsidepanelinventorysubpanel.h"
 #include "lluuid.h"
+#include "llpanel.h"
 #include "llselectmgr.h"
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -43,14 +43,14 @@ class LLNameBox;
 class LLViewerObject;
 class LLTextBase;
 
-class LLSidepanelTaskInfo : public LLSidepanelInventorySubpanel
+class LLSidepanelTaskInfo : public LLPanel
 {
 public:
 	LLSidepanelTaskInfo();
 	virtual ~LLSidepanelTaskInfo();
 
-	/*virtual*/	BOOL postBuild();
-	/*virtual*/ void onVisibilityChange ( BOOL new_visibility );
+	BOOL postBuild() override;
+	void onVisibilityChange ( BOOL new_visibility ) override;
 
 	void setObjectSelection(LLObjectSelectionHandle selection);
 
@@ -58,10 +58,12 @@ class LLSidepanelTaskInfo : public LLSidepanelInventorySubpanel
 	LLViewerObject* getFirstSelectedObject();
 
 	static LLSidepanelTaskInfo *getActivePanel();
+    void dirty();
+    static void onIdle( void* user_data );
 protected:
-	/*virtual*/ void refresh();	// refresh all labels as needed
-	/*virtual*/ void save();
-	/*virtual*/ void updateVerbs();
+	void refresh() override;	// refresh all labels as needed
+	void save();
+	void updateVerbs();
 
 	void refreshAll(); // ignore current keyboard focus and update all fields
 
@@ -82,7 +84,6 @@ class LLSidepanelTaskInfo : public LLSidepanelInventorySubpanel
 	static void onCommitNextOwnerModify(LLUICtrl* ctrl, void* data);
 	static void onCommitNextOwnerCopy(LLUICtrl* ctrl, void* data);
 	static void onCommitNextOwnerTransfer(LLUICtrl* ctrl, void* data);
-	static void onCommitNextOwnerExport(LLUICtrl* ctrl, void* data);
 	
 	static void onCommitName(LLUICtrl* ctrl, void* data);
 	static void onCommitDesc(LLUICtrl* ctrl, void* data);
@@ -104,6 +105,8 @@ class LLSidepanelTaskInfo : public LLSidepanelInventorySubpanel
 	LLUUID			mCreatorID;
 	LLUUID			mOwnerID;
 	LLUUID			mLastOwnerID;
+    
+    bool mIsDirty;
 
 protected:
 	void 						onOpenButtonClicked();
@@ -122,6 +125,10 @@ class LLSidepanelTaskInfo : public LLSidepanelInventorySubpanel
 private:
 	LLPointer<LLViewerObject>	mObject;
 	LLObjectSelectionHandle		mObjectSelection;
+
+    // mVisibleDebugPermissions doesn't nessesarily matche state
+    // of viewes and is primarily for floater resize
+    bool                        mVisibleDebugPermissions;
 	static LLSidepanelTaskInfo* sActivePanel;
 	
 private:
@@ -139,7 +146,6 @@ class LLSidepanelTaskInfo : public LLSidepanelInventorySubpanel
 	LLView*		mDAButtonDeed;
 	LLUICtrl*	mDACheckboxAllowEveryoneMove;
 	LLUICtrl*	mDACheckboxAllowEveryoneCopy;
-	LLUICtrl*	mDACheckboxAllowExport;
 	LLUICtrl*	mDACheckboxNextOwnerCanModify;
 	LLUICtrl*	mDACheckboxNextOwnerCanCopy;
 	LLUICtrl*	mDACheckboxNextOwnerCanTransfer;
@@ -150,12 +156,12 @@ class LLSidepanelTaskInfo : public LLSidepanelInventorySubpanel
 	LLView*		mDALabelClickAction;
 	LLComboBox*	mDAComboClickAction;
 	LLTextBase* mDAPathfindingAttributes;
-	LLView*		mDAB;
-	LLView*		mDAO;
-	LLView*		mDAG;
-	LLView*		mDAE;
-	LLView*		mDAN;
-	LLView*		mDAF;
+    LLUICtrl*   mDAB;
+    LLUICtrl*   mDAO;
+    LLUICtrl*   mDAG;
+    LLUICtrl*   mDAE;
+    LLUICtrl*   mDAN;
+    LLUICtrl*   mDAF;
 
     boost::signals2::connection mSelectionUpdateSlot;
 };
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index 492464e9aa5056fc5568e20998b4f72b9c92b8a7..50c57e8d1208b830b068811ddc8e3e5f698476e9 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -52,6 +52,7 @@
 #include "llviewercontrol.h"
 #include "llviewermenufile.h"	// upload_new_resource()
 #include "llviewerstats.h"
+#include "llviewertexturelist.h"
 #include "llwindow.h"
 #include "llworld.h"
 #include <boost/filesystem.hpp>
@@ -898,6 +899,11 @@ LLPointer<LLImageRaw> LLSnapshotLivePreview::getEncodedImage()
     return mPreviewImageEncoded;
 }
 
+bool LLSnapshotLivePreview::createUploadFile(const std::string &out_filename, const S32 max_image_dimentions, const S32 min_image_dimentions)
+{
+    return LLViewerTextureList::createUploadFile(mPreviewImage, out_filename, max_image_dimentions, min_image_dimentions);
+}
+
 // We actually estimate the data size so that we do not require actual compression when showing the preview
 // Note : whenever formatted image is computed, mDataSize will be updated to reflect the true size
 void LLSnapshotLivePreview::estimateDataSize()
diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h
index 1f81307976797f0ac52a2b3641b0515a0d35cbb0..6e38a957b41df23b6f38529dc0cf3131cc10ddb9 100644
--- a/indra/newview/llsnapshotlivepreview.h
+++ b/indra/newview/llsnapshotlivepreview.h
@@ -106,6 +106,7 @@ class LLSnapshotLivePreview : public LLView
 
 	LLPointer<LLImageFormatted>	getFormattedImage();
 	LLPointer<LLImageRaw>		getEncodedImage();
+    bool createUploadFile(const std::string &out_file, const S32 max_image_dimentions, const S32 min_image_dimentions);
 
 	/// Sets size of preview thumbnail image and the surrounding rect.
 	void setThumbnailPlaceholderRect(const LLRect& rect) {mThumbnailPlaceholderRect = rect; }
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 535b3b0047e4ac1445a333ca81e06995a843a797..e9debae1d27f084c395b78dea4d9950a1829bce3 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -267,7 +267,7 @@ static bool mLoginStatePastUI = false;
 static bool mBenefitsSuccessfullyInit = false;
 
 const F32 STATE_AGENT_WAIT_TIMEOUT = 240; //seconds
-const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3; // Give region 3 chances
+const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_ABORT = 4; // Give region 4 chances
 
 std::unique_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState"));
 std::unique_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener());
@@ -1471,11 +1471,18 @@ bool idle_startup()
 		else
 		{
 			U32 num_retries = regionp->getNumSeedCapRetries();
-            if (num_retries > MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN)
+            if (num_retries > MAX_SEED_CAP_ATTEMPTS_BEFORE_ABORT)
             {
-                // Region will keep trying to get capabilities,
-                // but for now continue as if caps were granted
-                LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED);
+                LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL;
+                if (gRememberPassword)
+                {
+                    LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status);
+                }
+                else
+                {
+                    LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status);
+                }
+                reset_login();
             }
 			else if (num_retries > 0)
 			{
@@ -1988,6 +1995,34 @@ bool idle_startup()
 		
         LLInventoryModelBackgroundFetch::instance().start();
 		gInventory.createCommonSystemCategories();
+        LLStartUp::setStartupState(STATE_INVENTORY_CALLBACKS );
+        display_startup();
+
+        return FALSE;
+    }
+
+    //---------------------------------------------------------------------
+    // STATE_INVENTORY_CALLBACKS 
+    //---------------------------------------------------------------------
+    if (STATE_INVENTORY_CALLBACKS  == LLStartUp::getStartupState())
+    {
+        if (!LLInventoryModel::isSysFoldersReady())
+        {
+            display_startup();
+            return FALSE;
+        }
+        LLInventoryModelBackgroundFetch::instance().start();
+        LLUUID cof_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+        LLViewerInventoryCategory* cof = gInventory.getCategory(cof_id);
+        if (cof
+            && cof->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
+        {
+            // Special case, dupplicate request prevention.
+            // Cof folder will be requested via FetchCOF
+            // in appearance manager, prevent recursive fetch
+            cof->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE);
+        }
+
 
 		// It's debatable whether this flag is a good idea - sets all
 		// bits, and in general it isn't true that inventory
@@ -2011,9 +2046,10 @@ bool idle_startup()
 
 		if (gSavedSettings.getBOOL("LocalInventoryEnabled"))
  		{
-			gLocalInventory = gInventory.createNewCategory(LLUUID::null,
+			gInventory.createNewCategory(LLUUID::null,
 														   LLFolderType::FT_LOCAL, 
-				                                           LOCAL_INVENTORY_FOLDER_NAME);
+				                                           LOCAL_INVENTORY_FOLDER_NAME,
+				[](const LLUUID& new_local_id) {gLocalInventory = new_local_id; });
  		}
 		// Create the inventory views
 		LL_INFOS() << "Creating Inventory Views" << LL_ENDL;
@@ -2262,7 +2298,7 @@ bool idle_startup()
 			{
 				gAgentWearables.sendDummyAgentWearablesUpdate();
 			}
-			callAfterCategoryFetch(LLAppearanceMgr::instance().getCOF(), set_flags_and_update_appearance);
+            callAfterCOFFetch(set_flags_and_update_appearance);
 		}
 
 		display_startup();
@@ -2884,7 +2920,7 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
 	// Not going through the processAgentInitialWearables path, so need to set this here.
 	LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
 	// Initiate creation of COF, since we're also bypassing that.
-	gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+	gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT);
 	
 	ESex gender;
 	if (gender_name == "male")
@@ -2937,8 +2973,15 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
 		bool do_append = false;
 		LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
 		// Need to fetch cof contents before we can wear.
-		callAfterCategoryFetch(LLAppearanceMgr::instance().getCOF(),
+        if (do_copy)
+        {
+            callAfterCategoryFetch(LLAppearanceMgr::instance().getCOF(),
 							   boost::bind(&LLAppearanceMgr::wearInventoryCategory, LLAppearanceMgr::getInstance(), cat, do_copy, do_append));
+        }
+        else
+        {
+            callAfterCategoryLinksFetch(cat_id, boost::bind(&LLAppearanceMgr::wearInventoryCategory, LLAppearanceMgr::getInstance(), cat, do_copy, do_append));
+        }
 		LL_DEBUGS() << "initial outfit category id: " << cat_id << LL_ENDL;
 	}
 
@@ -2994,6 +3037,7 @@ std::string LLStartUp::startupStateToString(EStartupState state)
 		RTNENUM( STATE_AGENT_SEND );
 		RTNENUM( STATE_AGENT_WAIT );
 		RTNENUM( STATE_INVENTORY_SEND );
+        RTNENUM(STATE_INVENTORY_CALLBACKS );
 		RTNENUM( STATE_MISC );
 		RTNENUM( STATE_PRECACHE );
 		RTNENUM( STATE_WEARABLES_WAIT );
@@ -3048,6 +3092,11 @@ void reset_login()
 	LLFloaterReg::hideVisibleInstances();
     LLStartUp::setStartupState( STATE_BROWSER_INIT );
 
+    if (LLVoiceClient::instanceExists())
+    {
+        LLVoiceClient::getInstance()->terminate();
+    }
+
     // Clear any verified certs and verify them again on next login
     // to ensure cert matches server instead of just getting reused
     LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore("");
@@ -3898,7 +3947,9 @@ bool process_login_success_response(U32& first_sim_size_x, U32& first_sim_size_y
 
 
 	// Only save mfa_hash for future logins if the user wants their info remembered.
-	if(response.has("mfa_hash") && gSavedSettings.getBOOL("RememberUser") && gSavedSettings.getBOOL("RememberPassword"))
+	if(response.has("mfa_hash")
+       && gSavedSettings.getBOOL("RememberUser")
+       && LLLoginInstance::getInstance()->saveMFA())
 	{
 		std::string grid(LLGridManager::getInstance()->getGridId());
 		std::string user_id(gUserCredential->userID());
@@ -3906,6 +3957,13 @@ bool process_login_success_response(U32& first_sim_size_x, U32& first_sim_size_y
 		// TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically
 		gSecAPIHandler->syncProtectedMap();
 	}
+    else if (!LLLoginInstance::getInstance()->saveMFA())
+    {
+        std::string grid(LLGridManager::getInstance()->getGridId());
+        std::string user_id(gUserCredential->userID());
+        gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid, user_id);
+        gSecAPIHandler->syncProtectedMap();
+    }
 
 	bool success = false;
 	// JC: gesture loading done below, when we have an asset system
diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h
index 8b627a4630a54079e3e84675c5617ca6eae857e5..4b6f3b38498d297b7951c48d5bd5efd54bc51997 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -70,6 +70,7 @@ typedef enum {
 	STATE_AGENT_SEND,				// Connect to a region
 	STATE_AGENT_WAIT,				// Wait for region
 	STATE_INVENTORY_SEND,			// Do inventory transfer
+	STATE_INVENTORY_CALLBACKS,		// Wait for missing system folders and register callbacks
 	STATE_MISC,						// Do more things (set bandwidth, start audio, save location, etc)
 	STATE_PRECACHE,					// Wait a bit for textures to download
 	STATE_WEARABLES_WAIT,			// Wait for clothing to download
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 8d0cbe01cd4c9170fe02f395528a413ab7fbef11..dbf452ae70dc0920c1ed9b5c615983180170f1d3 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -160,6 +160,9 @@ LLFloaterTexturePicker::LLFloaterTexturePicker(
 	mSelectedItemPinned( FALSE ),
 	mCanApply(true),
 	mCanPreview(true),
+    mLimitsSet(false),
+    mMaxDim(S32_MAX),
+    mMinDim(0),
 	mPreviewSettingChanged(false),
 	mOnFloaterCommitCallback(NULL),
 	mOnFloaterCloseCallback(NULL),
@@ -262,8 +265,9 @@ void LLFloaterTexturePicker::stopUsingPipette()
 	}
 }
 
-void LLFloaterTexturePicker::updateImageStats()
+bool LLFloaterTexturePicker::updateImageStats()
 {
+    bool result = true;
     if (mGLTFMaterial.notNull())
     {
         S32 width = 0;
@@ -319,14 +323,31 @@ void LLFloaterTexturePicker::updateImageStats()
 	else if (mTexturep.notNull())
 	{
 		//RN: have we received header data for this image?
-		if (mTexturep->getFullWidth() > 0 && mTexturep->getFullHeight() > 0)
+        S32 width = mTexturep->getFullWidth();
+        S32 height = mTexturep->getFullHeight();
+		if (width > 0 && height > 0)
 		{
-			std::string formatted_dims = llformat("%d x %d", mTexturep->getFullWidth(),mTexturep->getFullHeight());
-			mResolutionLabel->setTextArg("[DIMENSIONS]", formatted_dims);
-			if (mOnUpdateImageStatsCallback)
-			{
-				mOnUpdateImageStatsCallback(mTexturep);
-			}
+            if ((mLimitsSet && (width != height))
+                || width < mMinDim
+                || width > mMaxDim
+                || height < mMinDim
+                || height > mMaxDim
+                )
+            {
+                std::string formatted_dims = llformat("%dx%d", width, height);
+                mResolutionWarning->setTextArg("[TEXDIM]", formatted_dims);
+                result = false;
+            }
+            else
+            {
+                std::string formatted_dims = llformat("%d x %d", width, height);
+                mResolutionLabel->setTextArg("[DIMENSIONS]", formatted_dims);
+            }
+
+            if (mOnUpdateImageStatsCallback)
+            {
+                mOnUpdateImageStatsCallback(mTexturep);
+            }
 		}
 		else
 		{
@@ -337,6 +358,21 @@ void LLFloaterTexturePicker::updateImageStats()
 	{
 		mResolutionLabel->setTextArg("[DIMENSIONS]", std::string(""));
 	}
+    mResolutionLabel->setVisible(result);
+    mResolutionWarning->setVisible(!result);
+
+    // Hide buttons and pipete to make space for mResolutionWarning
+    // Hiding buttons is suboptimal, but at the moment limited to inventory thumbnails
+    // may be this should be an info/warning icon with a tooltip?
+    S32 index = mModeSelector->getValue().asInteger();
+    if (index == 0)
+    {
+        mDefaultBtn->setVisible(result);
+        mNoneBtn->setVisible(result);
+        mBlankBtn->setVisible(result);
+        mPipetteBtn->setVisible(result);
+    }
+    return result;
 }
 
 // virtual
@@ -469,11 +505,22 @@ BOOL LLFloaterTexturePicker::postBuild()
 	mTentativeLabel = getChild<LLTextBox>("Multiple");
 
 	mResolutionLabel = getChild<LLTextBox>("size_lbl");
+    mResolutionWarning = getChild<LLTextBox>("over_limit_lbl");
 
 
-	childSetAction("Default",LLFloaterTexturePicker::onBtnSetToDefault,this);
-	childSetAction("None", LLFloaterTexturePicker::onBtnNone,this);
-	childSetAction("Blank", LLFloaterTexturePicker::onBtnBlank,this);
+    mDefaultBtn = getChild<LLButton>("Default");
+    mNoneBtn = getChild<LLButton>("None");
+    mBlankBtn = getChild<LLButton>("Blank");
+    mPipetteBtn = getChild<LLButton>("Pipette");
+    mSelectBtn = getChild<LLButton>("Select");
+    mCancelBtn = getChild<LLButton>("Cancel");
+
+    mDefaultBtn->setClickedCallback(boost::bind(LLFloaterTexturePicker::onBtnSetToDefault,this));
+    mNoneBtn->setClickedCallback(boost::bind(LLFloaterTexturePicker::onBtnNone, this));
+    mBlankBtn->setClickedCallback(boost::bind(LLFloaterTexturePicker::onBtnBlank, this));
+    mPipetteBtn->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onBtnPipette, this));
+    mSelectBtn->setClickedCallback(boost::bind(LLFloaterTexturePicker::onBtnSelect, this));
+    mCancelBtn->setClickedCallback(boost::bind(LLFloaterTexturePicker::onBtnCancel, this));
 
     mFilterEdit = getChild<LLFilterEditor>("inventory search editor");
     mFilterEdit->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onFilterEdit, this, _2));
@@ -554,12 +601,13 @@ void LLFloaterTexturePicker::draw()
 
     // This is going to spam mOnUpdateImageStatsCallback,
     // either move elsewhere or fix to cause update once per image
-	updateImageStats();
+	bool valid_dims = updateImageStats();
 
 	// if we're inactive, gray out "apply immediate" checkbox
-	getChildView("Select")->setEnabled(mActive && mCanApply);
-	getChildView("Pipette")->setEnabled(mActive);
-	getChild<LLUICtrl>("Pipette")->setValue(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance());
+	getChildView("show_folders_check")->setEnabled(mActive && mCanApplyImmediately && !mNoCopyTextureSelected);
+	mSelectBtn->setEnabled(mActive && mCanApply && valid_dims);
+	mPipetteBtn->setEnabled(mActive);
+    mPipetteBtn->setValue(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance());
 
 	//BOOL allow_copy = FALSE;
 	if( mOwner ) 
@@ -604,9 +652,9 @@ void LLFloaterTexturePicker::draw()
 			mTentativeLabel->setVisible( FALSE  );
 		}
 
-		getChildView("Default")->setEnabled(mImageAssetID != mDefaultImageAssetID || mTentative);
-		getChildView("Blank")->setEnabled((mImageAssetID != mBlankImageAssetID && mBlankImageAssetID.notNull()) || mTentative);
-		getChildView("None")->setEnabled(mAllowNoTexture && (!mImageAssetID.isNull() || mTentative));
+		mDefaultBtn->setEnabled(mImageAssetID != mDefaultImageAssetID || mTentative);
+		mBlankBtn->setEnabled((mImageAssetID != mBlankImageAssetID && mBlankImageAssetID.notNull()) || mTentative);
+		mNoneBtn->setEnabled(mAllowNoTexture && (!mImageAssetID.isNull() || mTentative));
 
 		LLFloater::draw();
 
@@ -731,17 +779,86 @@ const LLUUID& LLFloaterTexturePicker::findItemID(const LLUUID& asset_id, BOOL co
 
 void LLFloaterTexturePicker::commitIfImmediateSet()
 {
-	if (!mNoCopyTextureSelected && mOnFloaterCommitCallback && mCanApply)
+	if (!mNoCopyTextureSelected && mCanApply)
 	{
-		mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CHANGE, LLUUID::null);
+        commitCallback(LLTextureCtrl::TEXTURE_CHANGE);
 	}
 }
 
+void LLFloaterTexturePicker::commitCallback(LLTextureCtrl::ETexturePickOp op)
+{
+    if (!mOnFloaterCommitCallback)
+    {
+        return;
+    }
+    LLUUID asset_id = mImageAssetID;
+    LLUUID inventory_id;
+    LLPickerSource mode = (LLPickerSource)mModeSelector->getValue().asInteger();
+
+    switch (mode)
+    {
+        case PICKER_INVENTORY:
+            {
+                LLFolderView* root_folder = mInventoryPanel->getRootFolder();
+                if (root_folder && root_folder->getCurSelectedItem())
+                {
+                    LLFolderViewItem* last_selected = root_folder->getCurSelectedItem();
+                    LLFolderViewModelItemInventory* inv_view = static_cast<LLFolderViewModelItemInventory*>(last_selected->getViewModelItem());
+
+                    LLInventoryItem* itemp = gInventory.getItem(inv_view->getUUID());
+                    if (itemp && itemp->getAssetUUID() == mImageAssetID)
+                    {
+                        inventory_id = inv_view->getUUID();
+                    }
+                    else
+                    {
+                        mode = PICKER_UNKNOWN; // source of id unknown
+                    }
+                }
+                else
+                {
+                    mode = PICKER_UNKNOWN; // source of id unknown
+                }
+                break;
+            }
+        case PICKER_LOCAL:
+            {
+                if (!mLocalScrollCtrl->getAllSelected().empty())
+                {
+                    LLSD data = mLocalScrollCtrl->getFirstSelected()->getValue();
+                    LLUUID temp_id = data["id"];
+                    S32 asset_type = data["type"].asInteger();
+
+                    if (LLAssetType::AT_MATERIAL == asset_type)
+                    {
+                        asset_id = LLLocalGLTFMaterialMgr::getInstance()->getWorldID(temp_id);
+                    }
+                    else
+                    {
+                        asset_id = LLLocalBitmapMgr::getInstance()->getWorldID(temp_id);
+                    }
+                }
+                else
+                {
+                    asset_id = mImageAssetID;
+                    mode = PICKER_UNKNOWN; // source of id unknown
+                }
+                break;
+            }
+        case PICKER_BAKE:
+            break;
+        default:
+            mode = PICKER_UNKNOWN; // source of id unknown
+            break;
+    }
+
+    mOnFloaterCommitCallback(op, mode, asset_id, inventory_id);
+}
 void LLFloaterTexturePicker::commitCancel()
 {
 	if (!mNoCopyTextureSelected && mOnFloaterCommitCallback && mCanApply)
 	{
-		mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CANCEL, LLUUID::null);
+		mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CANCEL, PICKER_UNKNOWN, mOriginalImageAssetID, LLUUID::null);
 	}
 }
 
@@ -795,7 +912,7 @@ void LLFloaterTexturePicker::onBtnCancel(void* userdata)
 	self->setImageID( self->mOriginalImageAssetID );
 	if (self->mOnFloaterCommitCallback)
 	{
-		self->mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CANCEL, LLUUID::null);
+		self->mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CANCEL, PICKER_UNKNOWN, self->mOriginalImageAssetID, LLUUID::null);
 	}
 	self->mViewModel->resetDirty();
 	self->closeFloater();
@@ -804,30 +921,10 @@ void LLFloaterTexturePicker::onBtnCancel(void* userdata)
 // static
 void LLFloaterTexturePicker::onBtnSelect(void* userdata)
 {
-	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
-	LLUUID local_id = LLUUID::null;
-	if (self->mOwner)
-	{
-		if (self->mLocalScrollCtrl->getVisible() && !self->mLocalScrollCtrl->getAllSelected().empty())
-		{
-            LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue();
-            LLUUID temp_id = data["id"];
-            S32 asset_type = data["type"].asInteger();
-
-            if (LLAssetType::AT_MATERIAL == asset_type)
-            {
-                local_id = LLLocalGLTFMaterialMgr::getInstance()->getWorldID(temp_id);
-            }
-            else
-            {
-                local_id = LLLocalBitmapMgr::getInstance()->getWorldID(temp_id);
-            }
-		}
-	}
-	
+	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;	
 	if (self->mOnFloaterCommitCallback)
 	{
-		self->mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_SELECT, local_id);
+		self->commitCallback(LLTextureCtrl::TEXTURE_SELECT);
 	}
 	self->closeFloater();
 }
@@ -890,24 +987,28 @@ void LLFloaterTexturePicker::onModeSelect(LLUICtrl* ctrl, void *userdata)
 	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
     int index = self->mModeSelector->getValue().asInteger();
 
-	self->getChild<LLButton>("Default")->setVisible(index == 0 ? TRUE : FALSE);
-	self->getChild<LLButton>("Blank")->setVisible(index == 0 ? TRUE : FALSE);
-	self->getChild<LLButton>("None")->setVisible(index == 0 ? TRUE : FALSE);
-	self->getChild<LLFilterEditor>("inventory search editor")->setVisible(index == 0 ? TRUE : FALSE);
-	self->getChild<LLInventoryPanel>("inventory panel")->setVisible(index == 0 ? TRUE : FALSE);
+	self->mDefaultBtn->setVisible(index == PICKER_INVENTORY ? TRUE : FALSE);
+	self->mBlankBtn->setVisible(index == PICKER_INVENTORY ? TRUE : FALSE);
+	self->mNoneBtn->setVisible(index == PICKER_INVENTORY ? TRUE : FALSE);
+	self->getChild<LLFilterEditor>("inventory search editor")->setVisible(index == PICKER_INVENTORY ? TRUE : FALSE);
+	self->getChild<LLInventoryPanel>("inventory panel")->setVisible(index == PICKER_INVENTORY ? TRUE : FALSE);
+
+	/*self->getChild<LLCheckBox>("show_folders_check")->setVisible(mode);
+	  no idea under which conditions the above is even shown, needs testing. */
 
-	self->getChild<LLButton>("l_add_btn")->setVisible(index == 1 ? TRUE : FALSE);
-	self->getChild<LLButton>("l_rem_btn")->setVisible(index == 1 ? TRUE : FALSE);
-	self->getChild<LLButton>("l_upl_btn")->setVisible(index == 1 ? TRUE : FALSE);
-	self->getChild<LLScrollListCtrl>("l_name_list")->setVisible(index == 1 ? TRUE : FALSE);
+	self->getChild<LLButton>("l_add_btn")->setVisible(index == PICKER_LOCAL ? TRUE : FALSE);
+	self->getChild<LLButton>("l_rem_btn")->setVisible(index == PICKER_LOCAL ? TRUE : FALSE);
+	self->getChild<LLButton>("l_upl_btn")->setVisible(index == PICKER_LOCAL ? TRUE : FALSE);
+	self->getChild<LLScrollListCtrl>("l_name_list")->setVisible(index == PICKER_LOCAL ? TRUE : FALSE);
 
-	self->getChild<LLComboBox>("l_bake_use_texture_combo_box")->setVisible(index == 2 ? TRUE : FALSE);
+	self->getChild<LLComboBox>("l_bake_use_texture_combo_box")->setVisible(index == PICKER_BAKE ? TRUE : FALSE);
+	self->getChild<LLCheckBoxCtrl>("hide_base_mesh_region")->setVisible(FALSE);// index == 2 ? TRUE : FALSE);
 
-    bool pipette_visible = (index == 0)
+    bool pipette_visible = (index == PICKER_INVENTORY)
         && (self->mInventoryPickType != LLTextureCtrl::PICK_MATERIAL);
-	self->getChild<LLButton>("Pipette")->setVisible(pipette_visible);
+	self->mPipetteBtn->setVisible(pipette_visible);
 
-	if (index == 2)
+	if (index == PICKER_BAKE)
 	{
 		self->stopUsingPipette();
 
@@ -1093,7 +1194,7 @@ void LLFloaterTexturePicker::onLocalScrollCommit(LLUICtrl* ctrl, void* userdata)
 		{
 			if (self->mOnFloaterCommitCallback)
 			{
-				self->mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CHANGE, inworld_id);
+				self->mOnFloaterCommitCallback(LLTextureCtrl::TEXTURE_CHANGE, PICKER_LOCAL, inworld_id, LLUUID::null);
 			}
 		}
 	}
@@ -1183,10 +1284,10 @@ void LLFloaterTexturePicker::onBakeTextureSelect(LLUICtrl* ctrl, void *user_data
 	}
 }
 
-void LLFloaterTexturePicker::setCanApply(bool can_preview, bool can_apply)
+void LLFloaterTexturePicker::setCanApply(bool can_preview, bool can_apply, bool inworld_image)
 {
-	getChildRef<LLUICtrl>("Select").setEnabled(can_apply);
-	getChildRef<LLUICtrl>("preview_disabled").setVisible(!can_preview);
+	mSelectBtn->setEnabled(can_apply);
+	getChildRef<LLUICtrl>("preview_disabled").setVisible(!can_preview && inworld_image);
 	getChildRef<LLUICtrl>("apply_immediate_check").setVisible(can_preview);
 
 	mCanApply = can_apply;
@@ -1194,6 +1295,15 @@ void LLFloaterTexturePicker::setCanApply(bool can_preview, bool can_apply)
 	mPreviewSettingChanged = true;
 }
 
+void LLFloaterTexturePicker::setMinDimentionsLimits(S32 min_dim)
+{
+    mMinDim = min_dim;
+    mLimitsSet = true;
+
+    std::string formatted_dims = llformat("%dx%d", mMinDim, mMinDim);
+    mResolutionWarning->setTextArg("[MINTEXDIM]", formatted_dims);
+}
+
 void LLFloaterTexturePicker::onFilterEdit(const std::string& search_string )
 {
 	std::string upper_case_search_string = search_string;
@@ -1640,7 +1750,10 @@ void LLTextureCtrl::showPicker(BOOL take_focus)
 		}
 		if (texture_floaterp)
 		{
-			texture_floaterp->setOnFloaterCommitCallback(boost::bind(&LLTextureCtrl::onFloaterCommit, this, _1, _2));
+			texture_floaterp->setOnFloaterCommitCallback(boost::bind(&LLTextureCtrl::onFloaterCommit, this, _1, _2, _3, _4));
+		}
+		if (texture_floaterp)
+		{
 			texture_floaterp->setSetImageAssetIDCallback(boost::bind(&LLTextureCtrl::setImageAssetID, this, _1));
 
 			texture_floaterp->setBakeTextureEnabled(mBakeTextureEnabled);
@@ -1718,7 +1831,10 @@ BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
                 LLInventoryModelBackgroundFetch::instance().start(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE));
             }
 			//...then start full inventory fetch.
-			LLInventoryModelBackgroundFetch::instance().start();
+            if (!LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted())
+            {
+                LLInventoryModelBackgroundFetch::instance().start();
+            }
 			handled = TRUE;
 		}
 		else
@@ -1758,7 +1874,7 @@ void LLTextureCtrl::onFloaterClose()
 	mFloaterHandle.markDead();
 }
 
-void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLUUID id)
+void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLPickerSource source, const LLUUID& asset_id, const LLUUID& inv_id)
 {
     LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
 
@@ -1772,22 +1888,29 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLUUID id)
 		else if (mCommitOnSelection || op == TEXTURE_SELECT)
 			mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here?
 			
-		if(floaterp->isDirty() || id.notNull()) // mModelView->setDirty does not work.
+		if(floaterp->isDirty() || asset_id.notNull()) // mModelView->setDirty does not work.
 		{
 			setTentative( FALSE );
 
-			if (id.notNull())
-			{
-				mImageItemID = id;
-				mImageAssetID = id;
-			}
-			else
-			{
-			    mImageItemID = floaterp->findItemID(floaterp->getAssetID(), FALSE);
-			    LL_DEBUGS() << "mImageItemID: " << mImageItemID << LL_ENDL;
-			    mImageAssetID = floaterp->getAssetID();
-			    LL_DEBUGS() << "mImageAssetID: " << mImageAssetID << LL_ENDL;
-			}
+            switch(source)
+            {
+                case PICKER_INVENTORY:
+                    mImageItemID = inv_id;
+                    mImageAssetID = asset_id;
+                    break;
+                case PICKER_BAKE:
+                case PICKER_LOCAL:
+                    mImageItemID = LLUUID::null;
+                    mImageAssetID = asset_id;
+                    break;
+                case PICKER_UNKNOWN:
+                default:
+                    mImageItemID = floaterp->findItemID(asset_id, FALSE);
+                    mImageAssetID = asset_id;
+                    break;
+            }
+
+            LL_DEBUGS() << "mImageAssetID: " << mImageAssetID << ", mImageItemID: " << mImageItemID << LL_ENDL;
 
 			if (op == TEXTURE_SELECT && mOnSelectCallback)
 			{
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index 053091f18ff45c518e46b28404a61442be314e63..0fd1f3e223dfc638121bbf187b9bea709db0e798 100644
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -61,6 +61,14 @@ bool get_is_predefined_texture(LLUUID asset_id);
 LLUUID get_copy_free_item_by_asset_id(LLUUID image_id, bool no_trans_perm = false);
 bool get_can_copy_texture(LLUUID image_id);
 
+enum LLPickerSource
+{
+    PICKER_INVENTORY,
+    PICKER_LOCAL,
+    PICKER_BAKE,
+    PICKER_UNKNOWN, // on cancel, default ids
+};
+
 //////////////////////////////////////////////////////////////////////////////////////////
 // LLTextureCtrl
 
@@ -192,7 +200,7 @@ class LLTextureCtrl
 	void			closeDependentFloater();
 
 	void			onFloaterClose();
-	void			onFloaterCommit(ETexturePickOp op, LLUUID id);
+	void			onFloaterCommit(ETexturePickOp op, LLPickerSource source, const LLUUID& local_id, const LLUUID& inv_id);
 
 	// This call is returned when a drag is detected. Your callback
 	// should return TRUE if the drag is acceptable.
@@ -262,5 +270,164 @@ class LLTextureCtrl
 	bool						mBakeTextureEnabled;
     LLTextureCtrl::EPickInventoryType mInventoryPickType;
 };
+#if 0
+//////////////////////////////////////////////////////////////////////////////////////////
+// LLFloaterTexturePicker
+typedef boost::function<void(LLTextureCtrl::ETexturePickOp op, LLPickerSource source, const LLUUID& asset_id, const LLUUID& inventory_id)> floater_commit_callback;
+typedef boost::function<void()> floater_close_callback;
+typedef boost::function<void(const LLUUID& asset_id)> set_image_asset_id_callback;
+typedef boost::function<void(LLPointer<LLViewerTexture> texture)> set_on_update_image_stats_callback;
+
+class LLFloaterTexturePicker : public LLFloater
+{
+public:
+	LLFloaterTexturePicker(
+		LLView* owner,
+		LLUUID image_asset_id,
+		LLUUID default_image_asset_id,
+		LLUUID blank_image_asset_id,
+		BOOL tentative,
+		BOOL allow_no_texture,
+		const std::string& label,
+		PermissionMask immediate_filter_perm_mask,
+		PermissionMask dnd_filter_perm_mask,
+		BOOL can_apply_immediately,
+		LLUIImagePtr fallback_image_name
+		);
+
+	virtual ~LLFloaterTexturePicker();
+
+	// LLView overrides
+	/*virtual*/ BOOL	handleDragAndDrop(S32 x, S32 y, MASK mask,
+		BOOL drop, EDragAndDropType cargo_type, void *cargo_data,
+		EAcceptance *accept,
+		std::string& tooltip_msg);
+	/*virtual*/ void	draw();
+	/*virtual*/ BOOL	handleKeyHere(KEY key, MASK mask);
+
+	// LLFloater overrides
+	/*virtual*/ BOOL    postBuild();
+	/*virtual*/ void	onClose(bool app_settings);
+
+	// New functions
+	void setImageID(const LLUUID& image_asset_id, bool set_selection = true);
+	bool updateImageStats(); // true if within limits
+	const LLUUID&	getAssetID() { return mImageAssetID; }
+	const LLUUID&	findItemID(const LLUUID& asset_id, BOOL copyable_only, BOOL ignore_library = FALSE);
+	void			setCanApplyImmediately(BOOL b);
+
+	void			setActive(BOOL active);
+
+	LLView*			getOwner() const { return mOwner; }
+	void			setOwner(LLView* owner) { mOwner = owner; }
+	void			stopUsingPipette();
+
+	void commitIfImmediateSet();
+    void commitCallback(LLTextureCtrl::ETexturePickOp op);
+	void commitCancel();
+
+	void onFilterEdit(const std::string& search_string);
+
+	void setCanApply(bool can_preview, bool can_apply, bool inworld_image = true);
+    void setMinDimentionsLimits(S32 min_dim);
+	void setTextureSelectedCallback(const texture_selected_callback& cb) { mTextureSelectedCallback = cb; }
+	void setOnFloaterCloseCallback(const floater_close_callback& cb) { mOnFloaterCloseCallback = cb; }
+	void setOnFloaterCommitCallback(const floater_commit_callback& cb) { mOnFloaterCommitCallback = cb; }
+	void setSetImageAssetIDCallback(const set_image_asset_id_callback& cb) { mSetImageAssetIDCallback = cb; }
+	void setOnUpdateImageStatsCallback(const set_on_update_image_stats_callback& cb) { mOnUpdateImageStatsCallback = cb; }
+	const LLUUID& getDefaultImageAssetID() { return mDefaultImageAssetID; }
+	const LLUUID& getBlankImageAssetID() { return mBlankImageAssetID; }
+
+	static void		onBtnSetToDefault(void* userdata);
+	static void		onBtnSelect(void* userdata);
+	static void		onBtnCancel(void* userdata);
+	void			onBtnPipette();
+	//static void		onBtnRevert( void* userdata );
+	static void		onBtnBlank(void* userdata);
+	static void		onBtnNone(void* userdata);
+	void			onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action);
+	static void		onApplyImmediateCheck(LLUICtrl* ctrl, void* userdata);
+	void			onTextureSelect(const LLTextureEntry& te);
 
+	static void		onModeSelect(LLUICtrl* ctrl, void *userdata);
+	static void		onBtnAdd(void* userdata);
+	static void		onBtnRemove(void* userdata);
+	static void		onBtnUpload(void* userdata);
+	static void		onLocalScrollCommit(LLUICtrl* ctrl, void* userdata);
+
+	static void		onBakeTextureSelect(LLUICtrl* ctrl, void *userdata);
+
+	void 			setLocalTextureEnabled(BOOL enabled);
+	void 			setBakeTextureEnabled(BOOL enabled);
+
+    void setInventoryPickType(LLTextureCtrl::EPickInventoryType type);
+    void setImmediateFilterPermMask(PermissionMask mask);
+
+    static void		onPickerCallback(const std::vector<std::string>& filenames, LLHandle<LLFloater> handle);
+
+protected:
+    void refreshLocalList();
+    void refreshInventoryFilter();
+    void setImageIDFromItem(const LLInventoryItem* itemp, bool set_selection = true);
+
+	LLPointer<LLViewerTexture> mTexturep;
+    LLPointer<LLFetchedGLTFMaterial> mGLTFMaterial;
+	LLView*				mOwner;
+
+	LLUUID				mImageAssetID; // Currently selected texture
+	LLUIImagePtr		mFallbackImage; // What to show if currently selected texture is null.
+	LLUUID				mDefaultImageAssetID;
+	LLUUID				mBlankImageAssetID;
+	BOOL				mTentative;
+	BOOL				mAllowNoTexture;
+	LLUUID				mSpecialCurrentImageAssetID;  // Used when the asset id has no corresponding texture in the user's inventory.
+	LLUUID				mOriginalImageAssetID;
+
+	std::string			mLabel;
+
+	LLTextBox*			mTentativeLabel;
+	LLTextBox*			mResolutionLabel;
+    LLTextBox*          mResolutionWarning;
+
+	std::string			mPendingName;
+	BOOL				mActive;
+
+	LLFilterEditor*		mFilterEdit;
+	LLInventoryPanel*	mInventoryPanel;
+	PermissionMask		mImmediateFilterPermMask;
+	PermissionMask		mDnDFilterPermMask;
+	BOOL				mCanApplyImmediately;
+	BOOL				mNoCopyTextureSelected;
+	F32					mContextConeOpacity;
+	LLSaveFolderState	mSavedFolderState;
+	BOOL				mSelectedItemPinned;
+
+	LLComboBox*			mModeSelector;
+	LLScrollListCtrl*	mLocalScrollCtrl;
+    LLButton*           mDefaultBtn;
+    LLButton*           mNoneBtn;
+    LLButton*           mBlankBtn;
+    LLButton*           mPipetteBtn;
+    LLButton*           mSelectBtn;
+    LLButton*           mCancelBtn;
+
+private:
+	bool mCanApply;
+	bool mCanPreview;
+	bool mPreviewSettingChanged;
+    bool mLimitsSet;
+    S32 mMaxDim;
+    S32 mMinDim;
+    LLTextureCtrl::EPickInventoryType mInventoryPickType;
+
+
+	texture_selected_callback mTextureSelectedCallback;
+	floater_close_callback mOnFloaterCloseCallback;
+	floater_commit_callback mOnFloaterCommitCallback;
+	set_image_asset_id_callback mSetImageAssetIDCallback;
+	set_on_update_image_stats_callback mOnUpdateImageStatsCallback;
+
+	BOOL mBakeTextureEnabled;
+};
+#endif
 #endif  // LL_LLTEXTURECTRL_H
diff --git a/indra/newview/llthumbnailctrl.cpp b/indra/newview/llthumbnailctrl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..04130fc724d755b2bce5c48a90d845629c63e006
--- /dev/null
+++ b/indra/newview/llthumbnailctrl.cpp
@@ -0,0 +1,239 @@
+/** 
+ * @file llthumbnailctrl.cpp
+ * @brief LLThumbnailCtrl base class
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llthumbnailctrl.h"
+
+#include "linden_common.h"
+#include "llagent.h"
+#include "lluictrlfactory.h"
+#include "lluuid.h"
+#include "lltrans.h"
+#include "llviewborder.h"
+#include "llviewertexture.h"
+#include "llviewertexturelist.h"
+#include "llwindow.h"
+
+static LLDefaultChildRegistry::Register<LLThumbnailCtrl> r("thumbnail");
+
+LLThumbnailCtrl::Params::Params()
+: border("border")
+, border_color("border_color")
+, fallback_image("fallback_image")
+, image_name("image_name")
+, border_visible("show_visible", false)
+, interactable("interactable", false)
+, show_loading("show_loading", true)
+{}
+
+LLThumbnailCtrl::LLThumbnailCtrl(const LLThumbnailCtrl::Params& p)
+:	LLUICtrl(p)
+,   mBorderColor(p.border_color())
+,   mBorderVisible(p.border_visible())
+,   mFallbackImagep(p.fallback_image)
+,   mInteractable(p.interactable())
+,   mShowLoadingPlaceholder(p.show_loading())
+,	mPriority(LLGLTexture::BOOST_PREVIEW)
+{
+    mLoadingPlaceholderString = LLTrans::getString("texture_loading");
+    
+    LLRect border_rect = getLocalRect();
+    LLViewBorder::Params vbparams(p.border);
+    vbparams.name("border");
+    vbparams.rect(border_rect);
+    mBorder = LLUICtrlFactory::create<LLViewBorder> (vbparams);
+    addChild(mBorder);
+    
+    if (p.image_name.isProvided())
+    {
+        setValue(p.image_name());
+    }
+}
+
+LLThumbnailCtrl::~LLThumbnailCtrl()
+{
+	mTexturep = nullptr;
+    mImagep = nullptr;
+    mFallbackImagep = nullptr;
+}
+
+
+void LLThumbnailCtrl::draw()
+{
+    LLRect draw_rect = getLocalRect();
+    
+    if (mBorderVisible)
+    {
+        mBorder->setKeyboardFocusHighlight(hasFocus());
+        
+        gl_rect_2d( draw_rect, mBorderColor.get(), FALSE );
+        draw_rect.stretch( -1 );
+    }
+
+    // If we're in a focused floater, don't apply the floater's alpha to the texture.
+    const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
+    if( mTexturep )
+    {
+        if( mTexturep->getComponents() == 4 )
+        {
+            const LLColor4 color(.098f, .098f, .098f);
+            gl_rect_2d( draw_rect, color, TRUE);
+        }
+        
+        gl_draw_scaled_image( draw_rect.mLeft, draw_rect.mBottom, draw_rect.getWidth(), draw_rect.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha);
+        
+        mTexturep->setKnownDrawSize(draw_rect.getWidth(), draw_rect.getHeight());
+    }
+    else if( mImagep.notNull() )
+    {
+        mImagep->draw(draw_rect, UI_VERTEX_COLOR % alpha );
+    }
+    else if (mFallbackImagep.notNull())
+    {
+        if (draw_rect.getWidth() > mFallbackImagep->getWidth()
+            && draw_rect.getHeight() > mFallbackImagep->getHeight())
+        {
+            S32 img_width = mFallbackImagep->getWidth();
+            S32 img_height = mFallbackImagep->getHeight();
+            S32 rect_width = draw_rect.getWidth();
+            S32 rect_height = draw_rect.getHeight();
+
+            LLRect fallback_rect;
+            fallback_rect.mLeft = draw_rect.mLeft + (rect_width - img_width) / 2;
+            fallback_rect.mRight = fallback_rect.mLeft + img_width;
+            fallback_rect.mBottom = draw_rect.mBottom + (rect_height - img_height) / 2;
+            fallback_rect.mTop = fallback_rect.mBottom + img_height;
+
+            mFallbackImagep->draw(fallback_rect, UI_VERTEX_COLOR % alpha);
+        }
+        else
+        {
+            mFallbackImagep->draw(draw_rect, UI_VERTEX_COLOR % alpha);
+        }
+    }
+    else
+    {
+        gl_rect_2d( draw_rect, LLColor4::grey % alpha, TRUE );
+
+        // Draw X
+        gl_draw_x( draw_rect, LLColor4::black );
+    }
+
+    // Show "Loading..." string on the top left corner while this texture is loading.
+    // Using the discard level, do not show the string if the texture is almost but not
+    // fully loaded.
+    if (mTexturep.notNull()
+        && mShowLoadingPlaceholder
+        && !mTexturep->isFullyLoaded())
+    {
+        U32 v_offset = 25;
+        LLFontGL* font = LLFontGL::getFontSansSerif();
+
+        // Don't show as loaded if the texture is almost fully loaded (i.e. discard1) unless god
+        if ((mTexturep->getDiscardLevel() > 1) || gAgent.isGodlike())
+        {
+            font->renderUTF8(
+                mLoadingPlaceholderString,
+                0,
+                llfloor(draw_rect.mLeft+3),
+                llfloor(draw_rect.mTop-v_offset),
+                LLColor4::white,
+                LLFontGL::LEFT,
+                LLFontGL::BASELINE,
+                LLFontGL::DROP_SHADOW);
+        }
+    }
+
+    LLUICtrl::draw();
+}
+
+void LLThumbnailCtrl::clearTexture()
+{
+    mImageAssetID = LLUUID::null;
+    mTexturep = nullptr;
+    mImagep = nullptr;
+}
+
+// virtual
+// value might be a string or a UUID
+void LLThumbnailCtrl::setValue(const LLSD& value)
+{
+	LLSD tvalue(value);
+	if (value.isString() && LLUUID::validate(value.asString()))
+	{
+		//RN: support UUIDs masquerading as strings
+		tvalue = LLSD(LLUUID(value.asString()));
+	}
+    
+	LLUICtrl::setValue(tvalue);
+    
+    mImageAssetID = LLUUID::null;
+    mTexturep = nullptr;
+    mImagep = nullptr;
+    
+	if (tvalue.isUUID())
+	{
+        mImageAssetID = tvalue.asUUID();
+        if (mImageAssetID.notNull())
+        {
+            // Should it support baked textures?
+            mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, MIPMAP_YES, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+            
+            mTexturep->setBoostLevel(mPriority);
+            mTexturep->forceToSaveRawImage(0);
+            
+            S32 desired_draw_width = mTexturep->getWidth();
+            S32 desired_draw_height = mTexturep->getHeight();
+            
+            mTexturep->setKnownDrawSize(desired_draw_width, desired_draw_height);
+        }
+	}
+    else if (tvalue.isString())
+    {
+        mImagep = LLUI::getUIImage(tvalue.asString(), LLGLTexture::BOOST_UI);
+        if (mImagep)
+        {
+            LLViewerFetchedTexture* texture = dynamic_cast<LLViewerFetchedTexture*>(mImagep->getImage().get());
+            if(texture)
+            {
+                mImageAssetID = texture->getID();
+            }
+        }
+    }
+}
+
+BOOL LLThumbnailCtrl::handleHover(S32 x, S32 y, MASK mask)
+{
+    if (mInteractable && getEnabled())
+    {
+        getWindow()->setCursor(UI_CURSOR_HAND);
+        return TRUE;
+    }
+    return LLUICtrl::handleHover(x, y, mask);
+}
+
+
diff --git a/indra/newview/llthumbnailctrl.h b/indra/newview/llthumbnailctrl.h
new file mode 100644
index 0000000000000000000000000000000000000000..686603b37300c4c4993764d2f421a62d65dfa390
--- /dev/null
+++ b/indra/newview/llthumbnailctrl.h
@@ -0,0 +1,88 @@
+/** 
+ * @file llthumbnailctrl.h
+ * @brief LLThumbnailCtrl base class
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023 Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTHUMBNAILCTRL_H
+#define LL_LLTHUMBNAILCTRL_H
+
+#include "llui.h"
+#include "lluictrl.h"
+#include "llviewborder.h" // for params
+
+class LLUICtrlFactory;
+class LLUUID;
+class LLViewerFetchedTexture;
+
+//
+// Classes
+//
+
+// 
+class LLThumbnailCtrl
+: public LLUICtrl
+{
+public:
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+        Optional<LLViewBorder::Params> border;
+        Optional<LLUIColor>        border_color;
+        Optional<std::string>      image_name;
+        Optional<LLUIImage*>       fallback_image;
+        Optional<bool>             border_visible;
+        Optional<bool>             interactable;
+        Optional<bool>             show_loading;
+        
+		Params();
+	};
+protected:
+    LLThumbnailCtrl(const Params&);
+	friend class LLUICtrlFactory;
+
+public:
+	virtual ~LLThumbnailCtrl();
+
+	virtual void draw() override;
+
+	virtual void setValue(const LLSD& value ) override;
+    void clearTexture();
+    
+    virtual BOOL handleHover(S32 x, S32 y, MASK mask) override;
+	
+private:
+	S32 mPriority;
+    bool mBorderVisible;
+    bool mInteractable;
+    bool mShowLoadingPlaceholder;
+    std::string mLoadingPlaceholderString;
+    LLUUID mImageAssetID;
+    LLViewBorder* mBorder;
+    LLUIColor mBorderColor;
+    
+	LLPointer<LLViewerFetchedTexture> mTexturep;
+    LLPointer<LLUIImage> mImagep;
+    LLPointer<LLUIImage> mFallbackImagep;
+};
+
+#endif
diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp
index 692e8d91a9c8d90c4cadc48447d4a4f1b52e78dc..d35833fac9ab04f9e902e1d730f60cecb73dfdd8 100644
--- a/indra/newview/lltoastalertpanel.cpp
+++ b/indra/newview/lltoastalertpanel.cpp
@@ -279,6 +279,10 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
 	if (!edit_text_name.empty())
 	{
 		S32 y = VPAD + BTN_HEIGHT + VPAD/2;
+        if (form->getIgnoreType() != LLNotificationForm::IGNORE_NO)
+        {
+            y += EDITOR_HEIGHT;
+        }
 		mLineEditor = LLUICtrlFactory::getInstance()->createFromFile<LLLineEditor>("alert_line_editor.xml", this, LLPanel::child_registry_t::instance());
 	
 		if (mLineEditor)
@@ -522,6 +526,10 @@ void LLToastAlertPanel::onButtonPressed( const LLSD& data, S32 button )
 	{
 		response[mLineEditor->getName()] = mLineEditor->getValue();
 	}
+    if (mNotification->getForm()->getIgnoreType() != LLNotificationForm::IGNORE_NO)
+    {
+        response["ignore"] = mNotification->isIgnored();
+    }
 	response[button_data->mButton->getName()] = true;
 
 	// If we declared a URL and chose the URL option, go to the url
diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp
index 2915024912ca55b0a479bfb65daadb4c7436408d..3d0c995786054e3b84a8ac475a9a2fe692a20975 100644
--- a/indra/newview/lltoolbarview.cpp
+++ b/indra/newview/lltoolbarview.cpp
@@ -360,9 +360,9 @@ bool LLToolBarView::loadToolbars(bool force_default)
 	}
 
     // SL-18581: Don't show the starter avatar toolbar button for NUX users
-    LLViewerInventoryCategory* my_outfits_cat = gInventory.getCategory(gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS));
     if (gAgent.isFirstLogin())
     {
+        LLViewerInventoryCategory* my_outfits_cat = gInventory.getCategory(gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS));
         LL_WARNS() << "First login: checking for NUX user." << LL_ENDL;
         if (my_outfits_cat != NULL && my_outfits_cat->getDescendentCount() > 0)
         {
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 897c56b31e0d54547c5c0969e2f942de6506871c..51af23bae96c953327022f28567dc729990fa264 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -773,7 +773,7 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop,
 	if (!handled)
 	{
 		// Disallow drag and drop to 3D from the marketplace
-        const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+        const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
 		if (marketplacelistings_id.notNull())
 		{
 			for (S32 item_index = 0; item_index < (S32)mCargoIDs.size(); item_index++)
@@ -1910,8 +1910,8 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
 		return ACCEPT_NO;
 	}
 
-	const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
-	if(gInventory.isObjectDescendentOf(item->getUUID(), outbox_id))
+	const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX);
+	if(outbox_id.notNull() && gInventory.isObjectDescendentOf(item->getUUID(), outbox_id))
 	{
 		// Legacy
 		return ACCEPT_NO;
@@ -2502,8 +2502,8 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory(
 			return ACCEPT_NO;
 		}
 
-		const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
-		if(gInventory.isObjectDescendentOf(category->getUUID(), outbox_id))
+		const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX);
+		if(outbox_id.notNull() && gInventory.isObjectDescendentOf(category->getUUID(), outbox_id))
 		{
 			// Legacy
 			return ACCEPT_NO;
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index c8bc852bb32f41e8dae7b722e456327984920e68..f0c2cc103a6d3edf3625f5b7e5731a90c7cf6b10 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -66,6 +66,7 @@
 #include "llfloaterbvhpreview.h"
 #include "llfloatercamera.h"
 #include "llfloatercamerapresets.h"
+#include "llfloaterchangeitemthumbnail.h"
 // [SL:KB] - Patch: Chat-Alerts | Checked: 2012-07-17 (Catznip-3.3)
 #include "llfloaterchatalerts.h"
 // [/SL:KB]
@@ -100,6 +101,7 @@
 #include "llfloaterimagepreview.h"
 #include "llfloaterimsession.h"
 #include "llfloaterinspect.h"
+#include "llfloaterinventorysettings.h"
 #include "llfloaterjoystick.h"
 #include "llfloaterlagmeter.h"
 #include "llfloaterland.h"
@@ -123,8 +125,7 @@
 #include "llfloaternotificationstabbed.h"
 #include "llfloaterobjectweights.h"
 #include "llfloateropenobject.h"
-#include "llfloateroutfitphotopreview.h"
-#include "llfloatersimpleoutfitsnapshot.h"
+#include "llfloatersimplesnapshot.h"
 #include "llfloaterpathfindingcharacters.h"
 #include "llfloaterpathfindingconsole.h"
 #include "llfloaterpathfindinglinksets.h"
@@ -138,7 +139,6 @@
 #include "llfloaterprofile.h"
 #include "llfloaterprofilelegacy.h"
 #include "llfloaterprogressview.h"
-#include "llfloaterproperties.h"
 #include "llfloaterpublishclassified.h"
 #include "llfloaterregiondebugconsole.h"
 #include "llfloaterregioninfo.h"
@@ -367,6 +367,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("chat_alerts", "floater_chat_alerts.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatAlerts>);
 // [/SL:KB]
 	LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>);
+    LLFloaterReg::add("change_item_thumbnail", "floater_change_item_thumbnail.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChangeItemThumbnail>);
 	LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater);
     LLFloaterReg::add("classified", "floater_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterClassified>);
 	LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>);
@@ -408,6 +409,8 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("inventory", "floater_my_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>);
 	LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInspect>);
 	LLFloaterReg::add("item_properties", "floater_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>);
+    LLFloaterReg::add("task_properties", "floater_task_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>);
+    LLFloaterReg::add("inventory_settings", "floater_inventory_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventorySettings>);
 	LLInspectAvatarUtil::registerFloater();
 	LLInspectGroupUtil::registerFloater();
 	LLInspectObjectUtil::registerFloater();
@@ -440,7 +443,6 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterObjectWeights>);
 	LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>);
 	LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>);
-	LLFloaterReg::add("outfit_photo_preview", "floater_outfit_photo_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOutfitPhotoPreview>);
 	LLFloaterPayUtil::registerFloater();
 
 	LLFloaterReg::add("pathfinding_characters", "floater_pathfinding_characters.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingCharacters>);
@@ -468,7 +470,6 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("preview_sound", "floater_preview_sound.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewSound>, "preview");
 	LLFloaterReg::add("preview_texture", "floater_preview_texture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewTexture>, "preview");
 	LLFloaterReg::add("preview_trash", "floater_preview_trash.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreviewTrash>);
-	LLFloaterReg::add("properties", "floater_inventory_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterProperties>);
 	LLFloaterReg::add("publish_classified", "floater_publish_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPublishClassified>);
 	LLFloaterReg::add("save_pref_preset", "floater_save_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSavePrefPreset>);
 	LLFloaterReg::add("save_camera_preset", "floater_save_camera_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSaveCameraPreset>);
@@ -511,7 +512,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("scene_load_stats", "floater_scene_load_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSceneLoadStats>);
 	LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>);
 	LLFloaterReg::add("snapshot", "floater_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSnapshot>);
-    LLFloaterReg::add("simple_outfit_snapshot", "floater_simple_outfit_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSimpleOutfitSnapshot>);
+    LLFloaterReg::add("simple_snapshot", "floater_simple_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSimpleSnapshot>);
     //LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSearch>);
 // [SL:KB] - Patch: UI-FloaterSearchReplace | Checked: 2010-10-26 (Catznip-2.3)
 	LLFloaterReg::add("search_replace", "floater_search_replace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSearchReplace>);
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index a3565e4a29d4092748bf537d526b9924b86ca6b9..590854932646f29c344217aa17b57dcaf76c804c 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -345,7 +345,7 @@ LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& uuid,
 											 time_t creation_date_utc) :
 	LLInventoryItem(uuid, parent_uuid, perm, asset_uuid, type, inv_type,
 					name, desc, sale_info, flags, creation_date_utc),
-	mIsComplete(TRUE)
+	mIsComplete(true)
 {
 }
 
@@ -354,7 +354,7 @@ LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& item_id,
 											 const std::string& name,
 											 LLInventoryType::EType inv_type) :
 	LLInventoryItem(),
-	mIsComplete(FALSE)
+	mIsComplete(false)
 {
 	mUUID = item_id;
 	mParentUUID = parent_id;
@@ -364,7 +364,7 @@ LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& item_id,
 
 LLViewerInventoryItem::LLViewerInventoryItem() :
 	LLInventoryItem(),
-	mIsComplete(FALSE)
+	mIsComplete(false)
 {
 }
 
@@ -381,7 +381,7 @@ LLViewerInventoryItem::LLViewerInventoryItem(const LLViewerInventoryItem* other)
 
 LLViewerInventoryItem::LLViewerInventoryItem(const LLInventoryItem *other) :
 	LLInventoryItem(other),
-	mIsComplete(TRUE)
+	mIsComplete(true)
 {
 }
 
@@ -484,48 +484,43 @@ void LLViewerInventoryItem::fetchFromServer(void) const
 {
 	if(!mIsComplete)
 	{
-		std::string url; 
+        if (AISAPI::isAvailable()) // AIS v 3
+        {
+            LLInventoryModelBackgroundFetch::getInstance()->scheduleItemFetch(mUUID);
+        }
+        else
+        {
+            std::string url;
 
-		LLViewerRegion* region = gAgent.getRegion();
-		// we have to check region. It can be null after region was destroyed. See EXT-245
-		if (region)
-		{
-		  if (gAgent.getID() != mPermissions.getOwner())
-		  {
-		      url = region->getCapability("FetchLib2");
-		  }
-		  else
-		  {	
-		      url = region->getCapability("FetchInventory2");
-		  }
-		}
-		else
-		{
-			LL_WARNS(LOG_INV) << "Agent Region is absent" << LL_ENDL;
-		}
+            LLViewerRegion* region = gAgent.getRegion();
+            // we have to check region. It can be null after region was destroyed. See EXT-245
+            if (region)
+            {
+                if (gAgent.getID() != mPermissions.getOwner())
+                {
+                    url = region->getCapability("FetchLib2");
+                }
+                else
+                {
+                    url = region->getCapability("FetchInventory2");
+                }
+            }
+            else
+            {
+                LL_WARNS(LOG_INV) << "Agent Region is absent" << LL_ENDL;
+            }
 
-		if (!url.empty())
-		{
-			LLSD body;
-			body["agent_id"]	= gAgent.getID();
-			body["items"][0]["owner_id"]	= mPermissions.getOwner();
-			body["items"][0]["item_id"]		= mUUID;
+            if (!url.empty())
+            {
+                LLSD body;
+                body["agent_id"] = gAgent.getID();
+                body["items"][0]["owner_id"] = mPermissions.getOwner();
+                body["items"][0]["item_id"] = mUUID;
 
-            LLCore::HttpHandler::ptr_t handler(new LLInventoryModel::FetchItemHttpHandler(body));
-			gInventory.requestPost(true, url, body, handler, "Inventory Item");
-		}
-		else
-		{
-			LLMessageSystem* msg = gMessageSystem;
-			msg->newMessageFast(_PREHASH_FetchInventory);
-			msg->nextBlockFast(_PREHASH_AgentData);
-			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-			msg->nextBlockFast(_PREHASH_InventoryData);
-			msg->addUUIDFast(_PREHASH_OwnerID, mPermissions.getOwner());
-			msg->addUUIDFast(_PREHASH_ItemID, mUUID);
-			gAgent.sendReliableMessage();
-		}
+                LLCore::HttpHandler::ptr_t handler(new LLInventoryModel::FetchItemHttpHandler(body));
+                gInventory.requestPost(true, url, body, handler, "Inventory Item");
+            }
+        }
 	}
 }
 
@@ -622,7 +617,8 @@ LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& uuid,
 	LLInventoryCategory(uuid, parent_uuid, pref, name),
 	mOwnerID(owner_id),
 	mVersion(LLViewerInventoryCategory::VERSION_UNKNOWN),
-	mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
+	mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN),
+    mFetching(FETCH_NONE)
 {
 	mDescendentsRequested.reset();
 }
@@ -630,7 +626,8 @@ LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& uuid,
 LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& owner_id) :
 	mOwnerID(owner_id),
 	mVersion(LLViewerInventoryCategory::VERSION_UNKNOWN),
-	mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
+	mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN),
+    mFetching(FETCH_NONE)
 {
 	mDescendentsRequested.reset();
 }
@@ -638,6 +635,7 @@ LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& owner_id) :
 LLViewerInventoryCategory::LLViewerInventoryCategory(const LLViewerInventoryCategory* other)
 {
 	copyViewerCategory(other);
+    mFetching = FETCH_NONE;
 }
 
 LLViewerInventoryCategory::~LLViewerInventoryCategory()
@@ -734,7 +732,6 @@ bool LLViewerInventoryCategory::fetch()
 		mDescendentsRequested.reset();
 		mDescendentsRequested.setTimerExpirySec(FETCH_TIMER_EXPIRY);
 
-
 		std::string url;
 		if (gAgent.getRegion())
 		{
@@ -744,38 +741,52 @@ bool LLViewerInventoryCategory::fetch()
 		{
 			LL_WARNS(LOG_INV) << "agent region is null" << LL_ENDL;
 		}
-		if (!url.empty()) //Capability found.  Build up LLSD and use it.
+		if (!url.empty() || AISAPI::isAvailable())
 		{
-			LLInventoryModelBackgroundFetch::instance().start(mUUID, false);			
-		}
-		else
-		{
-			// bitfield
-			// 1 = by date
-			// 2 = folders by date
-			// Need to mask off anything but the first bit.
-			// This comes from LLInventoryFilter from llfolderview.h
-			U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1;
-			
-			LLMessageSystem* msg = gMessageSystem;
-			msg->newMessage("FetchInventoryDescendents");
-			msg->nextBlock("AgentData");
-			msg->addUUID("AgentID", gAgent.getID());
-			msg->addUUID("SessionID", gAgent.getSessionID());
-			msg->nextBlock("InventoryData");
-			msg->addUUID("FolderID", mUUID);
-			msg->addUUID("OwnerID", mOwnerID);
-
-			msg->addS32("SortOrder", sort_order);
-			msg->addBOOL("FetchFolders", FALSE);
-			msg->addBOOL("FetchItems", TRUE);
-			gAgent.sendReliableMessage();
+			LLInventoryModelBackgroundFetch::instance().start(mUUID, false);
 		}
 		return true;
 	}
 	return false;
 }
 
+LLViewerInventoryCategory::EFetchType LLViewerInventoryCategory::getFetching()
+{
+    // if timer hasn't expired, request was scheduled, but not in progress
+    // if mFetching request was actually started
+    if (mDescendentsRequested.hasExpired())
+    {
+        mFetching = FETCH_NONE;
+    }
+    return mFetching;
+}
+
+void LLViewerInventoryCategory::setFetching(LLViewerInventoryCategory::EFetchType fetching)
+{
+    if (fetching > mFetching) // allow a switch from normal to recursive
+    {
+        if (mDescendentsRequested.hasExpired() || (mFetching == FETCH_NONE))
+        {
+            mDescendentsRequested.reset();
+            if (AISAPI::isAvailable())
+            {
+                mDescendentsRequested.setTimerExpirySec(AISAPI::HTTP_TIMEOUT);
+            }
+            else
+            {
+                const F32 FETCH_TIMER_EXPIRY = 30.0f;
+                mDescendentsRequested.setTimerExpirySec(FETCH_TIMER_EXPIRY);
+            }
+        }
+        mFetching = fetching;
+    }
+    else if (fetching == FETCH_NONE)
+    {
+        mDescendentsRequested.stop();
+        mFetching = fetching;
+    }
+}
+
 S32 LLViewerInventoryCategory::getViewerDescendentCount() const
 {
 	LLInventoryModel::cat_array_t* cats;
@@ -1138,13 +1149,18 @@ void create_gltf_material_cb(const LLUUID& inv_item)
 
 LLInventoryCallbackManager gInventoryCallbacks;
 
-void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
-						   const LLUUID& parent, const LLTransactionID& transaction_id,
-						   const std::string& name,
-						   const std::string& desc, LLAssetType::EType asset_type,
-						   LLInventoryType::EType inv_type, U8 subtype,
-						   U32 next_owner_perm,
-						   LLPointer<LLInventoryCallback> cb)
+void create_inventory_item(
+    const LLUUID& agent_id,
+    const LLUUID& session_id,
+    const LLUUID& parent_id,
+    const LLTransactionID& transaction_id,
+    const std::string& name,
+    const std::string& desc,
+    LLAssetType::EType asset_type,
+    LLInventoryType::EType inv_type,
+    U8 subtype,
+    U32 next_owner_perm,
+    LLPointer<LLInventoryCallback> cb)
 {
 	//check if name is equal to one of special inventory items names
 	//EXT-5839
@@ -1161,6 +1177,54 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
 		}
 	}
 
+#ifdef USE_AIS_FOR_NC
+    // D567 18.03.2023 not yet implemented within AIS3
+    if (AISAPI::isAvailable())
+    {
+        LLSD new_inventory = LLSD::emptyMap();
+        new_inventory["items"] = LLSD::emptyArray();
+
+        LLPermissions perms;
+        perms.init(
+            gAgentID,
+            gAgentID,
+            LLUUID::null,
+            LLUUID::null);
+        perms.initMasks(
+            PERM_ALL,
+            PERM_ALL,
+            PERM_NONE,
+            PERM_NONE,
+            next_owner_perm);
+
+        LLUUID null_id;
+        LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(
+            null_id, /*don't know yet*/
+            parent_id,
+            perms,
+            null_id, /*don't know yet*/
+            asset_type,
+            inv_type,
+            server_name,
+            desc,
+            LLSaleInfo(),
+            0,
+            0 /*don't know yet, whenever server creates it*/);
+        LLSD item_sd = item->asLLSD();
+        new_inventory["items"].append(item_sd);
+        AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
+        AISAPI::CreateInventory(
+            parent_id,
+            new_inventory,
+            cr);
+        return;
+    }
+    else
+    {
+        LL_WARNS() << "AIS v3 not available" << LL_ENDL;
+    }
+#endif
+
 	LLMessageSystem* msg = gMessageSystem;
 	msg->newMessageFast(_PREHASH_CreateInventoryItem);
 	msg->nextBlockFast(_PREHASH_AgentData);
@@ -1168,7 +1232,7 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
 	msg->addUUIDFast(_PREHASH_SessionID, session_id);
 	msg->nextBlockFast(_PREHASH_InventoryBlock);
 	msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
-	msg->addUUIDFast(_PREHASH_FolderID, parent);
+	msg->addUUIDFast(_PREHASH_FolderID, parent_id);
 	msg->addUUIDFast(_PREHASH_TransactionID, transaction_id);
 	msg->addU32Fast(_PREHASH_NextOwnerMask, next_owner_perm);
 	msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
@@ -1410,55 +1474,27 @@ void update_inventory_item(
 	LLPointer<LLInventoryCallback> cb)
 {
 	const LLUUID& item_id = update_item->getUUID();
-    if (AISAPI::isAvailable())
-	{
-		LLSD updates = update_item->asLLSD();
-		// Replace asset_id and/or shadow_id with transaction_id (hash_id)
-		if (updates.has("asset_id"))
-		{
-			updates.erase("asset_id");
-        		if (update_item->getTransactionID().notNull())
-        		{
-				updates["hash_id"] = update_item->getTransactionID();
-			}
-		}
-		if (updates.has("shadow_id"))
-		{
-			updates.erase("shadow_id");
-			if (update_item->getTransactionID().notNull())
-			{
-				updates["hash_id"] = update_item->getTransactionID();
-			}
-		}
-        	AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
-        	AISAPI::UpdateItem(item_id, updates, cr);
-	}
-    else
-	{
-		LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
-		LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (update_item ? update_item->getName() : "(NOT FOUND)") << LL_ENDL;
-		if(obj)
-		{
-			LLMessageSystem* msg = gMessageSystem;
-			msg->newMessageFast(_PREHASH_UpdateInventoryItem);
-			msg->nextBlockFast(_PREHASH_AgentData);
-			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-			msg->addUUIDFast(_PREHASH_TransactionID, update_item->getTransactionID());
-			msg->nextBlockFast(_PREHASH_InventoryData);
-			msg->addU32Fast(_PREHASH_CallbackID, 0);
-			update_item->packMessage(msg);
-			gAgent.sendReliableMessage();
-
-			LLInventoryModel::LLCategoryUpdate up(update_item->getParentUUID(), 0);
-			gInventory.accountForUpdate(up);
-			gInventory.updateItem(update_item);
-			if (cb)
-			{
-				cb->fire(item_id);
-			}
-		}
-	}
+  
+    LLSD updates = update_item->asLLSD();
+    // Replace asset_id and/or shadow_id with transaction_id (hash_id)
+    if (updates.has("asset_id"))
+    {
+        updates.erase("asset_id");
+        if (update_item->getTransactionID().notNull())
+        {
+            updates["hash_id"] = update_item->getTransactionID();
+        }
+    }
+    if (updates.has("shadow_id"))
+    {
+        updates.erase("shadow_id");
+        if (update_item->getTransactionID().notNull())
+        {
+            updates["hash_id"] = update_item->getTransactionID();
+        }
+    }
+    AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
+    AISAPI::UpdateItem(item_id, updates, cr);
 }
 
 // Note this only supports updating an existing item. Goes through AISv3
@@ -1469,41 +1505,8 @@ void update_inventory_item(
 	const LLSD& updates,
 	LLPointer<LLInventoryCallback> cb)
 {
-    if (AISAPI::isAvailable())
-	{
-        AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
-        AISAPI::UpdateItem(item_id, updates, cr);
-	}
-    else
-	{
-		LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
-		LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << LL_ENDL;
-		if(obj)
-		{
-			LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem);
-			new_item->copyViewerItem(obj);
-			new_item->fromLLSD(updates,false);
-
-			LLMessageSystem* msg = gMessageSystem;
-			msg->newMessageFast(_PREHASH_UpdateInventoryItem);
-			msg->nextBlockFast(_PREHASH_AgentData);
-			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-			msg->addUUIDFast(_PREHASH_TransactionID, new_item->getTransactionID());
-			msg->nextBlockFast(_PREHASH_InventoryData);
-			msg->addU32Fast(_PREHASH_CallbackID, 0);
-			new_item->packMessage(msg);
-			gAgent.sendReliableMessage();
-
-			LLInventoryModel::LLCategoryUpdate up(new_item->getParentUUID(), 0);
-			gInventory.accountForUpdate(up);
-			gInventory.updateItem(new_item);
-			if (cb)
-			{
-				cb->fire(item_id);
-			}
-		}
-	}
+    AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
+    AISAPI::UpdateItem(item_id, updates, cr);
 }
 
 void update_inventory_category(
@@ -1515,39 +1518,15 @@ void update_inventory_category(
 	LL_DEBUGS(LOG_INV) << "cat_id: [" << cat_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << LL_ENDL;
 	if(obj)
 	{
-		if (LLFolderType::lookupIsProtectedType(obj->getPreferredType()))
+        if (LLFolderType::lookupIsProtectedType(obj->getPreferredType())
+            && (updates.size() != 1 || !updates.has("thumbnail")))
 		{
 			LLNotificationsUtil::add("CannotModifyProtectedCategories");
 			return;
 		}
 
-		LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(obj);
-		new_cat->fromLLSD(updates);
-        if (AISAPI::isAvailable())
-		{
-			LLSD new_llsd = new_cat->asLLSD();
-            AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
-            AISAPI::UpdateCategory(cat_id, new_llsd, cr);
-		}
-		else // no cap
-		{
-			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);
-			new_cat->packMessage(msg);
-			gAgent.sendReliableMessage();
-
-			LLInventoryModel::LLCategoryUpdate up(new_cat->getParentUUID(), 0);
-			gInventory.accountForUpdate(up);
-			gInventory.updateCategory(new_cat);
-			if (cb)
-			{
-				cb->fire(cat_id);
-			}
-		}
+        AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
+        AISAPI::UpdateCategory(cat_id, updates, cr);
 	}
 }
 
@@ -1599,25 +1578,10 @@ void remove_inventory_item(
 				gInventory.onObjectDeletedFromServer(item_id);
 			}
 		}
-		else // no cap
-		{
-			LLMessageSystem* msg = gMessageSystem;
-			msg->newMessageFast(_PREHASH_RemoveInventoryItem);
-			msg->nextBlockFast(_PREHASH_AgentData);
-			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); 
-			msg->nextBlockFast(_PREHASH_InventoryData);
-			msg->addUUIDFast(_PREHASH_ItemID, item_id);
-			gAgent.sendReliableMessage();
-
-			// Update inventory and call callback immediately since
-			// message-based system has no callback mechanism (!)
-			gInventory.onObjectDeletedFromServer(item_id);
-			if (cb)
-			{
-				cb->fire(item_id);
-			}
-		}
+        else
+        {
+            LL_WARNS(LOG_INV) << "Tried to use inventory without AIS API" << LL_ENDL;
+        }
 	}
 	else
 	{
@@ -1779,28 +1743,10 @@ void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb)
 			AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t();
 			AISAPI::PurgeDescendents(id, cr);
 		}
-		else // no cap
-		{
-			// Fast purge
-			LL_DEBUGS(LOG_INV) << "purge_descendents_of fast case " << cat->getName() << LL_ENDL;
-
-			// send it upstream
-			LLMessageSystem* msg = gMessageSystem;
-			msg->newMessageFast(_PREHASH_PurgeInventoryDescendents);
-			msg->nextBlockFast(_PREHASH_AgentData);
-			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-			msg->nextBlockFast(_PREHASH_InventoryData);
-			msg->addUUIDFast(_PREHASH_FolderID, id);
-			gAgent.sendReliableMessage();
-
-			// Update model immediately because there is no callback mechanism.
-			gInventory.onDescendentsPurgedFromServer(id);
-			if (cb)
-			{
-				cb->fire(id);
-			}
-		}
+        else
+        {
+            LL_WARNS(LOG_INV) << "Tried to use inventory without AIS API" << LL_ENDL;
+        }
 	}
 }
 
@@ -1933,13 +1879,14 @@ void create_new_item(const std::string& name,
 				   const LLUUID& parent_id,
 				   LLAssetType::EType asset_type,
 				   LLInventoryType::EType inv_type,
-				   U32 next_owner_perm)
+				   U32 next_owner_perm,
+                   std::function<void(const LLUUID&)> created_cb = NULL)
 {
 	std::string desc;
 	LLViewerAssetType::generateDescriptionFor(asset_type, desc);
 	next_owner_perm = (next_owner_perm) ? next_owner_perm : PERM_MOVE | PERM_TRANSFER;
 
-	LLPointer<LLInventoryCallback> cb = NULL;
+	LLPointer<LLBoostFuncInventoryCallback> cb = NULL;
 
 	switch (inv_type)
 	{
@@ -1970,9 +1917,16 @@ void create_new_item(const std::string& name,
             next_owner_perm = LLFloaterPerms::getNextOwnerPerms("Materials");
             break;
         }
-		default:
-			break;
-	}
+        default:
+        {
+            cb = new LLBoostFuncInventoryCallback();
+            break;
+        }
+    }
+    if (created_cb != NULL)
+    {
+        cb->addOnFireFunc(created_cb);
+    }
 
 	create_inventory_item(gAgent.getID(),
 						  gAgent.getSessionID(),
@@ -2121,65 +2075,95 @@ const std::string NEW_MATERIAL_NAME = "New Material"; // *TODO:Translate? (proba
 // ! REFACTOR ! Really need to refactor this so that it's not a bunch of if-then statements...
 void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge, const LLSD& userdata, const LLUUID& default_parent_uuid)
 {
-	std::string type_name = userdata.asString();
-	
-	if (("inbox" == type_name) || ("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name))
-	{
-		LLFolderType::EType preferred_type = LLFolderType::lookup(type_name);
+    menu_create_inventory_item(panel, bridge ? bridge->getUUID() : LLUUID::null, userdata, default_parent_uuid);
+}
 
-		LLUUID parent_id;
-		if (bridge)
-		{
-			parent_id = bridge->getUUID();
-		}
-		else if (default_parent_uuid.notNull())
-		{
-			parent_id = default_parent_uuid;
-		}
-		else
-		{
-			parent_id = gInventory.getRootFolderID();
-		}
+void menu_create_inventory_item(LLInventoryPanel* panel, LLUUID dest_id, const LLSD& userdata, const LLUUID& default_parent_uuid, std::function<void(const LLUUID&)> created_cb)
+{
+    std::string type_name = userdata.asString();
+    
+    if (("inbox" == type_name) || ("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name))
+    {
+        LLFolderType::EType preferred_type = LLFolderType::lookup(type_name);
 
-		LLUUID category = gInventory.createNewCategory(parent_id, preferred_type, LLStringUtil::null);
-		gInventory.notifyObservers();
-		panel->setSelectionByID(category, TRUE);
-	}
-	else if ("lsl" == type_name)
-	{
-		const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_LSL_TEXT);
-		create_new_item(NEW_LSL_NAME,
-					  parent_id,
-					  LLAssetType::AT_LSL_TEXT,
-					  LLInventoryType::IT_LSL,
-					  PERM_MOVE | PERM_TRANSFER);	// overridden in create_new_item
-	}
-	else if ("notecard" == type_name)
-	{
-		const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_NOTECARD);
-		create_new_item(NEW_NOTECARD_NAME,
-					  parent_id,
-					  LLAssetType::AT_NOTECARD,
-					  LLInventoryType::IT_NOTECARD,
-					  PERM_ALL);	// overridden in create_new_item
-	}
-	else if ("gesture" == type_name)
-	{
-		const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
-		create_new_item(NEW_GESTURE_NAME,
-					  parent_id,
-					  LLAssetType::AT_GESTURE,
-					  LLInventoryType::IT_GESTURE,
-					  PERM_ALL);	// overridden in create_new_item
-	}
+        LLUUID parent_id;
+        if (dest_id.notNull())
+        {
+            parent_id = dest_id;
+        }
+        else if (default_parent_uuid.notNull())
+        {
+            parent_id = default_parent_uuid;
+        }
+        else
+        {
+            parent_id = gInventory.getRootFolderID();
+        }
+
+        std::function<void(const LLUUID&)> callback_cat_created = NULL;
+        if (panel)
+        {
+            LLHandle<LLPanel> handle = panel->getHandle();
+            callback_cat_created = [handle](const LLUUID& new_category_id)
+            {
+                gInventory.notifyObservers();
+                LLInventoryPanel* panel = static_cast<LLInventoryPanel*>(handle.get());
+                if (panel)
+                {
+                    panel->setSelectionByID(new_category_id, TRUE);
+                }
+                LL_DEBUGS(LOG_INV) << "Done creating inventory: " << new_category_id << LL_ENDL;
+            };
+        }
+        else if (created_cb != NULL)
+        {
+            callback_cat_created = created_cb;
+        }
+        gInventory.createNewCategory(
+            parent_id,
+            preferred_type,
+            LLStringUtil::null,
+            callback_cat_created);
+    }
+    else if ("lsl" == type_name)
+    {
+        const LLUUID parent_id = dest_id.notNull() ? dest_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_LSL_TEXT);
+        create_new_item(NEW_LSL_NAME,
+                      parent_id,
+                      LLAssetType::AT_LSL_TEXT,
+                      LLInventoryType::IT_LSL,
+                      PERM_MOVE | PERM_TRANSFER,
+                      created_cb);    // overridden in create_new_item
+    }
+    else if ("notecard" == type_name)
+    {
+        const LLUUID parent_id = dest_id.notNull() ? dest_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_NOTECARD);
+        create_new_item(NEW_NOTECARD_NAME,
+                      parent_id,
+                      LLAssetType::AT_NOTECARD,
+                      LLInventoryType::IT_NOTECARD,
+                      PERM_ALL,
+                      created_cb);    // overridden in create_new_item
+    }
+    else if ("gesture" == type_name)
+    {
+        const LLUUID parent_id = dest_id.notNull() ? dest_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
+        create_new_item(NEW_GESTURE_NAME,
+                      parent_id,
+                      LLAssetType::AT_GESTURE,
+                      LLInventoryType::IT_GESTURE,
+                      PERM_ALL,
+                      created_cb);    // overridden in create_new_item
+    }
     else if ("material" == type_name)
     {
-        const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_MATERIAL);
+        const LLUUID parent_id = dest_id.notNull() ? dest_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_MATERIAL);
         create_new_item(NEW_MATERIAL_NAME,
             parent_id,
             LLAssetType::AT_MATERIAL,
             LLInventoryType::IT_MATERIAL,
-            PERM_ALL);	// overridden in create_new_item
+            PERM_ALL,
+            created_cb);	// overridden in create_new_item
     }
     else if (("sky" == type_name) || ("water" == type_name) || ("daycycle" == type_name))
     {
@@ -2203,25 +2187,28 @@ void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge,
             return;
         }
 
-        LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS);
+        LLUUID parent_id = dest_id.notNull() ? dest_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS);
 
-        LLSettingsVOBase::createNewInventoryItem(stype, parent_id);
+        LLSettingsVOBase::createNewInventoryItem(stype, parent_id, created_cb);
+    }
+    else
+    {
+        // Use for all clothing and body parts.  Adding new wearable types requires updating LLWearableDictionary.
+        LLWearableType::EType wearable_type = LLWearableType::getInstance()->typeNameToType(type_name);
+        if (wearable_type >= LLWearableType::WT_SHAPE && wearable_type < LLWearableType::WT_COUNT)
+        {
+            const LLUUID parent_id = dest_id;
+            LLAgentWearables::createWearable(wearable_type, false, parent_id, created_cb);
+        }
+        else
+        {
+            LL_WARNS(LOG_INV) << "Can't create unrecognized type " << type_name << LL_ENDL;
+        }
+    }
+    if(panel)
+    {
+        panel->getRootFolder()->setNeedsAutoRename(TRUE);
     }
-	else
-	{
-		// Use for all clothing and body parts.  Adding new wearable types requires updating LLWearableDictionary.
-		LLWearableType::EType wearable_type = LLWearableType::getInstance()->typeNameToType(type_name);
-		if (wearable_type >= LLWearableType::WT_SHAPE && wearable_type < LLWearableType::WT_COUNT)
-		{
-			const LLUUID parent_id = bridge ? bridge->getUUID() : LLUUID::null;
-			LLAgentWearables::createWearable(wearable_type, false, parent_id);
-		}
-		else
-		{
-			LL_WARNS(LOG_INV) << "Can't create unrecognized type " << type_name << LL_ENDL;
-		}
-	}
-	panel->getRootFolder()->setNeedsAutoRename(TRUE);	
 }
 
 LLAssetType::EType LLViewerInventoryItem::getType() const
@@ -2347,6 +2334,25 @@ const LLSaleInfo& LLViewerInventoryItem::getSaleInfo() const
 	return LLInventoryItem::getSaleInfo();
 }
 
+const LLUUID& LLViewerInventoryItem::getThumbnailUUID() const
+{
+    if (mThumbnailUUID.isNull() && mType == LLAssetType::AT_TEXTURE)
+    {
+        return mAssetUUID;
+    }
+    if (mThumbnailUUID.isNull() && mType == LLAssetType::AT_LINK)
+    {
+        LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID);
+        return linked_item ? linked_item->getThumbnailUUID() : LLUUID::null;
+    }
+    if (mThumbnailUUID.isNull() && mType == LLAssetType::AT_LINK_FOLDER)
+    {
+        LLViewerInventoryCategory *linked_cat = gInventory.getCategory(mAssetUUID);
+        return linked_cat ? linked_cat->getThumbnailUUID() : LLUUID::null;
+    }
+    return mThumbnailUUID;
+}
+
 LLInventoryType::EType LLViewerInventoryItem::getInventoryType() const
 {
 	if (const LLViewerInventoryItem *linked_item = getLinkedItem())
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 93ec4efc7d4d9c6fc570485d5b58d32b74031dc1..fe48b9da9b30983e72d648666c6191518f05b2c6 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -75,6 +75,7 @@ class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::tr
 	virtual const LLUUID& getCreatorUUID() const;
 	virtual const std::string& getDescription() const;
 	virtual const LLSaleInfo& getSaleInfo() const;
+    virtual const LLUUID& getThumbnailUUID() const;
 	virtual LLInventoryType::EType getInventoryType() const;
 	virtual bool isWearableType() const;
 	virtual LLWearableType::EType getWearableType() const;
@@ -141,8 +142,8 @@ class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::tr
 	virtual BOOL importLegacyStream(std::istream& input_stream);
 
 	// new methods
-	BOOL isFinished() const { return mIsComplete; }
-	void setComplete(BOOL complete) { mIsComplete = complete; }
+	bool isFinished() const { return mIsComplete; }
+	void setComplete(bool complete) { mIsComplete = complete; }
 	//void updateAssetOnServer() const;
 
 	virtual void setTransactionID(const LLTransactionID& transaction_id);
@@ -170,7 +171,7 @@ class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::tr
 	BOOL regenerateLink();
 
 public:
-	BOOL mIsComplete;
+	bool mIsComplete;
 	LLTransactionID mTransactionID;
 };
 
@@ -215,9 +216,18 @@ class LLViewerInventoryCategory  : public LLInventoryCategory
 	S32 getVersion() const;
 	void setVersion(S32 version);
 
-	// Returns true if a fetch was issued.
+	// Returns true if a fetch was issued (not nessesary in progress).
 	bool fetch();
 
+    typedef enum {
+        FETCH_NONE = 0,
+        FETCH_NORMAL,
+        FETCH_RECURSIVE,
+    } EFetchType;
+    EFetchType getFetching();
+    // marks as fetch being in progress or as done
+    void setFetching(EFetchType);
+
 	// used to help make caching more robust - for example, if
 	// someone is getting 4 packets but logs out after 3. the viewer
 	// may never know the cache is wrong.
@@ -246,12 +256,14 @@ class LLViewerInventoryCategory  : public LLInventoryCategory
 	LLUUID mOwnerID;
 	S32 mVersion;
 	S32 mDescendentCount;
+    EFetchType mFetching;
 	LLFrameTimer mDescendentsRequested;
 };
 
 class LLInventoryCallback : public LLRefCount
 {
 public:
+    virtual ~LLInventoryCallback() {}
 	virtual void fire(const LLUUID& inv_item) = 0;
 };
 
@@ -293,17 +305,29 @@ class LLBoostFuncInventoryCallback: public LLInventoryCallback
 {
 public:
 
-	LLBoostFuncInventoryCallback(inventory_func_type fire_func = no_op_inventory_func,
+	LLBoostFuncInventoryCallback(inventory_func_type fire_func,
 								 nullary_func_type destroy_func = no_op):
-		mFireFunc(fire_func),
 		mDestroyFunc(destroy_func)
 	{
+        mFireFuncs.push_back(fire_func);
 	}
 
+    LLBoostFuncInventoryCallback()
+    {
+    }
+
+    void addOnFireFunc(inventory_func_type fire_func)
+    {
+        mFireFuncs.push_back(fire_func);
+    }
+
 	// virtual
 	void fire(const LLUUID& item_id)
     {
-		mFireFunc(item_id);
+        for (inventory_func_type &func: mFireFuncs)
+        {
+            func(item_id);
+        }
 	}
 
 	// virtual
@@ -314,7 +338,7 @@ class LLBoostFuncInventoryCallback: public LLInventoryCallback
 	
 
 private:
-	inventory_func_type mFireFunc;
+	std::list<inventory_func_type> mFireFuncs;
 	nullary_func_type mDestroyFunc;
 };
 
@@ -459,6 +483,8 @@ void menu_create_inventory_item(LLInventoryPanel* root,
 								const LLSD& userdata,
 								const LLUUID& default_parent_uuid = LLUUID::null);
 
+void menu_create_inventory_item(LLInventoryPanel* panel, LLUUID dest_id, const LLSD& userdata, const LLUUID& default_parent_uuid = LLUUID::null, std::function<void(const LLUUID&)> folder_created_cb = NULL);
+
 void slam_inventory_folder(const LLUUID& folder_id,
 						   const LLSD& contents,
 						   LLPointer<LLInventoryCallback> cb);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 5f4f5bd82236370f3b48d25b493d8265f4a07241..9e116a855e4056da34955850c8bb9194a83001f5 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -439,14 +439,14 @@ void LLSLMMenuUpdater::setMerchantMenu()
 
 	if(in_sl)
 	{
-	    const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+	    const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
 	    if (marketplacelistings_id.isNull())
 	    {
 	        U32 mkt_status = LLMarketplaceData::instance().getSLMStatus();
 	        bool is_merchant = (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) || (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MIGRATED_MERCHANT);
 	        if (is_merchant)
 	        {
-	            gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true);
+	            gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MARKETPLACE_LISTINGS);
 	            LL_WARNS("SLM") << "Creating the marketplace listings folder for a merchant" << LL_ENDL;
 	        }
 	    }
@@ -3167,9 +3167,7 @@ void handle_object_inspect()
 	LLViewerObject* selected_objectp = selection->getFirstRootObject();
 	if (selected_objectp)
 	{
-		LLSD key;
-		key["task"] = "task";
-		LLFloaterSidePanelContainer::showPanel("inventory", key);
+        LLFloaterReg::showInstance("task_properties");
 	}
 	
 	/*
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 1706ed8234c87b7791a0eec137f60d1cd6451c09..762fd006e1615be207b825a93dfd5cf1a7b8c96b 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -40,7 +40,7 @@
 #include "llmaterialeditor.h"
 #include "llfloaterperms.h"
 #include "llfloatersnapshot.h"
-#include "llfloatersimpleoutfitsnapshot.h"
+#include "llfloatersimplesnapshot.h"
 #include "llimage.h"
 #include "llimagebmp.h"
 #include "llimagepng.h"
@@ -849,9 +849,7 @@ class LLFileEnableCloseAllWindows : public view_listener_t
 	bool handleEvent(const LLSD& userdata) override
     {
 		LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance();
-		LLFloaterSimpleOutfitSnapshot* floater_outfit_snapshot = LLFloaterSimpleOutfitSnapshot::findInstance();
-		bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain())
-			|| (floater_outfit_snapshot && floater_outfit_snapshot->isInVisibleChain());
+		bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain());
 		bool open_children = gFloaterView->allChildrenClosed() && !is_floaters_snapshot_opened;
 		return !open_children && !LLNotificationsUI::LLToast::isAlertToastShown();
 	}
@@ -866,9 +864,6 @@ class LLFileCloseAllWindows : public view_listener_t
 		LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance();
 		if (floater_snapshot)
 			floater_snapshot->closeFloater(app_quitting);
-        LLFloaterSimpleOutfitSnapshot* floater_outfit_snapshot = LLFloaterSimpleOutfitSnapshot::findInstance();
-		if (floater_outfit_snapshot)
-			floater_outfit_snapshot->closeFloater(app_quitting);
 		if (gMenuHolder) gMenuHolder->hideMenus();
 		return true;
 	}
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index a77b2716992a21855cc32ee4ec4f8802dffe62b6..7d03d0d161543cffa94963340a2cddb241b90ff2 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -78,6 +78,7 @@
 #include "llnotifications.h"
 #include "llnotificationsutil.h"
 #include "llpanelgrouplandmoney.h"
+#include "llpanelmaininventory.h"
 #include "llrecentpeople.h"
 #include "llscriptfloater.h"
 #include "llscriptruntimeperms.h"
@@ -1558,11 +1559,35 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam
 		}
 
 		////////////////////////////////////////////////////////////////////////////////
-		// Highlight item
-		// Only show if either ShowInInventory is true OR it is an inventory
-		// offer from an agent and the asset is not previewable
-		const BOOL auto_open = gSavedSettings.getBOOL("ShowInInventory") || (manual_offer && !check_asset_previewable(asset_type));
-		if (auto_open) LLInventoryPanel::openInventoryPanelAndSetSelection(auto_open, obj_id);
+        static LLUICachedControl<bool> find_original_new_floater("FindOriginalOpenWindow", false);
+        //show in a new single-folder window
+        if(find_original_new_floater && !from_name.empty())
+        {
+            const LLInventoryObject *obj = gInventory.getObject(obj_id);
+            if (obj && obj->getParentUUID().notNull())
+            {
+                if (obj->getActualType() == LLAssetType::AT_CATEGORY)
+                {
+                    LLPanelMainInventory::newFolderWindow(obj_id);
+                }
+                else
+                {
+                    LLPanelMainInventory::newFolderWindow(obj->getParentUUID(), obj_id);
+                }
+            }
+        }
+        else
+        {
+            // Highlight item
+            // Only show if either ShowInInventory is true OR it is an inventory
+            // offer from an agent and the asset is not previewable
+            const BOOL auto_open = gSavedSettings.getBOOL("ShowInInventory") || (manual_offer && !check_asset_previewable(asset_type));
+            if(auto_open)
+            {
+                LLFloaterReg::showInstance("inventory");
+            }
+            if (auto_open) LLInventoryPanel::openInventoryPanelAndSetSelection(auto_open, obj_id, true);
+        }
 	}
 }
 
@@ -6385,42 +6410,47 @@ void container_inventory_arrived(LLViewerObject* object,
 	{
 		// create a new inventory category to put this in
 		LLUUID cat_id;
-		cat_id = gInventory.createNewCategory(gInventory.getRootFolderID(),
-											  LLFolderType::FT_NONE,
-											  LLTrans::getString("AcquiredItems"));
+		gInventory.createNewCategory(
+            gInventory.getRootFolderID(),
+            LLFolderType::FT_NONE,
+            LLTrans::getString("AcquiredItems"),
+            [inventory](const LLUUID &new_cat_id)
+        {
+            LLInventoryObject::object_list_t::const_iterator it = inventory->begin();
+            LLInventoryObject::object_list_t::const_iterator end = inventory->end();
+            for (; it != end; ++it)
+            {
+                if ((*it)->getType() != LLAssetType::AT_CATEGORY)
+                {
+                    LLInventoryObject* obj = (LLInventoryObject*)(*it);
+                    LLInventoryItem* item = (LLInventoryItem*)(obj);
+                    LLUUID item_id;
+                    item_id.generate();
+                    time_t creation_date_utc = time_corrected();
+                    LLPointer<LLViewerInventoryItem> new_item
+                        = new LLViewerInventoryItem(item_id,
+                            new_cat_id,
+                            item->getPermissions(),
+                            item->getAssetUUID(),
+                            item->getType(),
+                            item->getInventoryType(),
+                            item->getName(),
+                            item->getDescription(),
+                            LLSaleInfo::DEFAULT,
+                            item->getFlags(),
+                            creation_date_utc);
+                    new_item->updateServer(TRUE);
+                    gInventory.updateItem(new_item);
+                }
+            }
+            gInventory.notifyObservers();
 
-		LLInventoryObject::object_list_t::const_iterator it = inventory->begin();
-		LLInventoryObject::object_list_t::const_iterator end = inventory->end();
-		for ( ; it != end; ++it)
-		{
-			if ((*it)->getType() != LLAssetType::AT_CATEGORY)
-			{
-				LLInventoryObject* obj = (LLInventoryObject*)(*it);
-				LLInventoryItem* item = (LLInventoryItem*)(obj);
-				LLUUID item_id;
-				item_id.generate();
-				time_t creation_date_utc = time_corrected();
-				LLPointer<LLViewerInventoryItem> new_item
-					= new LLViewerInventoryItem(item_id,
-												cat_id,
-												item->getPermissions(),
-												item->getAssetUUID(),
-												item->getType(),
-												item->getInventoryType(),
-												item->getName(),
-												item->getDescription(),
-												LLSaleInfo::DEFAULT,
-												item->getFlags(),
-												creation_date_utc);
-				new_item->updateServer(TRUE);
-				gInventory.updateItem(new_item);
-			}
-		}
-		gInventory.notifyObservers();
-		if(active_panel)
-		{
-			active_panel->setSelection(cat_id, TAKE_FOCUS_NO);
-		}
+            LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
+            if (active_panel)
+            {
+                active_panel->setSelection(new_cat_id, TAKE_FOCUS_NO);
+            }
+        });
 	}
 	else if (inventory->size() == 2)
 	{
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 019a46ac8fe6900cc0624a20fe290275981f4be0..11706499a70f171844d8299388b0119228429571 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -63,7 +63,6 @@
 #include "llcontrolavatar.h"
 #include "lldrawable.h"
 #include "llface.h"
-#include "llfloaterproperties.h"
 #include "llfloatertools.h"
 #include "llfollowcam.h"
 #include "llhudtext.h"
@@ -3546,9 +3545,6 @@ void LLViewerObject::doInventoryCallback()
 
 void LLViewerObject::removeInventory(const LLUUID& item_id)
 {
-	// close any associated floater properties
-	LLFloaterReg::hideInstance("properties", item_id);
-
 	LLMessageSystem* msg = gMessageSystem;
 	msg->newMessageFast(_PREHASH_RemoveTaskInventory);
 	msg->nextBlockFast(_PREHASH_AgentData);
@@ -6334,8 +6330,7 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para
       }
 	  default:
 	  {
-          llassert(false); // invalid parameter type
-			LL_INFOS() << "Unknown param type. (" << llformat("0x%2x", param_type) << ")" << LL_ENDL;
+		  LL_INFOS_ONCE() << "Unknown param type. (" << llformat("0x%2x", param_type) << ")" << LL_ENDL;
 		  break;
 	  }
 	};
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 1863ae0c2e015e8476548d08dd247ca06893ee2a..e14f78fd00e2eea512b671fba943bd8af3077dd3 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -3356,6 +3356,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 
 	capabilityNames.append("InterestList");
 
+    capabilityNames.append("InventoryThumbnailUpload");
 	capabilityNames.append("GetDisplayNames");
 	capabilityNames.append("GetExperiences");
 	capabilityNames.append("AgentExperiences");
diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp
index 5eaebc422f6c51c6f6e4681ea09ad1a84b1e7b0c..c6ad8323bac8a426be8dcbf4aa347a99b8a4150a 100644
--- a/indra/newview/llviewertexteditor.cpp
+++ b/indra/newview/llviewertexteditor.cpp
@@ -36,6 +36,7 @@
 #include "llfloatersidepanelcontainer.h"
 #include "llfloaterworldmap.h"
 #include "llfocusmgr.h"
+#include "llinspecttexture.h"
 #include "llinventorybridge.h"
 #include "llinventorydefines.h"
 #include "llinventorymodel.h"
@@ -244,6 +245,21 @@ class LLEmbeddedItemSegment : public LLTextSegment
 	}
 	virtual BOOL				handleToolTip(S32 x, S32 y, MASK mask )
 	{ 
+		if (mItem->getThumbnailUUID().notNull())
+		{
+            LLSD params;
+            params["inv_type"] = mItem->getInventoryType();
+            params["thumbnail_id"] = mItem->getThumbnailUUID();
+            params["asset_id"] = mItem->getAssetUUID();
+            
+			LLToolTipMgr::instance().show(LLToolTip::Params()
+					.message(mToolTip)
+					.create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1))
+					.create_params(params));
+
+			return TRUE;
+		}
+
 		if (!mToolTip.empty())
 		{
 			LLToolTipMgr::instance().show(mToolTip);
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index d47dd8ca29b4c52fd5ec92190e7fefd9e626555d..bce1fc0c0e8a1cf05725e684823937e91e698f04 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -1260,11 +1260,52 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
 #endif
 }
 
+bool LLViewerTextureList::createUploadFile(LLPointer<LLImageRaw> raw_image,
+                                           const std::string& out_filename,
+                                           const S32 max_image_dimentions,
+                                           const S32 min_image_dimentions)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+
+    // make a copy, since convertToUploadFile scales raw image
+    LLPointer<LLImageRaw> scale_image = new LLImageRaw(
+        raw_image->getData(),
+        raw_image->getWidth(),
+        raw_image->getHeight(),
+        raw_image->getComponents());
+
+    LLPointer<LLImageJ2C> compressedImage = LLViewerTextureList::convertToUploadFile(scale_image, max_image_dimentions);
+    if (compressedImage->getWidth() < min_image_dimentions || compressedImage->getHeight() < min_image_dimentions)
+    {
+        std::string reason = llformat("Images below %d x %d pixels are not allowed. Actual size: %d x %dpx",
+                                      min_image_dimentions,
+                                      min_image_dimentions,
+                                      compressedImage->getWidth(),
+                                      compressedImage->getHeight());
+        compressedImage->setLastError(reason);
+        return false;
+    }
+    if (compressedImage.isNull())
+    {
+        compressedImage->setLastError("Couldn't convert the image to jpeg2000.");
+        LL_INFOS() << "Couldn't convert to j2c, file : " << out_filename << LL_ENDL;
+        return false;
+    }
+    if (!compressedImage->save(out_filename))
+    {
+        compressedImage->setLastError("Couldn't create the jpeg2000 image for upload.");
+        LL_INFOS() << "Couldn't create output file : " << out_filename << LL_ENDL;
+        return false;
+    }
+    return true;
+}
 
 BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
 										 const std::string& out_filename,
 										 const U8 codec,
-										 const S32 max_image_dimentions)
+										 const S32 max_image_dimentions,
+										 const S32 min_image_dimentions,
+										 bool force_square)
 {	
     LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// Load the image
@@ -1292,8 +1333,18 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
 		image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
 		return FALSE;
 	}
+    if (image->getWidth() < min_image_dimentions || image->getHeight() < min_image_dimentions)
+    {
+        std::string reason = llformat("Images below %d x %d pixels are not allowed. Actual size: %d x %dpx",
+            min_image_dimentions,
+            min_image_dimentions,
+            image->getWidth(),
+            image->getHeight());
+        image->setLastError(reason);
+        return FALSE;
+    }
 	// Convert to j2c (JPEG2000) and save the file locally
-	LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image, max_image_dimentions);
+	LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image, max_image_dimentions, force_square);
 	if (compressedImage.isNull())
 	{
 		image->setLastError("Couldn't convert the image to jpeg2000.");
@@ -1318,10 +1369,20 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
 }
 
 // note: modifies the argument raw_image!!!!
-LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImageRaw> raw_image, const S32 max_image_dimentions, bool force_lossless)
+LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImageRaw> raw_image, const S32 max_image_dimentions, bool force_square, bool force_lossless)
 {
 	LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
-	raw_image->biasedScaleToPowerOfTwo(max_image_dimentions);
+    if (force_square)
+    {
+        S32 biggest_side = llmax(raw_image->getWidth(), raw_image->getHeight());
+        S32 square_size = raw_image->biasedDimToPowerOfTwo(biggest_side, max_image_dimentions);
+
+        raw_image->scale(square_size, square_size);
+    }
+    else
+    {
+        raw_image->biasedScaleToPowerOfTwo(max_image_dimentions);
+    }
 	LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C();
 	
     if (force_lossless ||
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index bd4cbf5fa80702f160cf022333b821a01808ba20..04964e6128acd26dfcf5a8c7e26b9af78be8cbe0 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -107,11 +107,20 @@ class LLViewerTextureList
 	friend class LLLocalBitmap;
 	
 public:
+    static bool createUploadFile(LLPointer<LLImageRaw> raw_image,
+                                 const std::string& out_filename,
+                                 const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT,
+                                 const S32 min_image_dimentions = 0);
     static BOOL createUploadFile(const std::string& filename,
                                  const std::string& out_filename,
                                  const U8 codec,
-                                 const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
-	static LLPointer<LLImageJ2C> convertToUploadFile(LLPointer<LLImageRaw> raw_image, const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT, bool force_lossless = false);
+                                 const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT,
+                                 const S32 min_image_dimentions = 0,
+                                 bool force_square = false);
+	static LLPointer<LLImageJ2C> convertToUploadFile(LLPointer<LLImageRaw> raw_image,
+                                                     const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT,
+                                                     bool force_square = false,
+                                                     bool force_lossless = false);
 	static void processImageNotInDatabase( LLMessageSystem *msg, void **user_data );
 
 public:
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 94f07fb346aaebfe8fef457c8322ea1cc11a8a87..6d2add0077dd7fd97f6eec2bc90137b92160d710 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -9711,7 +9711,14 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 	// RequestAgentUpdateAppearanceResponder::onRequestRequested()
 	// assumes that cof version is only updated with server-bake
 	// appearance messages.
-    LL_INFOS("Avatar") << "Processing appearance message version " << thisAppearanceVersion << LL_ENDL;
+    if (isSelf())
+    {
+        LL_INFOS("Avatar") << "Processing appearance message version " << thisAppearanceVersion << LL_ENDL;
+    }
+    else
+    {
+        LL_INFOS("Avatar") << "Processing appearance message for " << getID() << ", version " << thisAppearanceVersion << LL_ENDL;
+    }
 
     // Note:
     // locally the COF is maintained via LLInventoryModel::accountForUpdate
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index a6341d9c9a5895ae8b5a1209f889e816ceadc343..e285ea1babaa533c24b81630c76199020b5f9d45 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5115,8 +5115,6 @@ void LLControlAVBridge::updateSpatialExtents()
 {
 	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
 
-	LLControlAvatar* controlAvatar = getVObj()->getControlAvatar();
-
 	LLSpatialGroup* root = (LLSpatialGroup*)mOctree->getListener(0);
 
 	bool rootWasDirty = root->isDirty();
@@ -5127,7 +5125,11 @@ void LLControlAVBridge::updateSpatialExtents()
 	// disappear when root goes off-screen"
 	//
 	// Expand extents to include Control Avatar placed outside of the bounds
-	if (controlAvatar && controlAvatar->mDrawable && (rootWasDirty || controlAvatar->mPlaying))
+    LLControlAvatar* controlAvatar = getVObj() ? getVObj()->getControlAvatar() : NULL;
+    if (controlAvatar
+        && controlAvatar->mDrawable
+        && controlAvatar->mDrawable->getEntry()
+        && (rootWasDirty || controlAvatar->mPlaying))
 	{
 		root->expandExtents(controlAvatar->mDrawable->getSpatialExtents(), *mDrawable->getXform());
 	}
diff --git a/indra/newview/rlvinventory.cpp b/indra/newview/rlvinventory.cpp
index 5e592f74cff3ca121c0f124fdb301445792f8c8e..b2201fcc6ff055124889dd446f1aed477de9bafc 100644
--- a/indra/newview/rlvinventory.cpp
+++ b/indra/newview/rlvinventory.cpp
@@ -476,12 +476,7 @@ void RlvRenameOnWearObserver::doneIdle()
 					{
 						// "No modify" item with a non-renameable parent: create a new folder named and move the item into it
 						inventory_func_type f = boost::bind(RlvRenameOnWearObserver::onCategoryCreate, _1, pItem->getUUID());
-						LLUUID idFolder = gInventory.createNewCategory(pFolder->getUUID(), LLFolderType::FT_NONE, strFolderName, f);
-						if (idFolder.notNull())
-						{
-							// Not using the new 'CreateInventoryCategory' cap so manually invoke the callback
-							RlvRenameOnWearObserver::onCategoryCreate(idFolder, pItem->getUUID());
-						}
+						gInventory.createNewCategory(pFolder->getUUID(), LLFolderType::FT_NONE, strFolderName, f);
 					}
 				}
 			}
@@ -529,9 +524,7 @@ bool RlvGiveToRLVOffer::createDestinationFolder(const std::string& strPath)
 			else
 			{
 				inventory_func_type f = boost::bind(RlvGiveToRLVOffer::onCategoryCreateCallback, _1, this);
-				const LLUUID idTemp = gInventory.createNewCategory(gInventory.getRootFolderID(), LLFolderType::FT_NONE, RLV_ROOT_FOLDER, f);
-				if (idTemp.notNull())
-					onCategoryCreateCallback(idTemp, this);
+				gInventory.createNewCategory(gInventory.getRootFolderID(), LLFolderType::FT_NONE, RLV_ROOT_FOLDER, f);
 			}
 			return true;
 		}
@@ -564,9 +557,7 @@ void RlvGiveToRLVOffer::onCategoryCreateCallback(LLUUID idFolder, RlvGiveToRLVOf
 		{
 			LLInventoryObject::correctInventoryName(strFolder);
 			inventory_func_type f = boost::bind(RlvGiveToRLVOffer::onCategoryCreateCallback, _1, pInstance);
-			const LLUUID idTemp = gInventory.createNewCategory(idFolder, LLFolderType::FT_NONE, strFolder, f);
-			if (idTemp.notNull())
-				onCategoryCreateCallback(idTemp, pInstance);
+			gInventory.createNewCategory(idFolder, LLFolderType::FT_NONE, strFolder, f);
 			return;
 		}
 	}
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index b95cb52a0e359f0dc834bfed44ce8dce5495dc88..c01ea9a755df0ed6cbf39b9ec6cbbc9caf143fe1 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -509,7 +509,7 @@
      value="0.43 0.06 0.06 1" />
     <color
      name="HTMLLinkColor"
-     reference="EmphasisColor" />
+     value="0.3 0.82 1 1" />
     <color
      name="HealthTextColor"
      reference="White" />
diff --git a/indra/newview/skins/default/textures/icons/copy_clipboard.png b/indra/newview/skins/default/textures/icons/copy_clipboard.png
new file mode 100644
index 0000000000000000000000000000000000000000..bb1ceff1ce55cdd0621d8c5672d8764e5e2531ea
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/copy_clipboard.png differ
diff --git a/indra/newview/skins/default/textures/icons/delete_icon.png b/indra/newview/skins/default/textures/icons/delete_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..37ce374653765e4e328eead84ca8f1ddc56e4415
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/delete_icon.png differ
diff --git a/indra/newview/skins/default/textures/icons/file_upload.png b/indra/newview/skins/default/textures/icons/file_upload.png
new file mode 100644
index 0000000000000000000000000000000000000000..58f2757136e77c1e923e22a583518799106c5b06
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/file_upload.png differ
diff --git a/indra/newview/skins/default/textures/icons/multi_folder_mode.png b/indra/newview/skins/default/textures/icons/multi_folder_mode.png
new file mode 100644
index 0000000000000000000000000000000000000000..8cda3efc365c878adb822f16e2ed73f7712b2b05
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/multi_folder_mode.png differ
diff --git a/indra/newview/skins/default/textures/icons/paste_clipboard.png b/indra/newview/skins/default/textures/icons/paste_clipboard.png
new file mode 100644
index 0000000000000000000000000000000000000000..e1589ab0983423760fced3c46720401aca39064e
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/paste_clipboard.png differ
diff --git a/indra/newview/skins/default/textures/icons/single_folder_back.png b/indra/newview/skins/default/textures/icons/single_folder_back.png
new file mode 100644
index 0000000000000000000000000000000000000000..b614e9ef9b594ba428acee44d50b9b996f5b0872
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/single_folder_back.png differ
diff --git a/indra/newview/skins/default/textures/icons/single_folder_forward.png b/indra/newview/skins/default/textures/icons/single_folder_forward.png
new file mode 100644
index 0000000000000000000000000000000000000000..c7bee3522d092939282ad9b3dd6eca5e5d4e5184
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/single_folder_forward.png differ
diff --git a/indra/newview/skins/default/textures/icons/single_folder_mode.png b/indra/newview/skins/default/textures/icons/single_folder_mode.png
new file mode 100644
index 0000000000000000000000000000000000000000..f70b754123e5d849943a69e2d2d64cdc0b5b919f
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/single_folder_mode.png differ
diff --git a/indra/newview/skins/default/textures/icons/single_folder_up.png b/indra/newview/skins/default/textures/icons/single_folder_up.png
new file mode 100644
index 0000000000000000000000000000000000000000..651b2b1af11769b7b2d689103cfa54f86d2a5db8
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/single_folder_up.png differ
diff --git a/indra/newview/skins/default/textures/icons/snapshot_icon.png b/indra/newview/skins/default/textures/icons/snapshot_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..41d524678f4e037f42b4a8fbcb53352800784955
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/snapshot_icon.png differ
diff --git a/indra/newview/skins/default/textures/icons/texture_icon.png b/indra/newview/skins/default/textures/icons/texture_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..278760a5b0e022c6d340103639b00b355fe73317
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/texture_icon.png differ
diff --git a/indra/newview/skins/default/textures/icons/thumbnail_fallback_icon.png b/indra/newview/skins/default/textures/icons/thumbnail_fallback_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..8d5ca624af31012a632d2bdc38caa3744082969b
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/thumbnail_fallback_icon.png differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 9372ec897d7715b1b17e7ce0fdb784967bedbfbb..44f626cb1f31d401d677de013634c873a0a41120 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -269,10 +269,16 @@ with the same filename but different name
   <texture name="Icon_Close_Foreground" file_name="windows/Icon_Close_Foreground.png" preload="true" />
   <texture name="Icon_Close_Press" file_name="windows/Icon_Close_Press.png" preload="true" />
   <texture name="Icon_Close_Toast" file_name="windows/Icon_Close_Toast.png" preload="true" />
+  
+  <texture name="Icon_Copy" file_name="icons/copy_clipboard.png" preload="true" />
+  
+  <texture name="Icon_Delete" file_name="icons/delete_icon.png" preload="true" />
 
   <texture name="Icon_Dock_Foreground" file_name="windows/Icon_Dock_Foreground.png" preload="true" />
   <texture name="Icon_Dock_Press" file_name="windows/Icon_Dock_Press.png" preload="true" />
 
+  <texture name="Icon_File_Upload" file_name="icons/file_upload.png" preload="true" />
+  
   <texture name="Icon_For_Sale" file_name="icons/Icon_For_Sale.png" preload="false" />
 
   <texture name="Icon_Gear_Background" file_name="windows/Icon_Gear_Background.png" preload="false" />
@@ -285,10 +291,16 @@ with the same filename but different name
 
   <texture name="Icon_Minimize_Foreground" file_name="windows/Icon_Minimize_Foreground.png" preload="true" />
   <texture name="Icon_Minimize_Press" file_name="windows/Icon_Minimize_Press.png" preload="true" />
+  
+  <texture name="Icon_Paste" file_name="icons/paste_clipboard.png" preload="true" />
 
   <texture name="Icon_Restore_Foreground" file_name="windows/Icon_Restore_Foreground.png" preload="false" />
   <texture name="Icon_Restore_Press" file_name="windows/Icon_Restore_Press.png" preload="false" />
 
+  <texture name="Icon_Snapshot" file_name="icons/snapshot_icon.png" preload="true" />
+  
+  <texture name="Icon_Use_Texture" file_name="icons/texture_icon.png" preload="true" />
+
   <texture name="Info" file_name="icons/Info.png" preload="false" />
   <texture name="Info_Small" file_name="icons/Info_Small.png" preload="false" />
   <texture name="Info_Off" file_name="navbar/Info_Off.png" preload="false" />
@@ -709,6 +721,7 @@ with the same filename but different name
   <texture name="TextField_Active" file_name="widgets/TextField_Active.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" />
   <texture name="TextField_Search_Highlight" file_name="widgets/TextField_Search_Highlight.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" />
 
+  <texture name="Thumbnail_Fallback" file_name="icons/thumbnail_fallback_icon.png" preload="true" />
 
   <texture name="Toast_CloseBtn" file_name="windows/Toast_CloseBtn.png" preload="true" />
   <texture name="Toast_Background" file_name="windows/Toast_Background.png" preload="true"
@@ -922,6 +935,12 @@ with the same filename but different name
   <texture name="Icon_Attachment_Small" file_name="icons/Icon_Attachment_Small.png"	preload="true"/>
   <texture name="Icon_Attachment_Large" file_name="icons/Icon_Attachment_Large.png"	preload="true"/>
 
+  <texture name="Single_Folder_Mode" file_name="icons/single_folder_mode.png" preload="true"/>
+  <texture name="Multi_Folder_Mode" file_name="icons/multi_folder_mode.png" preload="true"/>
+  <texture name="Single_Folder_Back" file_name="icons/single_folder_back.png" preload="true"/>
+  <texture name="Single_Folder_Forward" file_name="icons/single_folder_forward.png" preload="true"/>
+  <texture name="Single_Folder_Up" file_name="icons/single_folder_up.png" preload="true"/>
+ 
   <texture name="AlchemyRelease128" file_name="alchemy/alchemy_128.png" preload="false" />
   <texture name="AlchemyBeta128" file_name="alchemy/alchemybeta_128.png" preload="false" />
   <texture name="AlchemyProject128" file_name="alchemy/alchemyproject_128.png" preload="false" />
diff --git a/indra/newview/skins/default/xui/da/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/da/floater_inventory_item_properties.xml
deleted file mode 100644
index 59dcc87140a4e0844514ab25c10b50d84df5fd78..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/da/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="OPLYSNINGER OM BEHOLDNINGSGENSTAND">
-	<floater.string name="unknown">
-		(ukendt)
-	</floater.string>
-	<floater.string name="public">
-		(offentlig)
-	</floater.string>
-	<floater.string name="you_can">
-		Du kan:
-	</floater.string>
-	<floater.string name="owner_can">
-		Ejer kan:
-	</floater.string>
-	<floater.string name="acquiredDate">
-		[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
-	</floater.string>
-	<text name="LabelItemNameTitle">
-		Navn:
-	</text>
-	<text name="LabelItemDescTitle">
-		Beskrivelse:
-	</text>
-	<text name="LabelCreatorTitle">
-		Skaber:
-	</text>
-	<button label="Profil..." label_selected="" name="BtnCreator"/>
-	<text name="LabelOwnerTitle">
-		Ejer:
-	</text>
-	<button label="Profil..." label_selected="" name="BtnOwner"/>
-	<text name="LabelAcquiredTitle">
-		Erhvervet:
-	</text>
-	<text name="LabelAcquiredDate">
-		Wed May 24 12:50:46 2006
-	</text>
-	<text name="OwnerLabel">
-		Dig:
-	</text>
-	<check_box label="Redigér" name="CheckOwnerModify"/>
-	<check_box label="Kopiere" name="CheckOwnerCopy"/>
-	<check_box label="Sælg" name="CheckOwnerTransfer"/>
-	<text name="AnyoneLabel">
-		Enhver:
-	</text>
-	<check_box label="Kopiér" name="CheckEveryoneCopy"/>
-	<text name="GroupLabel">
-		Gruppe:
-	</text>
-	<check_box label="Del" name="CheckShareWithGroup"/>
-	<text name="NextOwnerLabel">
-		Næste ejer:
-	</text>
-	<check_box label="Redigér" name="CheckNextOwnerModify"/>
-	<check_box label="Kopiere" name="CheckNextOwnerCopy"/>
-	<check_box label="Sælg" name="CheckNextOwnerTransfer"/>
-	<check_box label="Til salg" name="CheckPurchase"/>
-	<combo_box name="combobox sale copy">
-		<combo_box.item label="Kopiér" name="Copy"/>
-		<combo_box.item label="Original" name="Original"/>
-	</combo_box>
-	<spinner label="Pris:" name="Edit Cost"/>
-	<text name="CurrencySymbol">
-		L$
-	</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/de/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/de/floater_inventory_item_properties.xml
deleted file mode 100644
index 92c038057f6ea43c6f03a9fde43af3629aa6bcc8..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/de/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="EIGENSCHAFTEN: INVENTAROBJEKT">
-	<floater.string name="unknown">(unbekannt)</floater.string>
-	<floater.string name="public">(öffentlich)</floater.string>
-	<floater.string name="you_can">Sie können:</floater.string>
-	<floater.string name="owner_can">Eigentümer kann:</floater.string>
-	<floater.string name="acquiredDate">[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]</floater.string>
-	<text name="LabelItemNameTitle">Name:</text>
-	<text name="LabelItemDescTitle">Beschreibung:</text>
-	<text name="LabelCreatorTitle">Ersteller:</text>
-	<button label="Profil..." label_selected="" name="BtnCreator"/>
-	<text name="LabelOwnerTitle">Eigentümer:</text>
-	<button label="Profil..." label_selected="" name="BtnOwner"/>
-	<text name="LabelAcquiredTitle">Erworben:</text>
-	<text name="LabelAcquiredDate">Mittwoch, 24. Mai 2006, 12:50:46</text>
-	<text name="OwnerLabel">Sie:</text>
-	<check_box label="Bearbeiten" name="CheckOwnerModify"/>
-	<check_box label="Kopieren" left_delta="85" name="CheckOwnerCopy"/>
-	<check_box label="Wiederverkaufen" name="CheckOwnerTransfer"/>
-	<text name="AnyoneLabel">Jeder:</text>
-	<check_box label="Kopieren" name="CheckEveryoneCopy"/>
-	<text name="GroupLabel">Gruppe:</text>
-	<check_box label="Teilen" name="CheckShareWithGroup"/>
-	<text name="NextOwnerLabel" width="150">Nächster Eigentümer:</text>
-	<check_box label="Bearbeiten" name="CheckNextOwnerModify"/>
-	<check_box label="Kopieren" left_delta="55" name="CheckNextOwnerCopy"/>
-	<check_box label="Wiederverkaufen" name="CheckNextOwnerTransfer"/>
-	<check_box label="Zum Verkauf" name="CheckPurchase"/>
-	<combo_box name="ComboBoxSaleType">
-		<combo_box.item label="Kopie" name="Copy"/>
-		<combo_box.item label="Inhalt" name="Contents"/>
-		<combo_box.item label="Original" name="Original"/>
-	</combo_box>
-	<spinner label="Preis:" name="Edit Cost"/>
-	<text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/de/panel_main_inventory.xml b/indra/newview/skins/default/xui/de/panel_main_inventory.xml
index a3adea9fa2e8a36c5e4058bf015a49a57b52b10b..175f6e1003f281de1f60837dc2a5857d436447c5 100644
--- a/indra/newview/skins/default/xui/de/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/de/panel_main_inventory.xml
@@ -9,6 +9,7 @@
 	<panel.string name="ItemcountUnknown">
 		Geholte [ITEM_COUNT] Bestellungen und [CATEGORY_COUNT] Ordner [FILTER]
 	</panel.string>
+    <panel.string name="inventory_title">INVENTAR</panel.string>
 	<text name="ItemcountText">
 		Objekte:
 	</text>
diff --git a/indra/newview/skins/default/xui/en/floater_change_item_thumbnail.xml b/indra/newview/skins/default/xui/en/floater_change_item_thumbnail.xml
new file mode 100644
index 0000000000000000000000000000000000000000..726cb38481b612c673e89cfcbfd3df3d4852f3b7
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_change_item_thumbnail.xml
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_resize="false"
+ height="366"
+ layout="topleft"
+ name="change_item_thumbnail"
+ help_topic="change_item_thumbnail"
+ title="CHANGE ITEM IMAGE"
+ width="319">
+
+  <floater.string
+    name="title_item_thumbnail">
+    CHANGE ITEM IMAGE
+  </floater.string>
+  <floater.string
+    name="title_folder_thumbnail">
+    CHANGE FOLDER IMAGE
+  </floater.string>
+  <floater.string
+    name="tooltip_upload_local">
+    Upload from computer
+  </floater.string>
+  <floater.string
+    name="tooltip_upload_snapshot">
+    Use snapshot tool
+  </floater.string>
+  <floater.string
+    name="tooltip_use_texture">
+    Choose texture
+  </floater.string>
+  <floater.string
+    name="tooltip_copy_to_clipboard">
+    Copy to clipboard
+  </floater.string>
+  <floater.string
+    name="tooltip_paste_from_clipboard">
+    Paste from clipboard
+  </floater.string>
+  <floater.string
+    name="tooltip_remove_image">
+    Remove image
+  </floater.string>
+  
+  <icon
+    follows="top|left"
+    height="16"
+    image_name="Inv_Object"
+    layout="topleft"
+    left="10"
+    mouse_opaque="true"
+    name="item_type_icon"
+    top="4"
+    width="16" />
+  <text
+    name="item_name"
+    font="SansSerif"
+    use_ellipses="true"
+    follows="left|top|right"
+    layout="topleft"
+    height="19"
+    top_delta="1"
+    left_pad="3"
+    width="286"/>
+
+  <thumbnail
+    name="item_thumbnail"
+    fallback_image="Thumbnail_Fallback"
+    follows="top|left"
+    layout="topleft"
+    left="32"
+    top_pad="9"
+    height="256"
+    width="256"
+        />
+
+  <button
+    follows="right|bottom"
+    layout="topleft"
+    image_hover_unselected="Toolbar_Middle_Over"
+    image_overlay="Icon_File_Upload"
+    image_selected="Toolbar_Middle_Selected"
+    image_unselected="Toolbar_Middle_Off"
+    name="upload_local"
+    left="38"
+    top_pad="9"
+    height="32"
+    width="32" />
+  <button
+    follows="right|bottom"
+    layout="topleft"
+    image_hover_unselected="Toolbar_Middle_Over"
+    image_overlay="Icon_Snapshot"
+    image_selected="Toolbar_Middle_Selected"
+    image_unselected="Toolbar_Middle_Off"
+    name="upload_snapshot"
+    left_pad="10"
+    top_delta="0"
+    height="32"
+    width="32" />
+  <button
+    follows="right|bottom"
+    layout="topleft"
+    image_hover_unselected="Toolbar_Middle_Over"
+    image_overlay="Icon_Use_Texture"
+    image_selected="Toolbar_Middle_Selected"
+    image_unselected="Toolbar_Middle_Off"
+    name="use_texture"
+    left_pad="10"
+    top_delta="0"
+    height="32"
+    width="32" />
+  <button
+    follows="right|bottom"
+    layout="topleft"
+    image_hover_unselected="Toolbar_Middle_Over"
+    image_overlay="Icon_Copy"
+    image_selected="Toolbar_Middle_Selected"
+    image_unselected="Toolbar_Middle_Off"
+    name="copy_to_clipboard"
+    left_pad="10"
+    top_delta="0"
+    height="32"
+    width="32" />
+  <button
+    follows="right|bottom"
+    layout="topleft"
+    image_hover_unselected="Toolbar_Middle_Over"
+    image_overlay="Icon_Paste"
+    image_selected="Toolbar_Middle_Selected"
+    image_unselected="Toolbar_Middle_Off"
+    name="paste_from_clipboard"
+    left_pad="10"
+    top_delta="0"
+    height="32"
+    width="32" />
+  <button
+    follows="right|bottom"
+    layout="topleft"
+    image_hover_unselected="Toolbar_Middle_Over"
+    image_overlay="Icon_Delete"
+    image_selected="Toolbar_Middle_Selected"
+    image_unselected="Toolbar_Middle_Off"
+    name="remove_image"
+    left_pad="10"
+    top_delta="0"
+    height="32"
+    width="32" />
+
+  <text
+    type="string"
+    halign="center"
+    length="1"
+    follows="left|top"
+    height="17"
+    layout="topleft"
+    left="5"
+    right="-5"
+    name="tooltip_text"
+    top_pad="12"
+    width="78">
+    tooltip
+  </text>
+  
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_inventory_settings.xml b/indra/newview/skins/default/xui/en/floater_inventory_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2e619d91fb71d9a71631fe84720295db4cb9df0d
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_inventory_settings.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_close="true"
+ can_minimize="true"
+ can_resize="false"
+ save_rect="true"
+ height="370"
+ width="370"
+ name="inventory_settings"
+ title="INVENTORY SETTINGS">
+ <icon
+  follows="top|left"
+  height="18"
+  image_name="Multi_Folder_Mode"
+  layout="topleft"
+  left="18"
+  mouse_opaque="true"
+  name="multi_folder_icon"
+  top="25"
+  width="18" />
+ <text
+   type="string"
+   length="1"
+   follows="left|top|right"
+   height="13"
+   layout="topleft"
+   left_pad="12"
+   top_delta="2"
+   name="multi_folder_txt"
+   font="SansSerifMedium"
+   text_color="White"
+   width="300">
+   Double-click on folder in multi-folder view:
+ </text>
+ <radio_group
+  control_name="MultiModeDoubleClickFolder"
+  follows="left|top"
+  top_pad="8"
+  layout="topleft"
+  font="SansSerifMedium"
+  left="60"
+  width="300"
+  height="70"
+  name="multi_double_click_setting">
+     <radio_item
+      height="20"
+      label="Expands &amp; collapses folder"
+      label_text.text_color="White"
+      follows="left|top"
+      layout="topleft"
+      name="0"
+      width="200"/>
+     <radio_item
+      height="20"
+      follows="left|top"
+      label="Opens a new window"
+      label_text.text_color="White"
+      layout="topleft"
+      left_delta="0"
+      name="1"
+      top_pad ="5"
+      width="200" />
+     <radio_item
+      height="20"
+      follows="left|top"
+      label="Switches view"
+      label_text.text_color="White"
+      layout="topleft"
+      left_delta="0"
+      name="2"
+      top_pad ="5"
+      width="200" />
+ </radio_group>
+ <icon
+  follows="top|left"
+  height="18"
+  image_name="Single_Folder_Mode"
+  layout="topleft"
+  left="18"
+  mouse_opaque="true"
+  name="single_folder_icon"
+  top_pad="30"
+  width="18" />
+ <text
+   type="string"
+   length="1"
+   follows="left|top|right"
+   height="13"
+   layout="topleft"
+   left_pad="12"
+   top_delta="2"
+   name="single_folder_txt"
+   font="SansSerifMedium"
+   text_color="White"
+   width="300">
+   Double-click on folder in single-folder view:
+ </text>
+ <radio_group
+  control_name="SingleModeDoubleClickOpenWindow"
+  follows="left|top"
+  top_pad="8"
+  layout="topleft"
+  font="SansSerifMedium"
+  left="60"
+  width="300"
+  height="45"
+  name="single_double_click_setting">
+     <radio_item
+      height="20"
+      label="Stays in current window"
+      label_text.text_color="White"
+      follows="left|top"
+      layout="topleft"
+      name="false"
+      width="200"/>
+     <radio_item
+      height="20"
+      follows="left|top"
+      label="Opens a new window"
+      label_text.text_color="White"
+      layout="topleft"
+      left_delta="0"
+      name="true"
+      top_pad ="5"
+      width="200" />
+ </radio_group>
+ <text
+   type="string"
+   length="1"
+   follows="left|top|right"
+   height="13"
+   layout="topleft"
+   left="48"
+   name="find_original_txt"
+   font="SansSerifMedium"
+   text_color="White"
+   top_pad="30"
+   width="300">
+   Clicking on "Show in inventory" or "Find original"
+ </text>
+ <radio_group
+  control_name="FindOriginalOpenWindow"
+  follows="left|top"
+  top_pad="8"
+  layout="topleft"
+  font="SansSerifMedium"
+  left="60"
+  width="300"
+  height="45"
+  name="find_original_settings">
+     <radio_item
+      height="20"
+      label="Shows item in main inventory window"
+      label_text.text_color="White"
+      follows="left|top"
+      layout="topleft"
+      name="false"
+      width="200"/>
+     <radio_item
+      height="20"
+      follows="left|top"
+      label="Opens a new single-folder window"
+      label_text.text_color="White"
+      layout="topleft"
+      left_delta="0"
+      name="true"
+      top_pad ="5"
+      width="200" />
+ </radio_group>
+ <button
+  height="20"
+  label="OK"
+  layout="topleft"
+  left="140"
+  bottom="-20"
+  name="ok_btn"
+  label_color="White"
+  width="90" />
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_item_properties.xml b/indra/newview/skins/default/xui/en/floater_item_properties.xml
index 0fc54a9c8bee6185c181311be586b6270cbe10f6..336bb902ca98c2e6c8d1e4b3e373fe17f06ee916 100644
--- a/indra/newview/skins/default/xui/en/floater_item_properties.xml
+++ b/indra/newview/skins/default/xui/en/floater_item_properties.xml
@@ -13,7 +13,7 @@
    left="0"
    class="sidepanel_item_info"
    filename="sidepanel_item_info.xml"
-   name="item_panel"
+   name="sidepanel"
    top="20"
    label=""
    height="570"
diff --git a/indra/newview/skins/default/xui/en/floater_my_inventory.xml b/indra/newview/skins/default/xui/en/floater_my_inventory.xml
index f182d27da8db93c010964470cbe3c2a622464e1a..a9900f05b7a79145462d6f4216aadd471dc7b444 100644
--- a/indra/newview/skins/default/xui/en/floater_my_inventory.xml
+++ b/indra/newview/skins/default/xui/en/floater_my_inventory.xml
@@ -5,14 +5,14 @@
  can_resize="true"
  height="570"
  help_topic="sidebar_inventory"
- min_width="333"
- min_height="590"
+ min_width="363"
+ min_height="270"
  name="floater_my_inventory"
  save_rect="true"
  save_visibility="true"
  reuse_instance="true"
  title="INVENTORY"
- width="333" >
+ width="363" >
    <panel
     class="sidepanel_inventory"
     name="main_panel"
diff --git a/indra/newview/skins/default/xui/en/floater_outfit_photo_preview.xml b/indra/newview/skins/default/xui/en/floater_outfit_photo_preview.xml
deleted file mode 100644
index bfc1c39e9db0cdfcc9aef0cf6e8f1599a4ca6219..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/en/floater_outfit_photo_preview.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<floater
- legacy_header_height="18"
- can_resize="false"
- height="325"
- layout="topleft"
- name="outfit_photo_preview"
- help_topic="preview_texture"
- width="410">
-   <floater.string
-     name="Title">
-        Texture: [NAME]
-    </floater.string>
-    <floater.string
-     name="exceed_limits">
-        Max outfit photo size is [MAX_WIDTH]*[MAX_HEIGHT]. Please select another texture.
-    </floater.string>
-    <floater.string
-     name="photo_confirmation">
-         Set this as Outfit Photo for [OUTFIT]?
-    </floater.string>
-    <text
-     type="string"
-     halign="right"
-     length="1"
-     follows="right|bottom"
-     height="16"
-     layout="topleft"
-     left="110"
-     name="dimensions"
-     top="255"
-     width="200">
-        [WIDTH]px x [HEIGHT]px
-    </text>
-    <text
-     type="string"
-     follows="left|top"
-     height="16"
-     layout="topleft"
-     name="notification"
-     left="25"
-     halign="center"
-     top_pad="5"
-     width="360">
-    </text>
-    <button
-     follows="right|bottom"
-     height="22"
-     label="OK"
-     layout="topleft"
-     name="ok_btn"
-     top_pad="5"
-     right="-115"
-     top_delta="0"
-     width="90" />
-    <button
-     follows="right|bottom"
-     height="22"
-     label="Cancel"
-     layout="topleft"
-     name="cancel_btn"
-     right="-20"
-     top_delta="0"
-     width="90" />
-</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_simple_outfit_snapshot.xml b/indra/newview/skins/default/xui/en/floater_simple_snapshot.xml
similarity index 86%
rename from indra/newview/skins/default/xui/en/floater_simple_outfit_snapshot.xml
rename to indra/newview/skins/default/xui/en/floater_simple_snapshot.xml
index 5ece7b85d583842c84d35f68701e05d7efd602e2..484ad159d13b92cc295492d3a414c45a8adde1ea 100644
--- a/indra/newview/skins/default/xui/en/floater_simple_outfit_snapshot.xml
+++ b/indra/newview/skins/default/xui/en/floater_simple_snapshot.xml
@@ -2,17 +2,17 @@
 <floater
  positioning="cascading"
  legacy_header_height="18"
- can_minimize="true"
+ can_minimize="false"
  can_resize="false"
  can_close="true"
  height="305"
  layout="topleft"
- name="simple_outfit_snapshot"
- single_instance="true"
+ name="simple_snapshot"
+ single_instance="false"
  help_topic="snapshot"
  save_rect="true"
  save_visibility="false"
- title="OUTFIT SNAPSHOT"
+ title="ITEM SNAPSHOT"
  width="351">
   <ui_ctrl
    layout="topleft"
@@ -36,7 +36,7 @@
    height="22"
    layout="topleft"
    left_pad="10"
-   label="Save (L$[UPLOAD_COST])"
+   label="Save"
    name="save_btn"
    width="90" />
   <button
diff --git a/indra/newview/skins/default/xui/en/floater_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml
index bccf0426bfbbee89ad988428ee6384a476d70d11..79734fa79669abbdd19bc4983f90d251316bbda6 100644
--- a/indra/newview/skins/default/xui/en/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml
@@ -444,7 +444,7 @@
     length="1"
     halign="right"
     name="360_label"
-    text_color="0.3 0.82 1 1"
+    text_color="HTMLLinkColor"
     top_delta="0"
     type="string"
     width="115">
diff --git a/indra/newview/skins/default/xui/en/floater_task_properties.xml b/indra/newview/skins/default/xui/en/floater_task_properties.xml
new file mode 100644
index 0000000000000000000000000000000000000000..56c236eab48f539d6b1274eb4db1d24faae8f615
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_task_properties.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ height="590"
+ layout="topleft"
+ name="Task Properties"
+ help_topic="item+properties"
+ title="ITEM PROPERTIES"
+ single_instance="true"
+ width="330">
+ <panel
+   follows="all"
+   layout="topleft"
+   left="0"
+   class="sidepanel_task_info"
+   filename="sidepanel_task_info.xml"
+   name="sidepanel"
+   top="20"
+   label=""
+   height="570"
+   visible="true"
+   width="330">
+ </panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
index 04cd78a1516fea6335ed08d1c9ab6487060a0f99..71e3a91a611cc9f4dc1f3df31415367c8a4cc1d2 100644
--- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
+++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
@@ -95,6 +95,22 @@ PICK: TEXTURE
      top_pad="4">
         [DIMENSIONS]
     </text>
+    <text
+     type="string"
+     text_color="Yellow"
+     length="1"
+     word_wrap="true"
+     follows="left|top"
+     height="56"
+     width="164"
+     layout="topleft"
+     left="8"
+     name="over_limit_lbl"
+     visible="false"
+     top_delta="0">
+        Selected texture is [TEXDIM]. Inventory image must be square, no less than [MINTEXDIM].
+    </text>
+    
 <!--  middle: inventory mode -->
 
     <button
diff --git a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d82c453e5f731328d4ca725ceb3108251d1c91ea
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml
@@ -0,0 +1,515 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+    layout="topleft"
+    name="Gallery">
+    <menu_item_call
+     label="Share"
+     layout="topleft"
+     name="Share">
+        <menu_item_call.on_click
+         function="Inventory.Share" />
+    </menu_item_call>
+    <menu_item_call
+     label="Empty Trash"
+     layout="topleft"
+     name="Empty Trash">
+        <menu_item_call.on_click
+         function="Inventory.EmptyTrash"/>
+    </menu_item_call>
+    <menu_item_call
+     label="Empty Lost And Found"
+     layout="topleft"
+     name="Empty Lost And Found">
+        <menu_item_call.on_click
+         function="Inventory.EmptyLostAndFound"/>
+    </menu_item_call>
+    <menu_item_call
+     label="Teleport"
+     layout="topleft"
+     name="Landmark Open">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="open" />
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft"
+     name="Folder Wearables Separator" />
+    <menu_item_call
+     label="Replace Current Outfit"
+     layout="topleft"
+     name="Replace Outfit">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="replaceoutfit" />
+    </menu_item_call>
+    <menu_item_call
+     label="Add To Current Outfit"
+     layout="topleft"
+     name="Add To Outfit">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="addtooutfit" />
+    </menu_item_call>
+    <menu_item_call
+     label="Remove From Current Outfit"
+     layout="topleft"
+     name="Remove From Outfit">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="removefromoutfit" />
+    </menu_item_call>
+    <menu_item_call
+     label="Copy outfit list to clipboard"
+     layout="topleft"
+     name="Copy outfit list to clipboard">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="copyoutfittoclipboard" />
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft"
+     name="Outfit Separator" />
+    <menu_item_call
+     label="Find Original"
+     layout="topleft"
+     name="Find Original">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="goto" />
+    </menu_item_call>
+    <menu_item_call
+     label="Purge Item"
+     layout="topleft"
+     name="Purge Item">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="purge"/>
+    </menu_item_call>
+    <menu_item_call
+     label="Restore Item"
+     layout="topleft"
+     name="Restore Item">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="restore" />
+    </menu_item_call>
+    <menu_item_call
+     label="Open"
+     layout="topleft"
+     name="Open">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="open" />
+    </menu_item_call>
+    <menu_item_call
+     label="Open Original"
+     layout="topleft"
+     name="Open Original">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="open_original" />
+    </menu_item_call>
+    <menu_item_call
+     label="Properties"
+     layout="topleft"
+     name="Properties">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="properties" />
+    </menu_item_call>
+    <menu_item_call
+     label="Image..."
+     layout="topleft"
+     name="thumbnail">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="thumbnail" />
+    </menu_item_call>
+    <menu_item_call
+     label="Copy Asset UUID"
+     layout="topleft"
+     name="Copy Asset UUID">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="copy_uuid" />
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft" 
+     name="Copy Separator" />
+    <menu_item_call
+     label="Open"
+     layout="topleft"
+     name="open_in_current_window">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="open_selected_folder" />
+    </menu_item_call>
+    <menu_item_call
+     label="Open in new window"
+     layout="topleft"
+     name="open_in_new_window">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="open_in_new_window" />
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft"
+     name="Open Folder Separator" />
+    <menu_item_call
+     label="Rename"
+     layout="topleft"
+     name="Rename">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="rename" />
+    </menu_item_call>
+    <menu_item_call
+     label="Cut"
+     layout="topleft"
+     name="Cut">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="cut" />
+    </menu_item_call>
+    <menu_item_call
+     label="Copy"
+     layout="topleft"
+     name="Copy">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste"
+     layout="topleft"
+     name="Paste">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="paste" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste As Link"
+     layout="topleft"
+     name="Paste As Link">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="paste_link" />
+    </menu_item_call>
+    <menu_item_call
+     label="Replace Links"
+     layout="topleft"
+     name="Replace Links">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="replace_links" />
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft" 
+     name="Paste Separator" />
+    <menu_item_call
+     label="Delete"
+     layout="topleft"
+     name="Delete">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="delete" />
+    </menu_item_call>
+    <menu_item_call
+     label="Delete System Folder"
+     layout="topleft"
+     name="Delete System Folder">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="delete_system_folder" />
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft" />
+    <menu_item_separator
+     layout="topleft" />
+    <menu_item_call
+     label="Play"
+     layout="topleft"
+     name="Sound Play">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="sound_play" />
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft"
+     name="Landmark Separator" />
+    <menu_item_call
+    label="Copy SLurl"
+    layout="topleft"
+    name="url_copy">
+       <menu_item_call.on_click
+        function="Inventory.DoToSelected"
+        parameter="copy_slurl" />
+   </menu_item_call> 
+   <menu_item_call
+     label="About Landmark"
+     layout="topleft"
+     name="About Landmark">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="about" />
+    </menu_item_call>
+   <menu_item_call
+     label="Show on Map"
+     layout="topleft"
+     name="show_on_map">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="show_on_map" />
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft" 
+     name="Animation Separator" />
+    <menu_item_call
+     label="Play Inworld"
+     layout="topleft"
+     name="Animation Play">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="playworld" />
+    </menu_item_call>
+    <menu_item_call
+     label="Play Locally"
+     layout="topleft"
+     name="Animation Audition">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="playlocal" />
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft" 
+     name="Send Instant Message Separator" />
+    <menu_item_call
+     label="Send Instant Message"
+     layout="topleft"
+     name="Send Instant Message">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="begin_im" />
+    </menu_item_call>
+    <menu_item_call
+     label="Offer Teleport..."
+     layout="topleft"
+     name="Offer Teleport...">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="lure" />
+    </menu_item_call>
+    <menu_item_call
+     label="Request Teleport..."
+     layout="topleft"
+     name="Request Teleport...">
+        <menu_item_call.on_click
+        function="Inventory.DoToSelected"
+        parameter="request_lure" />
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft" 
+     name="Gesture Separator" />
+    <menu_item_call
+     label="Activate"
+     layout="topleft"
+     name="Activate">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="activate" />
+    </menu_item_call>
+    <menu_item_call
+     label="Deactivate"
+     layout="topleft"
+     name="Deactivate">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="deactivate" />
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft" 
+     name="Texture Separator" />
+    <menu_item_call
+     label="Save As"
+     layout="topleft"
+     name="Save As">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="save_as" />
+    </menu_item_call>
+  <menu_item_call
+ label="Save Selected As"
+ layout="topleft"
+ name="Save Selected As">
+    <menu_item_call.on_click
+     function="Inventory.DoToSelected"
+     parameter="save_selected_as" />
+  </menu_item_call>
+    <menu_item_separator
+     layout="topleft" 
+     name="Wearable And Object Separator"/>
+    <menu_item_call
+     label="Wear"
+     layout="topleft"
+     name="Wearable And Object Wear">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="wear" />
+    </menu_item_call>
+    <menu
+     label="Attach To"
+     layout="topleft"
+     name="Attach To" />
+    <menu
+     label="Attach To HUD"
+     layout="topleft"
+     name="Attach To HUD" />
+    <menu_item_call
+     label="Touch"
+     layout="topleft"
+     name="Attachment Touch">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="touch" />
+    </menu_item_call>
+    <menu_item_call
+     label="Edit"
+     layout="topleft"
+     name="Wearable Edit">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="edit" />
+    </menu_item_call>
+    <menu_item_call
+     label="Add"
+     layout="topleft"
+     name="Wearable Add">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="wear_add" />
+    </menu_item_call>
+    <menu_item_call
+     label="Detach From Yourself"
+     layout="topleft"
+     name="Detach From Yourself">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="detach" />
+    </menu_item_call>
+    <menu_item_call
+     label="Take Off"
+     layout="topleft"
+     name="Take Off">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="take_off" />
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft" 
+     name="Settings Separator" />
+    <menu_item_call
+            name="Settings Apply Local"
+            layout="topleft"
+            label="Apply Only To Myself">
+        <menu_item_call.on_click 
+                function="Inventory.DoToSelected"
+                parameter="apply_settings_local" />
+    </menu_item_call>
+    <menu_item_call
+            name="Settings Apply Parcel"
+            layout="topleft"
+            label="Apply To Parcel">
+        <menu_item_call.on_click 
+                function="Inventory.DoToSelected"
+                parameter="apply_settings_parcel" />
+    </menu_item_call>
+  <menu_item_separator
+   layout="topleft"
+   name="Subfolder Separator" />
+  <menu_item_call
+   label="Create folder from selected"
+   layout="topleft"
+   name="New folder from selected">
+    <menu_item_call.on_click
+     function="Inventory.DoToSelected"
+     parameter="new_folder_from_selected" />
+  </menu_item_call>
+  <menu_item_call
+   label="Ungroup folder items"
+   layout="topleft"
+   name="Ungroup folder items">
+    <menu_item_call.on_click
+     function="Inventory.DoToSelected"
+     parameter="ungroup_folder_items" />
+  </menu_item_call>
+  <menu
+   label="Use as default for"
+   layout="topleft"
+   name="upload_def">
+    <menu_item_call
+     label="Image uploads"
+     layout="topleft"
+     name="Image uploads">
+      <menu_item_call.on_click
+       function="Inventory.FileUploadLocation"
+        parameter="texture" />
+      <menu_item_call.on_visible
+       function="Inventory.CanSetUploadLocation" />
+    </menu_item_call>
+    <menu_item_call
+     label="Sound uploads"
+     layout="topleft"
+     name="Sound uploads">
+      <menu_item_call.on_click
+       function="Inventory.FileUploadLocation"
+       parameter="sound" />
+      <menu_item_call.on_visible
+       function="Inventory.CanSetUploadLocation" />
+    </menu_item_call>
+    <menu_item_call
+     label="Animation uploads"
+     layout="topleft"
+     name="Animation uploads">
+      <menu_item_call.on_click
+       function="Inventory.FileUploadLocation"
+       parameter="animation" />
+      <menu_item_call.on_visible
+       function="Inventory.CanSetUploadLocation" />
+    </menu_item_call>
+    <menu_item_call
+     label="Model uploads"
+     layout="topleft"
+     name="Model uploads">
+      <menu_item_call.on_click
+       function="Inventory.FileUploadLocation"
+       parameter="model" />
+      <menu_item_call.on_visible
+       function="Inventory.CanSetUploadLocation" />
+    </menu_item_call>
+  </menu>
+	<menu_item_separator
+	 layout="topleft"
+	 name="Marketplace Separator" />
+	<menu_item_call
+        label="Copy to Marketplace Listings"
+        layout="topleft"
+        name="Marketplace Copy">
+		<menu_item_call.on_click
+        function="Inventory.DoToSelected"
+        parameter="copy_to_marketplace_listings" />
+	</menu_item_call>
+	<menu_item_call
+        label="Move to Marketplace Listings"
+        layout="topleft"
+        name="Marketplace Move">
+		<menu_item_call.on_click
+        function="Inventory.DoToSelected"
+        parameter="move_to_marketplace_listings" />
+	</menu_item_call>
+	<menu_item_call
+     label="--no options--"
+     layout="topleft"
+     name="--no options--" />
+    <menu_item_separator
+     layout="topleft" />
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml
index 99ca910062c8cffb7b92793a5f5a075e5462b2d3..0ca505dd5d01a667678dd88a1cc6c91b647a14ca 100755
--- a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml
+++ b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml
@@ -42,35 +42,11 @@
         parameter="take_off" />
     </menu_item_call>
     <menu_item_call
-        label="Upload Photo (L$[UPLOAD_COST])"
-        layout="topleft"
-        name="upload_photo">
-        <on_click
-        function="Outfit.UploadPhoto" />
-    </menu_item_call>
-    <menu_item_call
-        label="Select Photo"
-        layout="topleft"
-        name="select_photo">
+     label="Image..."
+     layout="topleft"
+     name="thumbnail">
         <on_click
-        function="Outfit.SelectPhoto" />
-    </menu_item_call>
-    <menu_item_call
-        label="Take a Snapshot"
-        layout="topleft"
-        name="take_snapshot">
-        <on_click
-        function="Outfit.TakeSnapshot" />
-    </menu_item_call>
-    <menu_item_call
-        label="Remove Photo"
-        layout="topleft"
-        name="remove_photo">
-        <on_click
-        function="Outfit.RemovePhoto" />
-        <on_visible
-        function="Outfit.OnVisible"
-        parameter="remove_photo" />
+         function="Outfit.Thumbnail" />
     </menu_item_call>
     <menu_item_separator name="sepatator1" />
     <menu
diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml
index 97962034f7915fce01c6f5e79cd39331fb20c6a7..42e67c290a0bd6bb77ce5e370c2625d91eb4dda7 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory.xml
@@ -143,6 +143,22 @@
          function="Inventory.EmptyLostAndFound"
          parameter="rename" />
     </menu_item_call>
+    <menu_item_call
+     label="New Folder"
+     layout="topleft"
+     name="New Folder">
+        <menu_item_call.on_click
+         function="Inventory.DoCreate"
+         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
      label="Change Type"
      layout="topleft"
@@ -339,12 +355,12 @@
          parameter="properties" />
     </menu_item_call>
     <menu_item_call
-     label="Rename"
+     label="Image..."
      layout="topleft"
-     name="Rename">
+     name="thumbnail">
         <menu_item_call.on_click
          function="Inventory.DoToSelected"
-         parameter="rename" />
+         parameter="thumbnail" />
     </menu_item_call>
     <menu_item_call
      label="Copy Asset UUID"
@@ -365,6 +381,32 @@
     <menu_item_separator
      layout="topleft" 
      name="Copy Separator" />
+    <menu_item_call
+     label="Open"
+     layout="topleft"
+     name="open_in_current_window">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="open_in_current_window" />
+    </menu_item_call>
+    <menu_item_call
+     label="Open in new window"
+     layout="topleft"
+     name="open_in_new_window">
+        <menu_item_call.on_click
+         function="Inventory.OpenNewFolderWindow"/>
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft"
+     name="Open Folder Separator" />
+    <menu_item_call
+     label="Rename"
+     layout="topleft"
+     name="Rename">
+        <menu_item_call.on_click
+         function="Inventory.DoToSelected"
+         parameter="rename" />
+    </menu_item_call>
     <menu_item_call
      label="Cut"
      layout="topleft"
@@ -952,6 +994,43 @@
      function="Inventory.DoToSelected"
      parameter="ungroup_folder_items" />
   </menu_item_call>
+  <menu
+   label="Use as default for"
+   layout="topleft"
+   name="upload_def">
+    <menu_item_call
+     label="Image uploads"
+     layout="topleft"
+     name="Image uploads">
+      <menu_item_call.on_click
+       function="Inventory.FileUploadLocation"
+        parameter="texture" />
+    </menu_item_call>
+    <menu_item_call
+     label="Sound uploads"
+     layout="topleft"
+     name="Sound uploads">
+    <menu_item_call.on_click
+     function="Inventory.FileUploadLocation"
+     parameter="sound" />
+    </menu_item_call>
+    <menu_item_call
+     label="Animation uploads"
+     layout="topleft"
+     name="Animation uploads">
+    <menu_item_call.on_click
+     function="Inventory.FileUploadLocation"
+     parameter="animation" />
+    </menu_item_call>
+    <menu_item_call
+     label="Model uploads"
+     layout="topleft"
+     name="Model uploads">
+    <menu_item_call.on_click
+     function="Inventory.FileUploadLocation"
+     parameter="model" />
+    </menu_item_call>
+  </menu>
 	<menu_item_separator
 	 layout="topleft"
 	 name="Marketplace Separator" />
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml
index ea2f467598c956fd6720c8f17c8d9feb5a182101..4db25db1035e8bdd532f520db00aaed7c29cfd9e 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml
@@ -310,6 +310,15 @@
                     function="Inventory.EnvironmentEnabled" />
         </menu_item_call>
     </menu>
+     <menu_item_separator/>
+    <menu_item_call
+     label="Shop..."
+     layout="topleft"
+     name="Shop">
+        <menu_item_call.on_click
+         function="Inventory.GearDefault.Custom.Action"
+         parameter="shop" />
+    </menu_item_call>
 	<menu_item_separator>
         <menu_item_separator.on_visible
 			function="SavedSetting"
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
index 8d39a9129ae30d763735f03f042c4627f526cda8..e7a24c72b7dd0108dcb001ee284f935505ffa7b8 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
@@ -15,52 +15,33 @@
          function="Inventory.GearDefault.Custom.Action"
          parameter="new_window" />
     </menu_item_call>
-    <menu_item_separator
-     layout="topleft" />
-    <menu_item_check
-     label="Sort by Name"
-     layout="topleft"
-     name="sort_by_name">
-        <on_click
-         function="Inventory.GearDefault.Custom.Action"
-         parameter="sort_by_name" />
-        <on_check
-         function="Inventory.GearDefault.Check"
-         parameter="sort_by_name" />
-    </menu_item_check>
-    <menu_item_check
-     label="Sort by Most Recent"
+    <menu_item_call 
+     label="Expand All Folders"
      layout="topleft"
-     name="sort_by_recent">
+     name="open_folders">
         <on_click
          function="Inventory.GearDefault.Custom.Action"
-         parameter="sort_by_recent" />
-        <on_check
-         function="Inventory.GearDefault.Check"
-         parameter="sort_by_recent" />         
-    </menu_item_check>
-    <menu_item_check
-     label="Sort Folders Always by Name"
+         parameter="open_folders" />
+    </menu_item_call>
+    <menu_item_call
+     label="Collapse All Folders"
      layout="topleft"
-     name="sort_folders_by_name">
+     name="close_folders">
         <on_click
          function="Inventory.GearDefault.Custom.Action"
-         parameter="sort_folders_by_name" />
-        <on_check
-         function="Inventory.GearDefault.Check"
-         parameter="sort_folders_by_name" />
-    </menu_item_check>
-    <menu_item_check
-     label="Sort System Folders to Top"
+         parameter="close_folders" />
+        <on_visible
+         function="Inventory.GearDefault.Visible"
+         parameter="multi_folder_view" />
+    </menu_item_call>
+    <menu_item_call
+     label="Close All Windows"
      layout="topleft"
-     name="sort_system_folders_to_top">
+     name="close_windows">
         <on_click
          function="Inventory.GearDefault.Custom.Action"
-         parameter="sort_system_folders_to_top" />
-        <on_check
-         function="Inventory.GearDefault.Check"
-         parameter="sort_system_folders_to_top" />
-    </menu_item_check>
+         parameter="close_inv_windows" />
+    </menu_item_call>
     <menu_item_separator
      layout="topleft" />
     <menu_item_call
@@ -79,37 +60,6 @@
          function="Inventory.GearDefault.Custom.Action"
          parameter="reset_filters" />
     </menu_item_call>
-    <menu_item_call
-     label="Open All Folders"
-     layout="topleft"
-     name="open_folders">
-        <on_click
-         function="Inventory.GearDefault.Custom.Action"
-         parameter="open_folders" />
-    </menu_item_call>
-    <menu_item_call
-     label="Close All Folders"
-     layout="topleft"
-     name="close_folders">
-        <on_click
-         function="Inventory.GearDefault.Custom.Action"
-         parameter="close_folders" />
-    </menu_item_call>
-    <menu_item_separator
-     layout="topleft" />
-    <menu_item_call
-     label="Empty Lost and Found"
-     layout="topleft"
-     name="empty_lostnfound">
-        <on_click
-         function="Inventory.GearDefault.Custom.Action"
-         parameter="empty_lostnfound" />
-        <on_enable
-         function="Inventory.GearDefault.Enable"
-         parameter="empty_lostnfound" />
-    </menu_item_call>
-    <menu_item_separator
-     layout="topleft" />
     <menu_item_call 
          label="Save Texture As"
          layout="topleft"
@@ -127,7 +77,8 @@
      name="Share"
      visible="true">
      <on_click
-         function="Inventory.Share" />
+         function="Inventory.GearDefault.Custom.Action"
+         parameter="share" />
      <on_enable
          function="Inventory.GearDefault.Enable"
          parameter="share" />
@@ -162,9 +113,25 @@
              function="Inventory.GearDefault.Custom.Action"
              parameter="replace_links" />
         </menu_item_call>
-    <menu_item_separator
-     layout="topleft" />
-
+    <menu_item_separator>
+        <menu_item_separator.on_visible
+         function="Inventory.GearDefault.Visible"
+         parameter="multi_folder_view" />
+    </menu_item_separator>
+    <menu_item_call
+     label="Empty Lost and Found"
+     layout="topleft"
+     name="empty_lostnfound">
+        <on_click
+         function="Inventory.GearDefault.Custom.Action"
+         parameter="empty_lostnfound" />
+        <on_enable
+         function="Inventory.GearDefault.Enable"
+         parameter="empty_lostnfound" />
+        <on_visible
+         function="Inventory.GearDefault.Visible"
+         parameter="multi_folder_view" />
+    </menu_item_call>
     <menu_item_call
      label="Empty Trash"
      layout="topleft"
@@ -175,5 +142,8 @@
         <on_enable
          function="Inventory.GearDefault.Enable"
          parameter="empty_trash" />
+        <on_visible
+         function="Inventory.GearDefault.Visible"
+         parameter="multi_folder_view" />
     </menu_item_call>
 </toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_search_visibility.xml b/indra/newview/skins/default/xui/en/menu_inventory_search_visibility.xml
index 46193f4a7a98ba5a2c4dbbc37d2365ec141557f4..8e34f52f3ac2f846ea2a7bcc1199f8c9c0b71fca 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_search_visibility.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_search_visibility.xml
@@ -6,6 +6,17 @@
  mouse_opaque="false"
  name="menu_search_visibility"
  visible="false">
+  <menu_item_check
+   label="Search outfit folders"
+   layout="topleft"
+   name="search_outfits">
+    <on_click
+     function="Inventory.GearDefault.Custom.Action"
+     parameter="toggle_search_outfits" />
+    <on_check
+     function="Inventory.GearDefault.Check"
+     parameter="toggle_search_outfits" />
+  </menu_item_check>
   <menu_item_check
    label="Search Trash"
    layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml b/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c7f9822e41b5e0260e683a3056592bfa62a4ec50
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ bottom="806"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ name="menu_view_default"
+ visible="false">
+    <menu_item_check
+     label="Sort by Name"
+     layout="topleft"
+     name="sort_by_name">
+        <on_click
+         function="Inventory.GearDefault.Custom.Action"
+         parameter="sort_by_name" />
+        <on_check
+         function="Inventory.GearDefault.Check"
+         parameter="sort_by_name" />
+    </menu_item_check>
+    <menu_item_check
+     label="Sort by Most Recent"
+     layout="topleft"
+     name="sort_by_recent">
+        <on_click
+         function="Inventory.GearDefault.Custom.Action"
+         parameter="sort_by_recent" />
+        <on_check
+         function="Inventory.GearDefault.Check"
+         parameter="sort_by_recent" />         
+    </menu_item_check>
+    <menu_item_check
+     label="Sort Folders Always by Name"
+     layout="topleft"
+     name="sort_folders_by_name">
+        <on_click
+         function="Inventory.GearDefault.Custom.Action"
+         parameter="sort_folders_by_name" />
+        <on_check
+         function="Inventory.GearDefault.Check"
+         parameter="sort_folders_by_name" />
+    </menu_item_check>
+    <menu_item_check
+     label="Sort System Folders to Top"
+     layout="topleft"
+     name="sort_system_folders_to_top">
+        <on_click
+         function="Inventory.GearDefault.Custom.Action"
+         parameter="sort_system_folders_to_top" />
+        <on_check
+         function="Inventory.GearDefault.Check"
+         parameter="sort_system_folders_to_top" />
+        <on_visible
+         function="Inventory.GearDefault.Visible"
+         parameter="multi_folder_view" />
+    </menu_item_check>
+    <menu_item_separator>
+        <menu_item_separator.on_visible
+         function="Inventory.GearDefault.Visible"
+         parameter="single_folder_view" />
+    </menu_item_separator>
+    <menu_item_check
+     label="List view"
+     layout="topleft"
+     name="list_view">
+        <on_click
+         function="Inventory.GearDefault.Custom.Action"
+         parameter="list_view" />
+        <on_check
+         function="Inventory.GearDefault.Check"
+         parameter="list_view" />
+        <on_visible
+         function="Inventory.GearDefault.Visible"
+         parameter="single_folder_view" />
+    </menu_item_check>
+    <menu_item_check
+     label="Gallery view"
+     layout="topleft"
+     name="gallery_view">
+        <on_click
+         function="Inventory.GearDefault.Custom.Action"
+         parameter="gallery_view" />
+        <on_check
+         function="Inventory.GearDefault.Check"
+         parameter="gallery_view" />
+        <on_visible
+         function="Inventory.GearDefault.Visible"
+         parameter="single_folder_view" />
+    </menu_item_check>
+    <menu_item_check
+     label="Combination view"
+     layout="topleft"
+     name="combination_view">
+        <on_click
+         function="Inventory.GearDefault.Custom.Action"
+         parameter="combination_view" />
+        <on_check
+         function="Inventory.GearDefault.Check"
+         parameter="combination_view" />
+        <on_visible
+         function="Inventory.GearDefault.Visible"
+         parameter="single_folder_view" />
+    </menu_item_check>
+    <menu_item_separator/>
+    <menu_item_check
+     label="Inventory settings..."
+     name="inv_settings">
+        <menu_item_check.on_check
+         function="Floater.Visible"
+         parameter="inventory_settings" />
+        <menu_item_check.on_click
+         function="Floater.Toggle"
+         parameter="inventory_settings" />
+    </menu_item_check>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
index 32d9d28434a1b418fd6b0fc485a478e2e48dda43..e216962d12a4fead02a8316dec8c6c7ca15b1161 100644
--- a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
@@ -40,32 +40,11 @@
          parameter="take_off" />
     </menu_item_call>
     <menu_item_call
-     label="Upload Photo (L$[UPLOAD_COST])"
+     label="Image..."
      layout="topleft"
-     name="upload_photo">
+     name="thumbnail">
         <on_click
-         function="Gear.UploadPhoto" />
-    </menu_item_call>
-    <menu_item_call
-     label="Select Photo"
-     layout="topleft"
-     name="select_photo">
-        <on_click
-         function="Gear.SelectPhoto" />
-    </menu_item_call>
-    <menu_item_call
-     label="Take a Snapshot"
-     layout="topleft"
-     name="take_snapshot">
-        <on_click
-         function="Gear.TakeSnapshot" />
-    </menu_item_call>
-    <menu_item_call
-     label="Remove Photo"
-     layout="topleft"
-     name="remove_photo">
-        <on_click
-         function="Gear.RemovePhoto" />
+         function="Gear.Thumbnail" />
     </menu_item_call>
   <menu_item_separator name="sepatator1" />
             <!-- copied (with minor modifications) from menu_inventory_add.xml -->
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index cb4318f3159a5421102c34e829e59946097239e9..86a0b59cdf5a79756b2e6825292e49d2278d1cd0 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -3430,6 +3430,30 @@ See https://wiki.secondlife.com/wiki/Adding_Spelling_Dictionaries
     </form>
   </notification>
 
+  <notification
+   icon="alertmodal.tga"
+   label="Rename Selected Item"
+   name="RenameItem"
+   type="alertmodal">
+    Choose a new name for:
+[NAME]
+   <tag>confirm</tag>
+    <form name="form">
+    <input name="new_name" type="text" width="300">
+      [NAME]
+    </input>
+    <button
+     default="true"
+     index="0"
+     name="OK"
+     text="OK"/>
+    <button
+     index="1"
+     name="Cancel"
+     text="Cancel"/>
+   </form>
+  </notification>
+
   <notification
    icon="alertmodal.tga"
    name="RemoveFromFriends"
@@ -6277,7 +6301,54 @@ Are you sure you want to delete them?
      notext="Cancel"
      yestext="OK"/>
   </notification>
-  
+
+  <notification
+   icon="alertmodal.tga"
+   name="DeleteThumbnail"
+   type="alertmodal">
+    <unique/>
+    Delete the image for this item? There is no undo.
+    <tag>confirm</tag>
+    <usetemplate
+     ignoretext="Don't show me this again"
+     name="okcancelignore"
+     notext="Cancel"
+     yestext="Delete"/>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="ThumbnailDimentionsLimit"
+   type="alertmodal">
+    <unique/>
+    Only square images from 64 to 256 pixels per side are allowed.
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="ThumbnailInsufficientPermissions"
+   type="alertmodal">
+    <unique/>
+    Only copy and transfer free images can be assigned as thumbnails.
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="ThumbnailOutfitPhoto"
+   type="alertmodal">
+    <unique/>
+    To add an image to an outfit, use the Outfit Gallery window, or right-click on the outfit folder and select "Image..."
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
+  </notification>
+
   <notification
      icon="alertmodal.tga"
      name="ConfirmUnlink"
@@ -6525,6 +6596,22 @@ Your inventory is experiencing issues. Please, contact support.
   <tag>fail</tag>
   </notification>
 
+  <notification
+   icon="alertmodal.tga"
+   name="InventoryLimitReachedAISAlert"
+   type="alertmodal">
+Your inventory is experiencing issues. Please, contact support.
+  <tag>fail</tag>
+  </notification>
+
+  <notification
+   icon="notifytip.tga"
+   name="InventoryLimitReachedAIS"
+   type="notifytip">
+Your inventory is experiencing issues. Please, contact support.
+  <tag>fail</tag>
+  </notification>
+
   <notification
    icon="alertmodal.tga"
    name="ConfirmClearBrowserCache"
@@ -12235,16 +12322,41 @@ Packing: [PACK_TIME]s [PSIZE]KB
 Unpacking: [UNPACK_TIME]s [USIZE]KB
     <tag>fail</tag>
   </notification>
-  
- <notification
+
+    <notification
+     icon="alertmodal.tga"
+     label="Prompt for MFA Token"
+     name="PromptMFAToken"
+     type="alertmodal">
+        [MESSAGE]
+        <tag>confirm</tag>
+        <form name="form">
+            <input name="token" type="text" width="400" />
+            <button
+             default="true"
+             index="0"
+             name="continue"
+             text="Continue"/>
+            <button
+             index="1"
+             name="cancel"
+             text="Cancel"/>
+        </form>
+    </notification>
+
+  <notification
    icon="alertmodal.tga"
    label="Prompt for MFA Token"
-   name="PromptMFAToken"
+   name="PromptMFATokenWithSave"
    type="alertmodal">
     [MESSAGE]
     <tag>confirm</tag>
     <form name="form">
       <input name="token" type="text" width="400" />
+      <ignore
+       name="ignore"
+       checkbox_only="true"
+       text="Remember this computer for 30 days."/>
       <button
        default="true"
        index="0"
diff --git a/indra/newview/skins/default/xui/en/panel_inventory_gallery.xml b/indra/newview/skins/default/xui/en/panel_inventory_gallery.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ed04e121932941b003d1326fbf4de52f5680a2e4
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_inventory_gallery.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+   background_visible="true"
+   bg_alpha_color="InventoryBackgroundColor"
+   border="false"
+   follows="all"
+   height="390"
+   name="Inventory Gallery"
+   layout="topleft">
+  <text
+    type="string"
+    clip_partial="false"
+    follows="all"
+    layout="topleft"
+    name="empty_txt"
+    height="390"
+    halign="center"
+    valign="center"
+    parse_urls="true"
+    wrap="true">
+    Folder is empty.
+  </text> 
+  <scroll_container
+   follows="all"
+   height="390"
+   layout="topleft"
+   left="0"
+   top="0"
+   tab_stop="true"
+   name="gallery_scroll_panel"
+   opaque="false">
+  </scroll_container>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml b/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml
new file mode 100644
index 0000000000000000000000000000000000000000..574872a8701a7bc3bda6f3c2cc9a4fff1093cd15
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+   background_visible="false"
+   background_opaque="false"
+   bg_alpha_color="FrogGreen"
+   bg_opaque_color="FrogGreen"   
+   border="false"
+   bevel_style="none"
+   follows="left|top"
+   height="149"
+   width="130"
+   name="gallery_item_panel"
+   layout="topleft"
+   left="0"
+   top="0">
+  <thumbnail
+   name="preview_thumbnail"
+   fallback_image="Thumbnail_Fallback"
+   layout="topleft"
+   follows="left|top"
+   interactable="false"
+   height="128"
+   width="128"
+   top="0"
+   left="1"/>
+  <icon
+   left="5"
+   top_pad="-21"
+   layout="topleft"
+   name="item_type"
+   height="16"
+   width="16"
+   follows="left|top"
+   visible="true"
+   image_name="Inv_Eye"/>
+  <icon
+    left="5"
+    top_pad="-8"
+    layout="topleft"
+    name="link_overlay"
+    height="8"
+    width="6"
+    follows="left|top"
+    visible="false"
+    image_name="Inv_Link"/>
+  <panel
+   background_visible="false"
+   background_opaque="true"
+   bg_opaque_color="MenuItemHighlightBgColor"
+   border="false"
+   bevel_style="none"
+   follows="left|top"
+   left="0"
+   top="129"
+   height="25"
+   width="130"
+   name="text_bg_panel">
+    <text
+      read_only="true"
+      length="1"
+      follows="left|top"
+      left="1"
+      height="23"
+      layout="topleft"
+      name="item_name"
+      parse_urls="false"
+      text_readonly_color="White"
+      word_wrap="true"
+      top="2"
+      width="127"
+      use_ellipses="true">
+      Item name, folder name.
+    </text>
+  </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
index 0b3c70b9a9c855b6bfbf6de26256c8ccab25ba97..9ba9a597ff0b8621fd950ec34e968de549e9bf04 100644
--- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
@@ -6,8 +6,7 @@
  layout="topleft"
  min_height="300"
  min_width="240"
- name="main inventory panel"
- width="330">
+ name="main inventory panel">
   <panel.string
    name="Itemcount">
   </panel.string>
@@ -23,257 +22,325 @@
    name="ItemcountUnknown">
     Fetched [ITEM_COUNT] Items and [CATEGORY_COUNT] Folders [FILTER]
   </panel.string>
+  <panel.string name="inventory_title">INVENTORY</panel.string>
+  <panel.string name="default_mode_btn">Multi_Folder_Mode</panel.string>
+  <panel.string name="single_folder_mode_btn">Single_Folder_Mode</panel.string>
   <text
-		     type="string"
-		     length="1"
-		     follows="left|top|right"
-		     height="13"
-		     layout="topleft"
-    		 left="12"
-		     name="ItemcountText"
-		     font="SansSerifMedium"
-		     text_color="InventoryItemLinkColor"
-		     use_ellipses="true"
-		     top_pad="0"
-		     width="300">
+     type="string"
+     length="1"
+     follows="left|top|right"
+     height="13"
+     layout="topleft"
+  	 left="12"
+  	 right="-12"
+     name="ItemcountText"
+     font="SansSerifMedium"
+     text_color="InventoryItemLinkColor"
+     use_ellipses="true"
+     top_pad="0">
     Items:
   </text>
-  <combo_box
-   height="23"
-   layout="topleft"
-   left="10"
-   top="18"
-   name="search_type"
-   follows="top|left"
-   width="88">
-    <item
-     label="Name"
-     name="Name"
-     value="search_by_name"/>
-    <item
-     label="Creator"
-     name="Creator"
-     value="search_by_creator"/>
-    <item
-     label="Description"
-     name="Description"
-     value="search_by_description"/>
-    <item
-     label="UUID"
-     name="UUID"
-     value="search_by_UUID"/>
-  </combo_box>
-  <menu_button
-   follows="top|left"
-   tool_tip="Show search visibility options"
-   height="23"
-   image_overlay="Inv_Toolbar_SearchVisibility"
-   layout="topleft"
-   left_pad="3"
-   name="options_visibility_btn"
-   width="31" />
-  <filter_editor
-   text_pad_left="10"
+  <layout_stack
    follows="left|top|right"
-   height="23"
-   label="Enter search text"
-   layout="topleft"
-   left_pad="3"
-   max_length_chars="300"
-   highlight_text_field="false"
-   name="inventory search editor"
-   width="177" />
-  <tab_container
-     follows="all"
-     halign="center"
-     height="339"
-     layout="topleft"
-     left="7"
-     name="inventory filter tabs"
-     tab_height="30"
-     tab_position="top"
-     tab_min_width="100"
-     top_pad="10"
-     width="312">
-    <inventory_panel
-     bg_opaque_color="PanelDefaultBackgroundColor"
-     bg_alpha_color="PanelDefaultBackgroundColor"
-     background_visible="true"
-     border="false"
-     bevel_style="none"
-     follows="all"
-     height="338"
-     label="MY INVENTORY"
-     help_topic="my_inventory_tab"
-     layout="topleft"
-     left="0"
-     name="All Items"
-     sort_order_setting="InventorySortOrder"
-     show_item_link_overlays="true"
-     top="16"
-     width="288" />
-    <recent_inventory_panel
-     bg_opaque_color="PanelDefaultBackgroundColor"
-     bg_alpha_color="PanelDefaultBackgroundColor"
-     background_visible="true"
+   height="25"
+   animate="false"
+   top_pad="10"
+   left="2"
+   right="-4"
+   orientation="horizontal">
+    <layout_panel
      border="false"
-     bevel_style="none"
-     follows="all"
-     height="338"
-     label="RECENT"
-     help_topic="recent_inventory_tab"
-     layout="topleft"
-     left_delta="0"
-     name="Recent Items"
-     show_item_link_overlays="true"
-     width="290" />
-       <inventory_panel
-      name="Worn Items"
-      label="WORN"
-      show_empty_message="false"
-      follows="all"
+     bevel_style="in"
+     user_resize="false"
+     auto_resize="false"
+     height="25"
+     width="65"
+     name="nav_buttons"
+     visible="false">
+     <button
+      follows="top|left"
+      height="23"
+      image_selected="Single_Folder_Back"
+      image_pressed="Single_Folder_Back"
+      image_unselected="Single_Folder_Back"
+      scale_image="false"
+      layout="topleft"
+      left="3"
+      top="2"
+      name="back_btn"
+      tool_tip="Back"
+      width="20" />
+     <button
+      follows="top|left"
+      height="23"
+      image_selected="Single_Folder_Forward"
+      image_pressed="Single_Folder_Forward"
+      image_unselected="Single_Folder_Forward"
+      scale_image="false"
       layout="topleft"
-      width="290"
-      bg_opaque_color="PanelDefaultBackgroundColor"
-      bg_alpha_color="PanelDefaultBackgroundColor"
-      background_visible="true"
+      left_pad="1"
+      name="forward_btn"
+      tool_tip="Forward"
+      width="20" />
+     <button
+      follows="top|left"
+      height="23"
+      image_selected="Single_Folder_Up"
+      image_pressed="Single_Folder_Up"
+      image_unselected="Single_Folder_Up"
+      scale_image="false"
+      layout="topleft"
+      left_pad="1"
+      name="up_btn"
+      tool_tip="Go up one level"
+      width="20" />
+    </layout_panel>
+    <layout_panel
       border="false"
-      bevel_style="none"
-      scroll.reserve_scroll_corner="false">
-  </inventory_panel>
-  </tab_container>
-  <layout_stack
-   animate="false"
-   border_size="0"
-   follows="left|right|bottom"
-   height="25"
-   layout="topleft"
-   orientation="horizontal"
-   top_pad="0"
-   left="10"
-   name="bottom_panel"
-   width="307">
-      <layout_panel
-       auto_resize="false"
-       height="25"
+      bevel_style="in"
+      user_resize="false"
+      height="25"
+      width="381"
+      visible="true">
+      <combo_box
+       height="23"
        layout="topleft"
-       name="options_gear_btn_panel"
-       width="32">
-          <menu_button
-           follows="bottom|left"
-           tool_tip="Show additional options"
-           height="25"
-           image_hover_unselected="Toolbar_Left_Over"
-           image_overlay="OptionsMenu_Off"
-           image_selected="Toolbar_Left_Selected"
-           image_unselected="Toolbar_Left_Off"
-           layout="topleft"
-           left="0"
-           name="options_gear_btn"
-           top="0"
-           width="31" />
-      </layout_panel>
-      <layout_panel
-       auto_resize="false"
-       height="25"
+       left="2"
+       top="0"
+       name="search_type"
+       tool_tip="Search by"
+       follows="top|left"
+       width="67">
+       <item
+        label="Name"
+        name="Name"
+        value="search_by_name"/>
+       <item
+        label="Creator"
+        name="Creator"
+        value="search_by_creator"/>
+       <item
+        label="Description"
+        name="Description"
+        value="search_by_description"/>
+       <item
+        label="UUID"
+        name="UUID"
+        value="search_by_UUID"/>
+      </combo_box>
+      <menu_button
+       follows="top|left"
+       tool_tip="Search visibility options"
+       height="23"
+       image_overlay="Inv_Toolbar_SearchVisibility"
        layout="topleft"
-       name="add_btn_panel"
-       width="32">
-          <button
-           follows="bottom|left"
-           height="25"
-           image_hover_unselected="Toolbar_Middle_Over"
-           image_overlay="AddItem_Off"
-           image_selected="Toolbar_Middle_Selected"
-           image_unselected="Toolbar_Middle_Off"
-           layout="topleft"
-           left="0"
-           name="add_btn"
-           tool_tip="Add new item"
-           top="0"
-           width="31" />
-      </layout_panel>
-      <layout_panel
-       auto_resize="false"
-       height="25"
+       left_pad="1"
+       name="options_visibility_btn"
+       width="31" />
+      <filter_editor
+       text_pad_left="10"
+       follows="left|top|right"
+       height="23"
+       label="Enter search text"
        layout="topleft"
-       name="open_folder_btn_panel"
-       width="32">
-          <button
-           follows="bottom|left"
-           height="25"
-           image_hover_unselected="Toolbar_Middle_Over"
-           image_overlay="Inv_FolderOpen_WT"
-           image_selected="Toolbar_Middle_Selected"
-           image_unselected="Toolbar_Middle_Off"
-           layout="topleft"
-           left="0"
-           name="open_folder_btn"
-           tool_tip="Open all folders"
-           top="0"
-           width="31">
-            <button.commit_callback
-             function="Inventory.OpenAllFolders" />
-         </button>
-      </layout_panel>
-      <layout_panel
-       auto_resize="false"
-       height="25"
+       left_pad="1"
+       max_length_chars="300"
+       highlight_text_field="false"
+       name="inventory search editor"
+       width="150" />
+      <menu_button
+       follows="top|right"
+       tool_tip="Actions"
+       height="23"
+       image_hover_unselected="Toolbar_Middle_Over"
+       image_overlay="OptionsMenu_Off"
+       image_selected="Toolbar_Middle_Selected"
+       image_unselected="Toolbar_Middle_Off"
        layout="topleft"
-       name="close_folder_btn_panel"
-       width="32">
-          <button
-           follows="bottom|left"
-           height="25"
-           image_hover_unselected="Toolbar_Middle_Over"
-           image_overlay="Inv_FolderClosed_WT"
-           image_selected="Toolbar_Middle_Selected"
-           image_unselected="Toolbar_Middle_Off"
-           layout="topleft"
-           left="0"
-           name="close_folder_btn"
-           tool_tip="Close all folders"
-           top="0"
-           width="31">
-            <button.commit_callback
-             function="Inventory.CloseAllFolders" />
-         </button>
-      </layout_panel>
-      <layout_panel
-       auto_resize="true"
-       height="25"
+       left_pad="1"
+       name="options_gear_btn"
+       width="31" />
+      <menu_button
+       follows="top|right"
+       tool_tip="View &amp; sort options"
+       height="23"
+       image_hover_unselected="Toolbar_Middle_Over"
+       image_overlay="Conv_toolbar_sort"
+       image_selected="Toolbar_Middle_Selected"
+       image_unselected="Toolbar_Middle_Off"
        layout="topleft"
-       name="dummy_panel"
-       width="212">
-          <icon
-           follows="bottom|left|right"
-           height="25"
-           image_name="Toolbar_Middle_Off"
-           layout="topleft"
-           left="0"
-           top="0"
-           name="dummy_icon"
-           width="211" />
-      </layout_panel>
-      <layout_panel
-       auto_resize="false"
-       height="25"
+       left_pad="1"
+       name="view_btn"
+       width="31" />
+      <button
+       follows="top|right"
+       height="23"
+       image_hover_unselected="Toolbar_Middle_Over"
+       image_overlay="AddItem_Off"
+       image_selected="Toolbar_Middle_Selected"
+       image_unselected="Toolbar_Middle_Off"
        layout="topleft"
-       name="trash_btn_panel"
-       width="31">
-          <dnd_button
-           follows="bottom|left"
-           height="25"
-           image_hover_unselected="Toolbar_Right_Over"
-           image_overlay="TrashItem_Off"
-           image_selected="Toolbar_Right_Selected"
-           image_unselected="Toolbar_Right_Off"
-           left="0"
-           layout="topleft"
-           name="trash_btn"
-           tool_tip="Remove selected item"
-           top="0"
-           width="31"/>
-      </layout_panel>
-  </layout_stack>
+       left_pad="1"
+       name="add_btn"
+       tool_tip="Create new item"
+       width="31" />
+      <button
+       follows="top|right"
+       tool_tip="Switch between views"
+       height="23"
+       image_hover_unselected="Toolbar_Middle_Over"
+       image_overlay="Single_Folder_Mode"
+       image_selected="Toolbar_Middle_Selected"
+       image_unselected="Toolbar_Middle_Off"
+       layout="topleft"
+       left_pad="1"
+       name="view_mode_btn"
+       width="31" />
+    </layout_panel>
+    </layout_stack>
+    <panel
+     follows="all"
+     halign="center"
+     height="372"
+     layout="topleft"
+     left="3"
+     right="-3"
+     name="default_inventory_panel"
+     top_pad="5">
+      <tab_container
+       follows="all"
+       halign="center"
+       height="372"
+       layout="topleft"
+       left="0"
+       name="inventory filter tabs"
+       tab_height="30"
+       tab_position="top"
+       tab_min_width="100"
+       top="0">
+        <inventory_panel
+         bg_opaque_color="PanelDefaultBackgroundColor"
+         bg_alpha_color="PanelDefaultBackgroundColor"
+         background_visible="true"
+         border="false"
+         bevel_style="none"
+         follows="all"
+         label="MY INVENTORY"
+         help_topic="my_inventory_tab"
+         layout="topleft"
+         name="All Items"
+         sort_order_setting="InventorySortOrder"
+         show_item_link_overlays="true"
+         preinitialize_views="false"
+         scroll.reserve_scroll_corner="false">
+            <folder double_click_override="true"/>
+        </inventory_panel>
+        <recent_inventory_panel
+         bg_opaque_color="PanelDefaultBackgroundColor"
+         bg_alpha_color="PanelDefaultBackgroundColor"
+         background_visible="true"
+         border="false"
+         bevel_style="none"
+         follows="all"
+         label="RECENT"
+         help_topic="recent_inventory_tab"
+         layout="topleft"
+         name="Recent Items"
+         show_item_link_overlays="true"
+         preinitialize_views="false"
+         scroll.reserve_scroll_corner="false">
+            <folder double_click_override="true"/>
+        </recent_inventory_panel>
+        <inventory_panel
+         name="Worn Items"
+         label="WORN"
+         show_empty_message="false"
+         follows="all"
+         layout="topleft"
+         bg_opaque_color="PanelDefaultBackgroundColor"
+         bg_alpha_color="PanelDefaultBackgroundColor"
+         background_visible="true"
+         preinitialize_views="false"
+         border="false"
+         bevel_style="none"
+         scroll.reserve_scroll_corner="false">
+            <folder double_click_override="true"/>
+        </inventory_panel>
+      </tab_container>
+    </panel>
+    <panel
+     follows="all"
+     halign="center"
+     height="375"
+     layout="topleft"
+     left="7"
+     name="combination_view_inventory"
+     top_delta="0"
+     visible="false">
+     <layout_stack
+      follows="all"
+      layout="topleft"
+      height="375"
+      name="combination_view_stack"
+      animate="false"
+      drag_handle_thickness="6"
+      drag_handle_first_indent="18"
+      drag_handle_second_indent="18"
+      drag_handle_shift="5"
+      show_drag_handle="true"
+      top="0"
+      left="0"
+      orientation="vertical">
+       <layout_panel
+        border="false"
+        bevel_style="in"
+        user_resize="true"
+        auto_resize="true"
+        height="248"
+        min_width="150"
+        name="comb_gallery_layout">
+        <panel
+         class="inventory_gallery"
+         filename="panel_inventory_gallery.xml"
+         left="0"
+         top="1"
+         height="248"
+         name="comb_gallery_view_inv"
+         background_visible="true"
+         follows="all"
+         layout="topleft">
+        </panel>
+       </layout_panel>
+       <layout_panel
+        border="false"
+        bevel_style="in"
+        user_resize="true"
+        auto_resize="true"
+        height="127"
+        min_height="100"
+        name="comb_inventory_layout">
+        <single_folder_inventory_panel
+         name="comb_single_folder_inv"
+         follows="all"
+         left="0"
+         top="1"
+         height="127"
+         layout="topleft"
+         show_item_link_overlays="true"
+         bg_opaque_color="DkGray2"
+         bg_alpha_color="DkGray2"
+         background_visible="true"
+         border="false"
+         bevel_style="none"
+         scroll.reserve_scroll_corner="false">
+         <item
+          single_folder_mode="true"
+          folder_indentation="-8"/>
+         <folder
+          single_folder_mode="true"
+          folder_indentation="-8"/>
+        </single_folder_inventory_panel>
+       </layout_panel>
+     </layout_stack>
+    </panel>
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml b/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml
index 097e7138fcd80ef7e9c1948f3909ca73f616dcee..27a13792923f0c519d331b05e9ae9d9eeb5decf7 100644
--- a/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml
@@ -40,49 +40,9 @@
    layout="topleft"
    left="3"
    top="0"
+   tab_stop="true"
    name="gallery_scroll_panel"
    opaque="false">
-   <!--outfit_gallery_item
-    layout="topleft"
-    left="10"
-    name="preview_outfit1"
-    height="175"
-    width="150"
-    follows="left|top"/-->
-     <!--layout_stack follows="left|right" height="180" width="498" layout="topleft" left="0" animate="false" top="0" name="top_gallery_stack" orientation="horizontal">
-      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top_gallery_panel">
-        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit1" height="175" width="150" follows="left|top"/>
-      </layout_panel>
-      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
-        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
-      </layout_panel>
-      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
-        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
-      </layout_panel>
-    </layout_stack>
-    <layout_stack follows="left|right" height="180" width="498" layout="topleft" left="0" animate="false" top="190" name="top_gallery_stack" orientation="horizontal">
-      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top_gallery_panel">
-        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit1" height="175" width="150" follows="left|top"/>
-      </layout_panel>
-      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
-        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
-      </layout_panel>
-      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
-        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
-      </layout_panel>
-    </layout_stack>
-     <layout_stack follows="left|right" height="180" width="498" layout="topleft" left="0" animate="false" top="380" name="top_gallery_stack" orientation="horizontal">
-       <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top_gallery_panel">
-         <outfit_gallery_item layout="topleft" left="10" name="preview_outfit1" height="175" width="150" follows="left|top"/>
-       </layout_panel>
-       <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
-         <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
-       </layout_panel>
-       <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
-         <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
-       </layout_panel>
-     </layout_stack-->
-    <!--</panel>-->  
   </scroll_container> 
   <panel
      background_visible="true"
diff --git a/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml b/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml
index 9888b4d18faecf21fe88ac3207c4f9be259e6ee0..5d39211386ac7d758cb2e07ee4c48e0874266bea 100644
--- a/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml
@@ -18,7 +18,7 @@
      follows="all"
      height="400"
      layout="topleft"
-     left="0"
+     left="3"
      single_expansion="true"
      top="0"
      name="wearables_accordion"
diff --git a/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml b/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml
index ca1e405a62cd5e076e6eefd0932f862aa88c0464..f899f83ad48650198c4c25f2664edf694986e6b8 100644
--- a/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml
@@ -19,7 +19,7 @@
      layout="topleft"
      visible="false"
     />
-    <icon
+    <thumbnail
      name="real_world_pic"
      image_name="Generic_Person_Large"
      follows="top|left"
diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
index cb6c1aec4d50a0e9830fde2008c57ffffd197c20..e758c836ad774669b4cedb19000c7546c2234e98 100644
--- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
@@ -74,7 +74,7 @@ Account: [ACCTTYPE]
      auto_resize="false"
      user_resize="false">
 
-      <icon
+      <thumbnail
        name="2nd_life_pic"
        image_name="Generic_Person_Large"
        layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml
index 9995523e61935ba7b38c071356ee3b78fd01888e..76d0ffcb8e04c86797e150ff0551f9f53256b9cc 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml
@@ -6,8 +6,7 @@
 	  layout="topleft"
 	  min_height="350"
 	  min_width="240"
-	  name="objects panel"
-	  width="333">
+	  name="objects panel">
     <panel
 		 follows="all"
 		 layout="topleft"
@@ -17,25 +16,22 @@
 		 label=""
 		 height="570"
 		 visible="true"
-		 default_tab_group="1"
-		 width="330">
+		 default_tab_group="1">
       <layout_stack
               follows="left|right|top|bottom"
               layout="topleft"
               left="0"
               top="0"
-							tab_group="1"
+              tab_group="1"
               orientation="vertical"
               name="inventory_layout_stack"
-              height="535"
-              width="330">
+              height="560">
              <layout_panel
                  name="main_inventory_layout_panel"
                  layout="topleft"
                  auto_resize="true"
                  user_resize="true"
                  min_dim="150"
-                 width="330"
                  follows="bottom|left|right"
                  height="300">
                  <panel
@@ -47,17 +43,15 @@
                       name="panel_main_inventory"
                       top="0"
                       label=""
-                      height="300"
-                      width="330" />
+                      height="300" />
              </layout_panel>
 			    <layout_panel
-                 width="330"
                  layout="topleft"
                  auto_resize="false"
                  user_resize="true"
                  follows="left|right|top"
                  name="inbox_layout_panel"
-                 visible="false"
+                 visible="true"
                  min_dim="35"
                  expanded_min_dim="90"
                  height="235">
@@ -69,17 +63,15 @@
                       class="panel_marketplace_inbox"
                       top="0"
                       label=""
-                      height="235"
-                      width="330">
+                      height="235">
                      <string name="InboxLabelWithArg">Received items ([NUM])</string>
                      <string name="InboxLabelNoArg">Received items</string>
                      <button
                         control_name="InventoryInboxToggleState"
                         label="Received items"
-												font="SansSerifMedium"
+                        font="SansSerifMedium"
                         name="inbox_btn"
                         height="35"
-                        width="308"
                         image_unselected="MarketplaceBtn_Off"
                         image_selected="MarketplaceBtn_Selected"
                         halign="left"
@@ -89,7 +81,8 @@
                         tab_stop="false"
                         pad_left="35"
                         top="0"
-                        left="10" />
+                        left="5"
+                        right="-5" />
                      <text
                         type="string"
                         length="1"
@@ -101,174 +94,35 @@
                         name="inbox_fresh_new_count"
                         font="SansSerifMedium"
                         halign="right"
-                        top_pad="0"
-                        width="300">
+                        top_pad="0">
                         [NUM] new
                      </text>
                      <panel
                         name="inbox_inventory_placeholder_panel"
                         follows="all"
-                        left="10"
-                        bottom="235"
-                        width="308"
+                        left="5"
+                        right="-5"
                         top="35"
+                        height="200"
                         bg_opaque_color="InventoryBackgroundColor"
                         background_visible="true"
                         background_opaque="true"
                         tool_tip="Drag and drop items to your inventory to use them"
                         >
                         <text name="inbox_inventory_placeholder"
-															type="string"
-															follows="all"
-															layout="topleft"
-															top="0"
-															left="0"
-															width="308"
-															height="200"
-															wrap="true"
-															halign="center">
-Purchases from the marketplace will be delivered here.
-												</text>
+                            type="string"
+                            follows="all"
+                            layout="topleft"
+                            top="0"
+                            height="200"
+                            wrap="true"
+                            halign="center"
+                            valign="center">
+                          Purchases from the marketplace will be delivered here.
+                        </text>
                     </panel>
                  </panel>
              </layout_panel>
          </layout_stack>
-			<panel follows="bottom|left|right"
-					 height="30"
-					 layout="topleft"
-					 name="button_panel"
-					 left="9"
-					 top_pad="7"
-					 width="308">
-				<layout_stack follows="bottom|left|right"
-											height="23"
-											layout="topleft"
-											mouse_opaque="false"
-											name="button_panel_ls"
-											left="0"
-											orientation="horizontal"
-											top="0"
-											width="308">	
-			    <layout_panel follows="bottom|left|right"
-												height="23"
-												layout="bottomleft"
-												left="0"			
-												mouse_opaque="false"
-												name="info_btn_lp"
-												auto_resize="true"
-												width="101">
-						<button enabled="true"
-										follows="bottom|left|right"
-										height="23"
-										label="Profile"
-										layout="topleft"
-										left="1"
-										name="info_btn"
-										tool_tip="Show object profile"
-										top="0"
-										width="100" />
-			    </layout_panel>
-			    <layout_panel
-                     follows="bottom|left|right"
-                     height="23"
-                     layout="bottomleft"
-                     left_pad="1"			
-                     mouse_opaque="false"
-                     name="share_btn_lp"
-                     auto_resize="true"
-                     width="100">
-                    <button
-                         enabled="true"
-                         follows="bottom|left|right"
-                         height="23"
-                         label="Share"
-                         layout="topleft"
-                         left="1"
-                         name="share_btn"
-                         tool_tip="Share an inventory item"
-                         top="0"
-                         width="99" />
-			    </layout_panel>
-			    <layout_panel
-                     follows="bottom|left|right"
-                     height="23"
-                     layout="bottomleft"
-                     left_pad="1"			
-                     mouse_opaque="false"
-                     name="shop_btn_lp"
-                     auto_resize="true"
-                     width="100">
-                    <button
-                         enabled="true"
-                         follows="bottom|left|right"
-                         height="23"
-                         label="Shop"
-                         layout="topleft"
-                         left="1"
-                         name="shop_btn"
-                         tool_tip="Open Marketplace webpage"
-                         top="0"
-                         width="99" />
-                    <button
-                         enabled="false"
-                         follows="bottom|left|right"
-                         height="23"
-                         label="Wear"
-                         layout="topleft"
-                         left="1"
-                         name="wear_btn"
-                         tool_tip="Wear seleceted outfit"
-                         top="0"
-                         width="99" />
-                    <button
-                         enabled="false"
-                         follows="bottom|left|right"
-                         height="23"
-                         label="Play"
-                         layout="topleft"
-                         name="play_btn"
-                         left="1"
-                         top="0"
-                         width="99" />
-                    <button
-                         enabled="false"
-                         follows="bottom|left|right"
-                         height="23"
-                         label="Teleport"
-                         layout="topleft"
-                         left="1"
-                         name="teleport_btn"
-                         tool_tip="Teleport to the selected area"
-                         top="0"
-                         width="99" />
-			    </layout_panel>
-			</layout_stack>
-		</panel>
-	</panel>
-	<panel
-		 follows="all"
-		 layout="topleft"
-		 left="0"
-		 class="sidepanel_item_info"
-		 filename="sidepanel_item_info.xml"
-		 name="sidepanel__item_panel"
-		 top="0"
-		 label=""
-		 height="570"
-		 visible="false"
-		 width="330">
-	</panel>
-	<panel
-		 follows="all"
-		 layout="topleft"
-		 left="0"
-		 class="sidepanel_task_info"
-		 filename="sidepanel_task_info.xml"
-		 name="sidepanel__task_panel"
-		 top="0"
-		 label=""
-		 height="570"
-		 visible="false"
-		 width="330">
 	</panel>
 </panel>
diff --git a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
index 4d5b7f35e0bf27b49e869d0531e4a44d59a151a5..ad521cb1af1bb5a1c0e7381edee47566b7f013c9 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
@@ -43,214 +43,126 @@
     name="origin_inworld">
     (Inworld)
   </panel.string>
-  <icon
-    follows="top|right"
-    height="18"
-    image_name="Lock"
-    layout="topleft"
-    right="-15"
-    mouse_opaque="true"
-    name="IconLocked"
-    top="8"
-    width="18" />
-  <button
-    follows="top|left"
-    height="24"
-    image_hover_unselected="BackButton_Over"
-    image_pressed="BackButton_Press"
-    image_unselected="BackButton_Off"
-    layout="topleft"
-    left="12"
-    name="back_btn"
-    tab_stop="false"
-    top="2"
-    width="30"
-    use_draw_context_alpha="false" />
-  <text
-    follows="top|left|right"
-    font="SansSerifHugeBold"
-    height="26"
-    layout="topleft"
-    left_pad="3"
-    name="title"
-    text_color="LtGray"
-    top="2"
-    use_ellipses="true"
-    value="Item Profile"
-    width="275" />
-  <text
-    follows="top|left|right"
-    height="13"
-    layout="topleft"
-    left="45"
-    name="origin"
-    text_color="LtGray_50"
-    use_ellipses="true"
-    value="(Inventory)"
-    width="275" />
-  <scroll_container
-    color="PanelDefaultBackgroundColor"
-    follows="all"
-    layout="topleft"
-    left="9"
-    name="item_profile_scroll"
-    opaque="true"
-    height="493"
-    width="313"
-    top="45">
-    <panel
-      follows="left|top|right"
-      height="390"
-      help_topic=""
-      label=""
+
+<layout_stack
+  animate="false"
+  name="main_stack"
+  layout="topleft"
+  follows="all"
+  orientation="vertical"
+  left="0"
+  top="0"
+  right="-1"
+  bottom="-1">
+    <layout_panel
+      auto_resize="false"
+      name="layout_item_name"
       layout="topleft"
-      left="0"
-      name="item_profile"
-      top="0"
-      width="295">
-      <text
-        type="string"
-        length="1"
-        follows="left|top"
-        height="10"
+      follows="all"
+      height="25">
+      <icon
+        follows="top|left"
+        height="16"
+        image_name="Inv_Object"
         layout="topleft"
         left="5"
-        name="LabelItemNameTitle"
-        top="10"
-        width="78">
-        Name:
-      </text>
+        mouse_opaque="true"
+        name="item_type_icon"
+        top="3"
+        width="16" />
       <line_editor
         border_style="line"
         border_thickness="1"
         follows="left|top|right"
-        height="20"
         layout="topleft"
-        left_delta="78"
+        left_pad="5"
+        top="1"
+        right="-5"
+        height="20"
         max_length_bytes="63"
         name="LabelItemName"
-        top_delta="0"
-        width="210"
         tool_tip="The name is limited to 63 characters. Longer prim names are cut short. Names can only consist of printable characters found in the ASCII-7 (non-extended) character set, with the exception of the vertical bar/pipe &apos;|&apos;." />
-      <text
-        type="string"
-        length="1"
-        follows="left|top"
-        height="10"
+    </layout_panel>
+    
+    <layout_panel
+      auto_resize="false"
+      name="layout_item_details"
+      layout="topleft"
+      follows="all"
+      height="133">
+      
+      <thumbnail
+        name="item_thumbnail"
+        fallback_image="Thumbnail_Fallback"
+        follows="top|left"
         layout="topleft"
         left="5"
-        name="LabelItemDescTitle"
-        top_pad="10"
-        width="78">
-        Description:
-      </text>
-      <line_editor
-        border_style="line"
-        border_thickness="1"
-        follows="left|top|right"
-        height="23"
-        layout="topleft"
-        left_delta="78"
-        max_length_bytes="127"
-        name="LabelItemDesc"
-        top_delta="-5"
-        width="210"
-        tool_tip="When people have &apos;Hover Tips on All Objects&apos; selected in the viewer's settings, they'll see the object description pop-up for any object under their mouse pointer. The prim description is limited to 127 bytes any string longer then that will be truncated." />
+        top="2"
+        height="128"
+        width="128"
+        />
+        
       <text
         type="string"
         length="1"
         follows="left|top"
-        height="23"
+        height="16"
         layout="topleft"
-        left="5"
-        name="LabelCreatorTitle"
-        top_pad="10"
+        left_pad="5"
+        name="LabelOwnerTitle"
+        top="0"
         width="78">
-        Creator:
+        Owner:
       </text>
-      <avatar_icon
-        follows="top|left"
-        height="20"
-        default_icon_name="Generic_Person"
-        layout="topleft"
-        left_pad="0"
-        top_delta="-6"
-        mouse_opaque="true"
-        width="20" />
       <text
         type="string"
-        follows="left|right|top"
         font="SansSerifSmall"
-        height="15"
+        follows="left|right|top"
         layout="topleft"
-        left_pad="5"
-        name="LabelCreatorName"
-        top_delta="6"
+        height="15"
+        width="187"
+        left_delta="0"
+        top_pad="0"
+        name="LabelOwnerName"
         use_ellipses="true"
-        width="165">
+        translate="false">
+TestString PleaseIgnore
       </text>
-      <button
-        follows="top|right"
-        height="16"
-        image_selected="Inspector_I"
-        image_unselected="Inspector_I"
-        layout="topleft"
-        right="-5"
-        name="BtnCreator"
-        top_delta="-6"
-        width="16" />
       <text
         type="string"
         length="1"
         follows="left|top"
-        height="23"
+        height="16"
         layout="topleft"
-        left="5"
-        name="LabelOwnerTitle"
-        top_pad="10"
+        left_delta="0"
+        name="LabelCreatorTitle"
+        top_pad="7"
         width="78">
-        Owner:
+        Creator:
       </text>
-      <avatar_icon
-        follows="top|left"
-        height="20"
-        default_icon_name="Generic_Person"
-        layout="topleft"
-        left_pad="0"
-        top_delta="-6"
-        mouse_opaque="true"
-        width="20" />
       <text
         type="string"
-        follows="left|right|top"
         font="SansSerifSmall"
-        height="15"
+        follows="left|right|top"
         layout="topleft"
-        left_pad="5"
-        name="LabelOwnerName"
-        top_delta="6"
+        left_delta="0"
+        top_pad="0"
+        width="187"
+        height="15"
+        name="LabelCreatorName"
         use_ellipses="true"
-        width="165">
+        translate="false">
+TestString PleaseIgnore
       </text>
-      <button
-        follows="top|right"
-        height="16"
-        image_selected="Inspector_I"
-        image_unselected="Inspector_I"
-        layout="topleft"
-        right="-5"
-        name="BtnOwner"
-        top_delta="-3"
-        width="16" />
       <text
         type="string"
         length="1"
         follows="left|top"
-        height="23"
+        height="16"
         layout="topleft"
-        left="5"
+        left_delta="0"
         name="LabelAcquiredTitle"
-        top_pad="10"
+        top_pad="7"
         width="78">
         Acquired:
       </text>
@@ -258,188 +170,247 @@
         type="string"
         length="1"
         follows="left|top|right"
-        height="23"
+        height="18"
         layout="topleft"
-        left_delta="78"
+        left_delta="0"
         name="LabelAcquiredDate"
-        top_delta="0"
-        width="210">
+        top_pad="0"
+        width="187">
+        00/00/00
       </text>
-      <text
-        type="string"
-        length="1"
+      <button
         follows="left|top"
-        height="10"
+        height="21"
+        label="Image..."
         layout="topleft"
-        left="5"
-        name="LabelItemExperienceTitle"
+        left_delta="0"
+        name="change_thumbnail_btn"
         top_pad="0"
-        width="78"
-        visible="true">
-        Experience:
-      </text>
+        width="120" />
+    </layout_panel>
+    
+    <layout_panel
+      auto_resize="false"
+      name="layout_item_description"
+      layout="topleft"
+      follows="all"
+      height="84">
       <text
         type="string"
         length="1"
-        follows="left|top|right"
+        follows="left|top"
         height="10"
         layout="topleft"
-        left_delta="78"
-        name="LabelItemExperience"
-        top_delta="0"
-        width="210"
-        visible="true"
-        />
-      <panel
-        border="false"
-        follows="left|top|right"
+        left="5"
+        name="LabelItemDescTitle"
+        top="0"
+        width="78">
+        Description:
+      </text>
+      <text_editor
+        text_type="ascii_printable_no_pipe"
+        commit_on_focus_lost="true"
+        border_style="line"
+        border_thickness="1"
+        word_wrap="true"
+        use_ellipses="false"
+        follows="all"
         layout="topleft"
-        mouse_opaque="false"
-        name="perms_inv"
-        left="0"
-        top_pad="25"
-        height="155"
-        width="313">
-        <text
-          type="string"
-          length="1"
-          left="10"
-          top_pad="13"
-          text_color="EmphasisColor"
-          height="15"
-          follows="left|top|right"
-          layout="topleft"
-          name="perm_modify"
-          width="200">
-          You can:
-        </text>
-        <check_box
-          height="18"
-          label="Modify"
-          layout="topleft"
-          left="20"
-          name="CheckOwnerModify"
-          top_pad="0"
-          width="90" />
-        <check_box
-          height="18"
-          label="Copy"
-          layout="topleft"
-          left_pad="0"
-          name="CheckOwnerCopy"
-          width="90" />
-        <check_box
-          height="18"
-          label="Transfer"
-          layout="topleft"
-          left_pad="0"
-          name="CheckOwnerTransfer"
-          width="106" />
-        <check_box
-          height="18"
-          label="Export"
-          layout="topleft"
-          left="20"
-          top_pad="4"
-          name="CheckOwnerExport"
-          width="106" />
-        <text
-          type="string"
-          length="1"
-          follows="left|top"
-          height="16"
-          layout="topleft"
-          left="10"
-          name="AnyoneLabel"
-          top_pad="8"
-          width="100">
-          Anyone:
-        </text>
-        <check_box
-          height="18"
-          label="Copy"
-          layout="topleft"
-          left_pad="0"
-          name="CheckEveryoneCopy"
-          tool_tip="Anyone can take a copy of the object . Object and all of its contents must be copy and transfer permissive."
-          top_delta="-2"
-          width="150" />
+        left="5"
+        top_pad="5"
+        right="-5"
+        height="46"
+        max_length="127"
+        name="LabelItemDesc"
+        tool_tip="When people have &apos;Hover Tips on All Objects&apos; selected in the viewer's settings, they'll see the object description pop-up for any object under their mouse pointer. The prim description is limited to 127 bytes any string longer then that will be truncated." />
+
         <text
           type="string"
           length="1"
           follows="left|top"
-          height="16"
+          height="10"
           layout="topleft"
-          left="10"
-          name="GroupLabel"
-          top_pad="8"
-          width="100">
-          Group:
+          left="5"
+          name="LabelItemExperienceTitle"
+          top_pad="7"
+          width="78"
+          visible="true">
+          Experience:
         </text>
-        <check_box
-          height="18"
-          label="Share"
-          layout="topleft"
-          left_pad="0"
-          top_delta="-2"
-          name="CheckShareWithGroup"
-          tool_tip="Allow all members of the set group to share your modify permissions for this object. You must Deed to enable role restrictions."
-          width="150" />
         <text
           type="string"
           length="1"
-          follows="left|top"
-          height="16"
-          layout="topleft"
-          left="10"
-          name="NextOwnerLabel"
-          top_pad="8"
-          width="200"
-          word_wrap="true">
-          Next owner:
-        </text>
-        <check_box
-          height="18"
-          label="Modify"
-          layout="topleft"
-          left="20"
-          top_pad="0"
-          name="CheckNextOwnerModify"
-          tool_tip="Next owner can edit properties like item name or scale of this object."
-          width="90" />
-        <check_box
-          height="18"
-          label="Copy"
-          layout="topleft"
-          left_pad="0"
-          name="CheckNextOwnerCopy"
-          tool_tip="Next owner can make unlimited copies of this object. Copies maintain creator information, and can never be more permissive than the item being copied."
-          width="90" />
-        <check_box
-          height="18"
-          label="Transfer"
-          layout="topleft"
-          left_pad="0"
-          name="CheckNextOwnerTransfer"
-          tool_tip="Next owner can give away or resell this object."
-          width="106" />
-        <check_box
-          height="18"
-          label="Export"
+          follows="left|top|right"
+          height="10"
           layout="topleft"
-          left="20"
-          top_pad="4"
-          name="CheckNextOwnerExport"
-          tool_tip="Next owner can export this object to other grids"
-          width="106" />
-      </panel>
+          left_delta="78"
+          name="LabelItemExperience"
+          top_delta="0"
+          width="210"
+          visible="true"
+          />
+    </layout_panel>
+    
+    <layout_panel
+      auto_resize="false"
+      name="layout_item_permissions_sale"
+      layout="topleft"
+      follows="all"
+      height="235">
+      
+      <view_border
+        bevel_style="none"
+        height="0"
+        layout="topleft"
+        left="5"
+        right="-5"
+        name="cost_text_border"
+        top="1"/>
+        
+      <text
+        type="string"
+        length="1"
+        left="10"
+        top_pad="7"
+        height="15"
+        follows="left|top"
+        layout="topleft"
+        name="perm_modify"
+        width="200">
+        Permissions
+      </text>
+
+      <text
+        type="string"
+        length="1"
+        left="10"
+        top_pad="5"
+        height="15"
+        follows="left|top"
+        layout="topleft"
+        name="perm_modify"
+        width="200">
+        You can:
+      </text>
+      <check_box
+        height="18"
+        label="Modify"
+        layout="topleft"
+        left="20"
+        name="CheckOwnerModify"
+        top_pad="0"
+        width="90" />
+      <check_box
+        height="18"
+        label="Copy"
+        layout="topleft"
+        left_pad="0"
+        name="CheckOwnerCopy"
+        width="90" />
+      <check_box
+        height="18"
+        label="Transfer"
+        layout="topleft"
+        left_pad="0"
+        name="CheckOwnerTransfer"
+        width="106" />
+      <text
+        type="string"
+        length="1"
+        follows="left|top"
+        height="16"
+        layout="topleft"
+        left="10"
+        name="AnyoneLabel"
+        top_pad="8"
+        width="100">
+        Anyone:
+      </text>
+      <check_box
+        height="18"
+        label="Copy"
+        layout="topleft"
+        left_pad="0"
+        name="CheckEveryoneCopy"
+        tool_tip="Anyone can take a copy of the object . Object and all of its contents must be copy and transfer permissive."
+        top_delta="-2"
+        width="150" />
+      <text
+        type="string"
+        length="1"
+        follows="left|top"
+        height="16"
+        layout="topleft"
+        left="10"
+        name="GroupLabel"
+        top_pad="8"
+        width="100">
+        Group:
+      </text>
+      <check_box
+        height="18"
+        label="Share"
+        layout="topleft"
+        left_pad="0"
+        top_delta="-2"
+        name="CheckShareWithGroup"
+        tool_tip="Allow all members of the set group to share your modify permissions for this object. You must Deed to enable role restrictions."
+        width="150" />
+      <text
+        type="string"
+        length="1"
+        follows="left|top"
+        height="16"
+        layout="topleft"
+        left="10"
+        name="NextOwnerLabel"
+        top_pad="8"
+        width="200"
+        word_wrap="true">
+        Next owner:
+      </text>
+      <check_box
+        height="18"
+        label="Modify"
+        layout="topleft"
+        left="20"
+        top_pad="0"
+        name="CheckNextOwnerModify"
+        tool_tip="Next owner can edit properties like item name or scale of this object."
+        width="90" />
+      <check_box
+        height="18"
+        label="Copy"
+        layout="topleft"
+        left_pad="0"
+        name="CheckNextOwnerCopy"
+        tool_tip="Next owner can make unlimited copies of this object. Copies maintain creator information, and can never be more permissive than the item being copied."
+        width="90" />
+      <check_box
+        height="18"
+        label="Transfer"
+        layout="topleft"
+        left_pad="0"
+        name="CheckNextOwnerTransfer"
+        tool_tip="Next owner can give away or resell this object."
+        width="106" />
+        
+    <view_border
+        bevel_style="none"
+        height="0"
+        layout="topleft"
+        left="5"
+        right="-5"
+        name="cost_text_border"
+        top_pad="9"/>
+        
       <check_box
         height="18"
         label="For Sale"
         layout="topleft"
         left="20"
         name="CheckPurchase"
-        top_pad="30"
+        top_pad="15"
         width="100"
         tool_tip="Lets people buy this object, its content or it copy inworld for specified price." />
       <combo_box
@@ -467,6 +438,7 @@
         follows="left|top"
         decimal_digits="0"
         increment="1"
+        control_name="Edit Cost"
         name="Edit Cost"
         label="Price: L$"
         label_width="75"
@@ -477,88 +449,80 @@
         max_val="999999999"
         top_pad="10"
         tool_tip="Object cost." />
-      <text
-        type="string"
-        length="1"
-        follows="left|top"
-        height="10"
-        layout="topleft"
-        left="10"
-        name="BaseMaskDebug"
-        text_color="White"
-        top_pad="30"
-        width="130">
-        B:
-      </text>
-      <text
-        type="string"
-        length="1"
-        follows="left|top"
-        height="10"
-        layout="topleft"
-        left_delta="60"
-        name="OwnerMaskDebug"
-        text_color="White"
-        top_delta="0"
-        width="270">
-        O:
-      </text>
-      <text
-        type="string"
-        length="1"
-        follows="left|top"
-        height="10"
-        layout="topleft"
-        left_delta="60"
-        name="GroupMaskDebug"
-        text_color="White"
-        top_delta="0"
-        width="210">
-        G:
-      </text>
-      <text
-        type="string"
-        length="1"
-        follows="left|top"
-        height="10"
-        layout="topleft"
-        left_delta="60"
-        name="EveryoneMaskDebug"
-        text_color="White"
-        top_delta="0"
-        width="150">
-        E:
-      </text>
-      <text
-       type="string"
-       length="1"
-       follows="left|top"
-       height="10"
-       layout="topleft"
-       left_delta="60"
-       name="NextMaskDebug"
-       text_color="White"
-       top_delta="0"
-       width="90">
-        N:
-      </text>
-    </panel>   
-  </scroll_container>
-  <panel
-    height="30"
-    layout="topleft"
-    name="button_panel"
-    left="5"
-    top_pad="0"
-    width="313"
-    follows="top|right|left">
-    <button
-      follows="top|right"
-      height="23"
-      label="Cancel"
-      layout="topleft"
-      name="cancel_btn"
-      right="-1"
-      width="100" />
-  </panel>
+      
+    </layout_panel>
+
+    <layout_panel
+     auto_resize="false"
+     name="layout_debug_permissions"
+     layout="topleft"
+     follows="all"
+     height="30">
+        <text
+          type="string"
+          length="1"
+          follows="left|top"
+          height="10"
+          layout="topleft"
+          left="10"
+          name="BaseMaskDebug"
+          text_color="White"
+          top="2"
+          width="130">
+          B:
+        </text>
+        <text
+          type="string"
+          length="1"
+          follows="left|top"
+          height="10"
+          layout="topleft"
+          left_delta="60"
+          name="OwnerMaskDebug"
+          text_color="White"
+          top_delta="0"
+          width="270">
+          O:
+        </text>
+        <text
+          type="string"
+          length="1"
+          follows="left|top"
+          height="10"
+          layout="topleft"
+          left_delta="60"
+          name="GroupMaskDebug"
+          text_color="White"
+          top_delta="0"
+          width="210">
+          G:
+        </text>
+        <text
+          type="string"
+          length="1"
+          follows="left|top"
+          height="10"
+          layout="topleft"
+          left_delta="60"
+          name="EveryoneMaskDebug"
+          text_color="White"
+          top_delta="0"
+          width="150">
+          E:
+        </text>
+        <text
+         type="string"
+         length="1"
+         follows="left|top"
+         height="10"
+         layout="topleft"
+         left_delta="60"
+         name="NextMaskDebug"
+         text_color="White"
+         top_delta="0"
+         width="90">
+          N:
+        </text>
+    </layout_panel>
+  </layout_stack>
 </panel>
diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
index fd172cc51e7378b61b3c8acd356332abe90871e9..9e69f3dfe30db2454946a7bb41656e5d8da3c326 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
@@ -62,25 +62,12 @@
              name="Sale Mixed">
                 Mixed Sale
             </panel.string>
-    <button
-     follows="top|left"
-     height="24"
-     image_hover_unselected="BackButton_Over"
-     image_pressed="BackButton_Press"
-     image_unselected="BackButton_Off"
-     layout="topleft"
-     left="8"
-     name="back_btn"
-     tab_stop="false"
-     top="0"
-     width="30"
-     use_draw_context_alpha="false" />
-        <text
+    <text
      follows="top|left|right"
      font="SansSerifHuge"
      height="26"
      layout="topleft"
-     left_pad="10"
+     left="48"
      name="title"
      text_color="LtGray"
      top="0"
@@ -181,7 +168,6 @@
 		     translate="false"
          use_ellipses="true" 
 		     width="225">
-	        TestString PleaseIgnore
 	     </text>
 	    <text
 			 type="string"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 470036ee1bad6d84b433d9e901a665480de035a2..86b4ce88f182afddf0679254b846fa749312481e 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -2332,6 +2332,8 @@ For AI Character: Get the closest navigable point to the point provided.
 	<string name="FavoritesNoMatchingItems">To add a place to your favorites, click the star to the right of the location name, then save the landmark to "Favorites bar".</string>
 	<string name="MarketplaceNoListing">You have no listings yet.</string>
 	<string name="MarketplaceNoMatchingItems">No items found. Check the spelling of your search string and try again.</string>
+	<string name="InventorySingleFolderEmpty">Folder is empty.</string>
+	<string name="InventorySingleFolderNoMatches">No matches.</string>
 	<string name="InventoryNoTexture">You do not have a copy of this texture in your inventory</string>
 	<string name="InventoryInboxNoItems">Your Marketplace purchases will appear here. You may then drag them into your inventory to use them.</string>
 	<string name="MarketplaceURL">https://marketplace.[MARKETPLACE_DOMAIN_NAME]/</string>
@@ -2379,6 +2381,7 @@ If you continue to receive this message, please contact Second Life support for
 	<string name="InventoryMarketplaceListingsNoItems">
         Drag folders to this area to list them for sale on the [[MARKETPLACE_DASHBOARD_URL] Marketplace].
 	</string>
+    <string name="InventoryFolderDebug">( F:[FOLDER_COUNT] I:[ITEMS_COUNT] V:[VERSION] DC:[VIEWER_DESCENDANT_COUNT]/[SERVER_DESCENDANT_COUNT] )</string>
 	<string name="InventoryItemsCount">( [ITEMS_COUNT] Items )</string>
 	<string name="Marketplace Validation Log"></string>
 	<string name="Marketplace Validation Warning Stock">stock folder must be contained by a version folder</string>
@@ -2417,12 +2420,16 @@ If you continue to receive this message, please contact Second Life support for
   <string name="Unconstrained">Unconstrained</string>
 
 	<!-- use value="" because they have preceding spaces -->
+    <string name="active" value=" (active)"/>
 	<string name="no_transfer" value=" (no transfer)" />
 	<string name="no_modify"   value=" (no modify)" />
 	<string name="no_copy"     value=" (no copy)" />
 	<string name="worn"        value=" (worn)" />
-	<string name="link"        value=" (link)" />
-	<string name="broken_link" value=" (broken_link)" />
+	<string name="link"        value="  link" />
+	<string name="broken_link" value="  broken_link" />
+    <string name="no_transfer_lbl" value=" no transfer" />
+    <string name="no_modify_lbl"   value=" no modify" />
+    <string name="no_copy_lbl"     value=" no copy" />
 	<string name="LoadingContents">Loading contents...</string>
 	<string name="NoContents">No contents</string>
 	<string name="WornOnAttachmentPoint" value=" (worn on [ATTACHMENT_POINT])" />
diff --git a/indra/newview/skins/default/xui/es/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/es/floater_inventory_item_properties.xml
deleted file mode 100644
index a8a3ad08f8d92ed60859a8af919528a821c7e3ea..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/es/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="PROPIEDADES DEL ÍTEM DEL INVENTARIO">
-	<floater.string name="unknown">(desconocido)</floater.string>
-	<floater.string name="public">(público)</floater.string>
-	<floater.string name="you_can">Usted puede:</floater.string>
-	<floater.string name="owner_can">El propietario puede:</floater.string>
-	<floater.string name="acquiredDate">[wkday,datetime,local][day,datetime,local] [mth,datetime,local] [year,datetime,local][hour,datetime,local]:[min,datetime,local]:[second,datetime,local]</floater.string>
-	<text name="LabelItemNameTitle">Nombre:</text>
-	<text name="LabelItemDescTitle">Descripción:</text>
-	<text name="LabelCreatorTitle">Creador:</text>
-	<button label="Perfil..." label_selected="" name="BtnCreator"/>
-	<text name="LabelOwnerTitle">Propietario:</text>
-	<button label="Perfil..." label_selected="" name="BtnOwner"/>
-	<text name="LabelAcquiredTitle">Adquirido:</text>
-	<text name="LabelAcquiredDate">May Mié 24 12:50:46 2006</text>
-	<text name="OwnerLabel">Tú:</text>
-	<check_box label="Editar" name="CheckOwnerModify"/>
-	<check_box label="Copiarlo" left_delta="88" name="CheckOwnerCopy"/>
-	<check_box label="Revender" name="CheckOwnerTransfer"/>
-	<text name="AnyoneLabel">Cualquiera:</text>
-	<check_box label="Copiar" name="CheckEveryoneCopy"/>
-	<text name="GroupLabel">Grupo:</text>
-	<check_box label="Compartir" name="CheckShareWithGroup"/>
-	<text name="NextOwnerLabel" width="230">Próximo propietario:</text>
-	<check_box label="Editar" name="CheckNextOwnerModify"/>
-	<check_box label="Copiarlo" left_delta="88" name="CheckNextOwnerCopy"/>
-	<check_box label="Revender" name="CheckNextOwnerTransfer"/>
-	<check_box label="En venta" name="CheckPurchase"/>
-	<combo_box name="ComboBoxSaleType">
-		<combo_box.item label="Copiar" name="Copy"/>
-		<combo_box.item label="Contenidos" name="Contents"/>
-		<combo_box.item label="Original" name="Original"/>
-	</combo_box>
-	<spinner label="Precio:" name="Edit Cost"/>
-	<text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/es/panel_main_inventory.xml b/indra/newview/skins/default/xui/es/panel_main_inventory.xml
index 1252c7ce0dfd14606441704bc039d5908baa991a..bf1205046bf54bf05c40372bfa75af4b3bc86dab 100644
--- a/indra/newview/skins/default/xui/es/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/es/panel_main_inventory.xml
@@ -9,6 +9,7 @@
 	<panel.string name="ItemcountUnknown">
 		[ITEM_COUNT] Objetos y [CATEGORY_COUNT] Carpetas Obtenidos [FILTER]
 	</panel.string>
+    <panel.string name="inventory_title">INVENTARIO</panel.string>
 	<text name="ItemcountText">
 		Ítems:
 	</text>
diff --git a/indra/newview/skins/default/xui/fr/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/fr/floater_inventory_item_properties.xml
deleted file mode 100644
index 1d4e7c818fe192e8b66a71423fecfa557aaa372b..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/fr/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="PROPRIÉTÉS DES ARTICLES DE L&apos;INVENTAIRE">
-	<floater.string name="unknown">(inconnu)</floater.string>
-	<floater.string name="public">(public)</floater.string>
-	<floater.string name="you_can">Vous pouvez :</floater.string>
-	<floater.string name="owner_can">Le propriétaire peut :</floater.string>
-	<floater.string name="acquiredDate">[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]</floater.string>
-	<text name="LabelItemNameTitle">Nom :</text>
-	<text name="LabelItemDescTitle">Description :</text>
-	<text name="LabelCreatorTitle">Créateur :</text>
-	<button label="Profil..." label_selected="" name="BtnCreator"/>
-	<text name="LabelOwnerTitle">Propriétaire :</text>
-	<button label="Profil..." label_selected="" name="BtnOwner"/>
-	<text name="LabelAcquiredTitle">Acquis :</text>
-	<text name="LabelAcquiredDate">Wed May 24 12:50:46 2006</text>
-	<text name="OwnerLabel">Vous :</text>
-	<check_box label="Modifier" name="CheckOwnerModify"/>
-	<check_box label="Copier" name="CheckOwnerCopy"/>
-	<check_box label="Revendre" name="CheckOwnerTransfer"/>
-	<text name="AnyoneLabel" width="80">N&apos;importe qui :</text>
-	<check_box label="Copier" name="CheckEveryoneCopy"/>
-	<text name="GroupLabel" width="80">Groupe :</text>
-	<check_box label="Partager" name="CheckShareWithGroup"/>
-	<text name="NextOwnerLabel" width="192">Le prochain propriétaire :</text>
-	<check_box label="Modifier" name="CheckNextOwnerModify"/>
-	<check_box label="Copier" name="CheckNextOwnerCopy"/>
-	<check_box label="Revendre" name="CheckNextOwnerTransfer"/>
-	<check_box label="À vendre" name="CheckPurchase"/>
-	<combo_box name="ComboBoxSaleType">
-		<combo_box.item label="Copier" name="Copy"/>
-		<combo_box.item label="Contenu" name="Contents"/>
-		<combo_box.item label="Original" name="Original"/>
-	</combo_box>
-	<spinner label="Prix :" name="Edit Cost"/>
-	<text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/fr/panel_main_inventory.xml b/indra/newview/skins/default/xui/fr/panel_main_inventory.xml
index 5bcee89752fb423cda4925b56bfcba4c36ff620c..5bf4d6c15d0bfe77a4e8e4adf0923036d67672ae 100644
--- a/indra/newview/skins/default/xui/fr/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/fr/panel_main_inventory.xml
@@ -9,6 +9,7 @@
 	<panel.string name="ItemcountUnknown">
 		Recherche effectuée [ITEM_COUNT] d&apos;articles et [CATEGORY_COUNT] de dossiers [FILTER]
 	</panel.string>
+    <panel.string name="inventory_title">INVENTAIRE</panel.string>
 	<text name="ItemcountText">
 		Articles :
 	</text>
diff --git a/indra/newview/skins/default/xui/it/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/it/floater_inventory_item_properties.xml
deleted file mode 100644
index 8cf680b3f0010186a95a35cb9b8142f4d9d08745..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/it/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="CARATTERISTICHE DELL&apos;ARTICOLO IN INVENTARIO">
-	<floater.string name="unknown">(sconosciuto)</floater.string>
-	<floater.string name="public">(pubblico)</floater.string>
-	<floater.string name="you_can">Tu puoi:</floater.string>
-	<floater.string name="owner_can">Il proprietario può:</floater.string>
-	<floater.string name="acquiredDate">[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]</floater.string>
-	<text name="LabelItemNameTitle">Nome:</text>
-	<text name="LabelItemDescTitle">Descrizione:</text>
-	<text name="LabelCreatorTitle">Creatore:</text>
-	<button label="Profilo..." label_selected="" name="BtnCreator"/>
-	<text name="LabelOwnerTitle">proprietario:</text>
-	<button label="Profilo..." label_selected="" name="BtnOwner"/>
-	<text name="LabelAcquiredTitle">Acquisito:</text>
-	<text name="LabelAcquiredDate">Wed May 24 12:50:46 2006</text>
-	<text name="OwnerLabel">Tu:</text>
-	<check_box label="Modifica" name="CheckOwnerModify"/>
-	<check_box label="Copiare" left_delta="88" name="CheckOwnerCopy"/>
-	<check_box label="Rivendi" name="CheckOwnerTransfer"/>
-	<text name="AnyoneLabel">Chiunque:</text>
-	<check_box label="Copia" name="CheckEveryoneCopy"/>
-	<text name="GroupLabel">Gruppo:</text>
-	<check_box label="Condividi" name="CheckShareWithGroup"/>
-	<text name="NextOwnerLabel" width="230">Proprietario successivo:</text>
-	<check_box label="Modifica" name="CheckNextOwnerModify"/>
-	<check_box label="Copiare" left_delta="88" name="CheckNextOwnerCopy"/>
-	<check_box label="Rivendi" name="CheckNextOwnerTransfer"/>
-	<check_box label="In vendita" name="CheckPurchase"/>
-	<combo_box name="ComboBoxSaleType">
-		<combo_box.item label="Copia" name="Copy"/>
-		<combo_box.item label="Contenuti" name="Contents"/>
-		<combo_box.item label="Originale" name="Original"/>
-	</combo_box>
-	<spinner label="Prezzo:" name="Edit Cost"/>
-	<text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/it/panel_main_inventory.xml b/indra/newview/skins/default/xui/it/panel_main_inventory.xml
index 5d11967cee288affd2d3fd64564b09a3a1b85f80..d6890229e7ef667838b99497b9144f3ca072f75a 100644
--- a/indra/newview/skins/default/xui/it/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/it/panel_main_inventory.xml
@@ -9,6 +9,7 @@
 	<panel.string name="ItemcountUnknown">
 		Recuperati [ITEM_COUNT] oggetti e [CATEGORY_COUNT] cartelle [FILTER]
 	</panel.string>
+    <panel.string name="inventory_title">INVENTARIO</panel.string>
 	<text name="ItemcountText">
 		Oggetti:
 	</text>
diff --git a/indra/newview/skins/default/xui/ja/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/ja/floater_inventory_item_properties.xml
deleted file mode 100644
index 102e21d4ee29acec9da382e83a54a8a60916ccd0..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/ja/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="インベントリアイテムのプロパティ">
-	<floater.string name="unknown">(不明)</floater.string>
-	<floater.string name="public">(公共)</floater.string>
-	<floater.string name="you_can">できること:</floater.string>
-	<floater.string name="owner_can">オーナーは次のことができます:</floater.string>
-	<floater.string name="acquiredDate">[year,datetime,local]年[mth,datetime,local]月[day,datetime,local]日[wkday,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]</floater.string>
-	<text name="LabelItemNameTitle">名前:</text>
-	<text name="LabelItemDescTitle">説明:</text>
-	<text name="LabelCreatorTitle">制作者:</text>
-	<button label="プロフィール…" label_selected="" name="BtnCreator"/>
-	<text name="LabelOwnerTitle">所有者:</text>
-	<button label="プロフィール…" label_selected="" name="BtnOwner"/>
-	<text name="LabelAcquiredTitle">入手日時:</text>
-	<text name="LabelAcquiredDate">2006年5月24日水曜日 12:50:46</text>
-	<text name="OwnerLabel">あなた:</text>
-	<check_box label="編集" name="CheckOwnerModify"/>
-	<check_box label="コピー" name="CheckOwnerCopy"/>
-	<check_box label="再販・譲渡" name="CheckOwnerTransfer"/>
-	<text name="AnyoneLabel">全員:</text>
-	<check_box label="コピー" name="CheckEveryoneCopy"/>
-	<text name="GroupLabel">グループ:</text>
-	<check_box label="共有" name="CheckShareWithGroup"/>
-	<text name="NextOwnerLabel">次の所有者:</text>
-	<check_box label="編集" name="CheckNextOwnerModify"/>
-	<check_box label="コピー" name="CheckNextOwnerCopy"/>
-	<check_box label="再販・譲渡" name="CheckNextOwnerTransfer"/>
-	<check_box label="売り出し中" name="CheckPurchase"/>
-	<combo_box name="ComboBoxSaleType">
-		<combo_box.item label="コピー" name="Copy"/>
-		<combo_box.item label="コンテンツ" name="Contents"/>
-		<combo_box.item label="オリジナル" name="Original"/>
-	</combo_box>
-	<spinner label="価格:" name="Edit Cost"/>
-	<text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/ja/panel_main_inventory.xml b/indra/newview/skins/default/xui/ja/panel_main_inventory.xml
index 1f3973e1b7163e15624cffc18641100bfa901cc6..1885f90b8e150a5a88a827b885541f54b4fa2cd4 100644
--- a/indra/newview/skins/default/xui/ja/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/ja/panel_main_inventory.xml
@@ -3,6 +3,7 @@
 	<panel.string name="ItemcountFetching">[ITEM_COUNT]個のアイテムと[CATEGORY_COUNT]個のフォルダーを取得しています…。[FILTER]</panel.string>
 	<panel.string name="ItemcountCompleted">[ITEM_COUNT]個のアイテムと[CATEGORY_COUNT]個のフォルダーの取得が完了しました。[FILTER]</panel.string>
 	<panel.string name="ItemcountUnknown">[ITEM_COUNT]個のアイテムと[CATEGORY_COUNT]個のフォルダーを取得しました。[FILTER]</panel.string>
+    <panel.string name="inventory_title">インベントリ</panel.string>
 	<text name="ItemcountText">アイテム:</text>
 	<filter_editor label="検索用語を入力する" name="inventory search editor" tool_tip="検索したい単語は「+」で区切って複数入力してください。"/>
 	<combo_box name="search_type">
diff --git a/indra/newview/skins/default/xui/pl/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/pl/floater_inventory_item_properties.xml
deleted file mode 100644
index d2844e117f07069d1ccd389becc35972422b9f31..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/pl/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<floater name="item properties" title="WŁAŚCIWOŚCI OBIEKTÓW W SZAFIE">
-	<floater.string name="unknown">
-		(nieznany)
-	</floater.string>
-	<floater.string name="public">
-		(publiczny)
-	</floater.string>
-	<floater.string name="you_can">
-		Ty możesz:
-	</floater.string>
-	<floater.string name="owner_can">
-		Właściciel może:
-	</floater.string>
-	<text name="LabelItemNameTitle">
-		Nazwa:
-	</text>
-	<text name="LabelItemDescTitle">
-		Opis:
-	</text>
-	<text name="LabelCreatorTitle">
-		Twórca:
-	</text>
-	<button label="Profil..." name="BtnCreator" />
-	<text name="LabelOwnerTitle">
-		Właściciel:
-	</text>
-	<button label="Profil..." name="BtnOwner" />
-	<text name="LabelAcquiredTitle">
-		Nabyte:
-	</text>
-	<text name="OwnerLabel">
-		Ty:
-	</text>
-	<check_box label="Modyfikacja" name="CheckOwnerModify" />
-	<check_box label="Kopiowanie" name="CheckOwnerCopy" />
-	<check_box label="Transferowanie" name="CheckOwnerTransfer" />
-	<text name="AnyoneLabel">
-		Każdy:
-	</text>
-	<check_box label="Kopiowanie" name="CheckEveryoneCopy" />
-	<text name="GroupLabel">
-		Grupa:
-	</text>
-	<check_box label="Udostępnij" name="CheckShareWithGroup" />
-	<text name="NextOwnerLabel">
-		Nast. właściciel:
-	</text>
-	<check_box label="Modyfikacja" name="CheckNextOwnerModify" />
-	<check_box label="Kopiowanie" name="CheckNextOwnerCopy" />
-	<check_box label="Transferowanie" name="CheckNextOwnerTransfer" />
-	<check_box label="Sprzedaż" name="CheckPurchase" />
-	<combo_box name="ComboBoxSaleType">
-		<combo_box.item label="Kopia" name="Copy" />
-		<combo_box.item label="Zawartość" name="Contents" />
-		<combo_box.item label="Oryginał" name="Original" />
-	</combo_box>
-	<spinner name="Edit Cost" label="Cena:" />
-</floater>
diff --git a/indra/newview/skins/default/xui/pl/panel_main_inventory.xml b/indra/newview/skins/default/xui/pl/panel_main_inventory.xml
index dc254e246f09b7ec73678833ae663f4c1397ec6d..1011c38378fedc193b3453c9a14b948d105383ff 100644
--- a/indra/newview/skins/default/xui/pl/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/pl/panel_main_inventory.xml
@@ -6,6 +6,7 @@
 	<panel.string name="ItemcountCompleted">
 		[ITEM_COUNT] obiekty [FILTER]
 	</panel.string>
+    <panel.string name="inventory_title">MOJA SZAFA</panel.string>
 	<text name="ItemcountText">
 		Obiekty:
 	</text>
diff --git a/indra/newview/skins/default/xui/pt/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/pt/floater_inventory_item_properties.xml
deleted file mode 100644
index 5f04c0853131a43de8b04cb10cf3f550c7b5e8e4..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/pt/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="PROPRIEDADES DE ITEM NO INVENTÁRIO">
-	<floater.string name="unknown">(desconhecido)</floater.string>
-	<floater.string name="public">(público)</floater.string>
-	<floater.string name="you_can">Você pode:</floater.string>
-	<floater.string name="owner_can">Proprietário pode :</floater.string>
-	<floater.string name="acquiredDate">[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]</floater.string>
-	<text name="LabelItemNameTitle">Nome:</text>
-	<text name="LabelItemDescTitle">Descrição:</text>
-	<text name="LabelCreatorTitle">Criador:</text>
-	<button label="Perfil..." label_selected="" name="BtnCreator"/>
-	<text name="LabelOwnerTitle">Dono:</text>
-	<button label="Perfil..." label_selected="" name="BtnOwner"/>
-	<text name="LabelAcquiredTitle">Adquirido:</text>
-	<text name="LabelAcquiredDate">Qua Mai 24 12:50:46 2006</text>
-	<text name="OwnerLabel">Você:</text>
-	<check_box label="Editar" name="CheckOwnerModify"/>
-	<check_box label="Copiar" name="CheckOwnerCopy"/>
-	<check_box label="Revender" name="CheckOwnerTransfer"/>
-	<text name="AnyoneLabel">Todos:</text>
-	<check_box label="Cortar" name="CheckEveryoneCopy"/>
-	<text name="GroupLabel">Grupo:</text>
-	<check_box label="Compartilhar" name="CheckShareWithGroup"/>
-	<text name="NextOwnerLabel" width="230">Próximo proprietário:</text>
-	<check_box label="Editar" name="CheckNextOwnerModify"/>
-	<check_box label="Copiar" name="CheckNextOwnerCopy"/>
-	<check_box label="Revender" name="CheckNextOwnerTransfer"/>
-	<check_box label="À venda" name="CheckPurchase"/>
-	<combo_box name="ComboBoxSaleType">
-		<combo_box.item label="Cortar" name="Copy"/>
-		<combo_box.item label="Conteúdo" name="Contents"/>
-		<combo_box.item label="Original" name="Original"/>
-	</combo_box>
-	<spinner label="Preço:" name="Edit Cost"/>
-	<text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/pt/panel_main_inventory.xml b/indra/newview/skins/default/xui/pt/panel_main_inventory.xml
index 009b5b31937042b6fe05447bd538e498fd00c850..e0cf528468ee7492b4c7debbb60a1cd4c099b3eb 100644
--- a/indra/newview/skins/default/xui/pt/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/pt/panel_main_inventory.xml
@@ -9,6 +9,7 @@
 	<panel.string name="ItemcountUnknown">
 		Itens [ITEM_COUNT] e Pastas [CATEGORY_COUNT] Reunidos [FILTER]
 	</panel.string>
+    <panel.string name="inventory_title">INVENTÁRIO</panel.string>
 	<text name="ItemcountText">
 		Itens:
 	</text>
diff --git a/indra/newview/skins/default/xui/ru/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/ru/floater_inventory_item_properties.xml
deleted file mode 100644
index c988825756e949d4bee091071abc7f0060d7883b..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/ru/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="СВОЙСТВА ПРЕДМЕТА">
-	<floater.string name="unknown">(неизвестно)</floater.string>
-	<floater.string name="public">(публичное)</floater.string>
-	<floater.string name="you_can">Вы можете:</floater.string>
-	<floater.string name="owner_can">Владелец может:</floater.string>
-	<floater.string name="acquiredDate">[wkday,datetime,local], [day,datetime,local] [mth,datetime,local] [year,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]</floater.string>
-	<text name="LabelItemNameTitle">Название:</text>
-	<text name="LabelItemDescTitle">Описание:</text>
-	<text name="LabelCreatorTitle">Создатель:</text>
-	<button label="Профиль…" name="BtnCreator"/>
-	<text name="LabelOwnerTitle">Владелец:</text>
-	<button label="Профиль…" name="BtnOwner"/>
-	<text name="LabelAcquiredTitle">Приобретено:</text>
-	<text name="LabelAcquiredDate">Ср 24 Май 12:50:46 2006</text>
-	<text name="OwnerLabel">Ð’Ñ‹:</text>
-	<check_box label="Изменить" name="CheckOwnerModify"/>
-	<check_box label="Копировать" name="CheckOwnerCopy"/>
-	<check_box label="Перепродать" name="CheckOwnerTransfer"/>
-	<text name="AnyoneLabel">Все:</text>
-	<check_box label="Копировать" name="CheckEveryoneCopy"/>
-	<text name="GroupLabel">Группа:</text>
-	<check_box label="Поделиться" name="CheckShareWithGroup"/>
-	<text name="NextOwnerLabel">Следующий владелец:</text>
-	<check_box label="Изменить" name="CheckNextOwnerModify"/>
-	<check_box label="Копировать" name="CheckNextOwnerCopy"/>
-	<check_box label="Перепродать" name="CheckNextOwnerTransfer"/>
-	<check_box label="Для продажи" name="CheckPurchase"/>
-	<combo_box name="ComboBoxSaleType">
-		<combo_box.item label="Копировать" name="Copy"/>
-		<combo_box.item label="Содержимое" name="Contents"/>
-		<combo_box.item label="Оригинал" name="Original"/>
-	</combo_box>
-	<spinner label="Цена:" name="Edit Cost"/>
-	<text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/ru/panel_main_inventory.xml b/indra/newview/skins/default/xui/ru/panel_main_inventory.xml
index f2502bf6d3a94739ebd50089d0d084296ab07c19..b473fb8f9826c0c900077ab6cb0d11ceb0dacffe 100644
--- a/indra/newview/skins/default/xui/ru/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/ru/panel_main_inventory.xml
@@ -9,6 +9,7 @@
 	<panel.string name="ItemcountUnknown">
 		Выборка [ITEM_COUNT] предметов и [CATEGORY_COUNT] папок [FILTER]
 	</panel.string>
+    <panel.string name="inventory_title">ИНВЕНТАРЬ</panel.string>
 	<text name="ItemcountText">
 		Вещи:
 	</text>
diff --git a/indra/newview/skins/default/xui/tr/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/tr/floater_inventory_item_properties.xml
deleted file mode 100644
index c6a5515c6edf253fa3be3b7375bf5e923d813446..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/tr/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="ENVANTER ÖGESİ ÖZELLİKLERİ">
-	<floater.string name="unknown">(bilinmiyor)</floater.string>
-	<floater.string name="public">(kamuya açık)</floater.string>
-	<floater.string name="you_can">Åžunu yapabilirsiniz:</floater.string>
-	<floater.string name="owner_can">Sahip ÅŸunu yapabilir:</floater.string>
-	<floater.string name="acquiredDate">[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]</floater.string>
-	<text name="LabelItemNameTitle">Ad:</text>
-	<text name="LabelItemDescTitle">Açıklama:</text>
-	<text name="LabelCreatorTitle">OluÅŸturan:</text>
-	<button label="Profil..." name="BtnCreator"/>
-	<text name="LabelOwnerTitle">Sahip:</text>
-	<button label="Profil..." name="BtnOwner"/>
-	<text name="LabelAcquiredTitle">Alınan:</text>
-	<text name="LabelAcquiredDate">24 Mayıs Çarş 12:50:46 2006</text>
-	<text name="OwnerLabel">Siz:</text>
-	<check_box label="Düzenle" name="CheckOwnerModify"/>
-	<check_box label="Kopyala" name="CheckOwnerCopy"/>
-	<check_box label="Tekrar Sat" name="CheckOwnerTransfer"/>
-	<text name="AnyoneLabel">Herkes:</text>
-	<check_box label="Kopyala" name="CheckEveryoneCopy"/>
-	<text name="GroupLabel">Grup:</text>
-	<check_box label="PaylaÅŸ" name="CheckShareWithGroup"/>
-	<text name="NextOwnerLabel">Sonraki sahip:</text>
-	<check_box label="Düzenle" name="CheckNextOwnerModify"/>
-	<check_box label="Kopyala" name="CheckNextOwnerCopy"/>
-	<check_box label="Tekrar Sat" name="CheckNextOwnerTransfer"/>
-	<check_box label="Satılık" name="CheckPurchase"/>
-	<combo_box name="ComboBoxSaleType">
-		<combo_box.item label="Kopyala" name="Copy"/>
-		<combo_box.item label="İçerik" name="Contents"/>
-		<combo_box.item label="Orijinal" name="Original"/>
-	</combo_box>
-	<spinner label="Fiyat:" name="Edit Cost"/>
-	<text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/tr/panel_main_inventory.xml b/indra/newview/skins/default/xui/tr/panel_main_inventory.xml
index a11fd98b9a3b71e2f092dbf6958ce217d914405a..7e980786354df4f16d73c54000704aa193606497 100644
--- a/indra/newview/skins/default/xui/tr/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/tr/panel_main_inventory.xml
@@ -9,6 +9,7 @@
 	<panel.string name="ItemcountUnknown">
 		[ITEM_COUNT] Öğe ve [CATEGORY_COUNT] Klasör Alındı [FILTER]
 	</panel.string>
+    <panel.string name="inventory_title">ENVANTER</panel.string>
 	<text name="ItemcountText">
 		Ögeler:
 	</text>
diff --git a/indra/newview/skins/default/xui/zh/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/zh/floater_inventory_item_properties.xml
deleted file mode 100644
index 4f17b96579c87f9156088f17422a542e43b96948..0000000000000000000000000000000000000000
--- a/indra/newview/skins/default/xui/zh/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="收納區物品屬性">
-	<floater.string name="unknown">(未知)</floater.string>
-	<floater.string name="public">(公開)</floater.string>
-	<floater.string name="you_can">你可以:</floater.string>
-	<floater.string name="owner_can">所有人可以:</floater.string>
-	<floater.string name="acquiredDate">[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]</floater.string>
-	<text name="LabelItemNameTitle">名稱:</text>
-	<text name="LabelItemDescTitle">描述:</text>
-	<text name="LabelCreatorTitle">創造者:</text>
-	<button label="檔案..." name="BtnCreator"/>
-	<text name="LabelOwnerTitle">所有人:</text>
-	<button label="檔案..." name="BtnOwner"/>
-	<text name="LabelAcquiredTitle">取得於:</text>
-	<text name="LabelAcquiredDate">Wed May 24 12:50:46 2006</text>
-	<text name="OwnerLabel">你:</text>
-	<check_box label="編輯" name="CheckOwnerModify"/>
-	<check_box label="恚庨" name="CheckOwnerCopy"/>
-	<check_box label="轉售" name="CheckOwnerTransfer"/>
-	<text name="AnyoneLabel">任何人:</text>
-	<check_box label="恚庨" name="CheckEveryoneCopy"/>
-	<text name="GroupLabel">群組:</text>
-	<check_box label="分享" name="CheckShareWithGroup"/>
-	<text name="NextOwnerLabel">下一個所有人:</text>
-	<check_box label="編輯" name="CheckNextOwnerModify"/>
-	<check_box label="恚庨" name="CheckNextOwnerCopy"/>
-	<check_box label="轉售" name="CheckNextOwnerTransfer"/>
-	<check_box label="出售" name="CheckPurchase"/>
-	<combo_box name="ComboBoxSaleType">
-		<combo_box.item label="複製" name="Copy"/>
-		<combo_box.item label="內容" name="Contents"/>
-		<combo_box.item label="原件" name="Original"/>
-	</combo_box>
-	<spinner label="價格:" name="Edit Cost"/>
-	<text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/zh/panel_main_inventory.xml b/indra/newview/skins/default/xui/zh/panel_main_inventory.xml
index 1a28f4c3b5cf0ecff51da10867abb24a2686f7a1..9ffa9323cc55c80592a7df5305e84c39e479464b 100644
--- a/indra/newview/skins/default/xui/zh/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/zh/panel_main_inventory.xml
@@ -9,6 +9,7 @@
 	<panel.string name="ItemcountUnknown">
 		擷取了[ITEM_COUNT]個物項及[CATEGORY_COUNT]個資料夾[FILTER]
 	</panel.string>
+    <panel.string name="inventory_title">收納區</panel.string>
 	<text name="ItemcountText">
 		物品:
 	</text>