From 5e5105bd223f5180bbca634ba2c393be2ef3d13d Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Fri, 13 Jan 2012 18:37:50 -0800
Subject: EXP-1770 WIP Drag and drop visual selection can be off across
 hierarchies added throttling to fetchInventoryItem queries

---
 indra/newview/llfolderviewitem.cpp                |  11 +-
 indra/newview/llinventorybridge.cpp               |   2 +-
 indra/newview/llinventorymodelbackgroundfetch.cpp | 328 +++++++++++++++-------
 indra/newview/llinventorymodelbackgroundfetch.h   |  16 +-
 4 files changed, 237 insertions(+), 120 deletions(-)

diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp
index ca7e4bc1d0..50d62b29d3 100644
--- a/indra/newview/llfolderviewitem.cpp
+++ b/indra/newview/llfolderviewitem.cpp
@@ -499,7 +499,7 @@ BOOL LLFolderViewItem::setSelection(LLFolderViewItem* selection, BOOL openitem,
 
 BOOL LLFolderViewItem::changeSelection(LLFolderViewItem* selection, BOOL selected)
 {
-	if (selection == this && mIsSelected != selected)
+	if (selection == this)
 	{
 		if (mIsSelected)
 		{
@@ -521,11 +521,14 @@ void LLFolderViewItem::deselectItem(void)
 
 void LLFolderViewItem::selectItem(void)
 {
-	if (mListener)
+	if (mIsSelected == FALSE)
 	{
-		mListener->selectItem();
+		if (mListener)
+		{
+			mListener->selectItem();
+		}
+		mIsSelected = TRUE;
 	}
-	mIsSelected = TRUE;
 }
 
 BOOL LLFolderViewItem::isMovable()
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index eaf9b53eb9..5916ed60a4 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -1234,7 +1234,7 @@ void LLItemBridge::selectItem()
 	LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem());
 	if(item && !item->isFinished())
 	{
-		item->fetchFromServer();
+		LLInventoryModelBackgroundFetch::instance().start(item->getUUID(), false);
 	}
 }
 
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index 91fdd67806..5f0c744192 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -50,7 +50,7 @@ LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() :
 	mMinTimeBetweenFetches(0.3f),
 	mMaxTimeBetweenFetches(10.f),
 	mTimelyFetchPending(FALSE),
-	mBulkFetchCount(0)
+	mFetchCount(0)
 {
 }
 
@@ -60,7 +60,7 @@ LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch()
 
 bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() const
 {
-	return mFetchQueue.empty() && mBulkFetchCount<=0;
+	return mFetchQueue.empty() && mFetchCount<=0;
 }
 
 bool LLInventoryModelBackgroundFetch::libraryFetchStarted() const
@@ -103,44 +103,60 @@ BOOL LLInventoryModelBackgroundFetch::backgroundFetchActive() const
 	return mBackgroundFetchActive;
 }
 
-void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id, BOOL recursive)
+void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
 {
-	if (!mAllFoldersFetched || cat_id.notNull())
-	{
-		LL_DEBUGS("InventoryFetch") << "Start fetching category: " << cat_id << ", recursive: " << recursive << LL_ENDL;
+	if (id.isNull()) return;
 
-		mBackgroundFetchActive = TRUE;
-		if (cat_id.isNull())
+	LLViewerInventoryCategory* cat = gInventory.getCategory(id);
+	if (cat)
+	{	// it's a folder, do a bulk fetch
+		if (!mAllFoldersFetched)
 		{
-			if (!mRecursiveInventoryFetchStarted)
+			LL_DEBUGS("InventoryFetch") << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL;
+
+			mBackgroundFetchActive = TRUE;
+			if (id.isNull())
 			{
-				mRecursiveInventoryFetchStarted |= recursive;
-				mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive));
-				gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+				if (!mRecursiveInventoryFetchStarted)
+				{
+					mRecursiveInventoryFetchStarted |= recursive;
+					mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive));
+					gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+				}
+				if (!mRecursiveLibraryFetchStarted)
+				{
+					mRecursiveLibraryFetchStarted |= recursive;
+					mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive));
+					gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+				}
 			}
-			if (!mRecursiveLibraryFetchStarted)
+			else
 			{
-				mRecursiveLibraryFetchStarted |= recursive;
-				mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive));
-				gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+				// 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 (id == gInventory.getLibraryRootFolderID())
+				{
+					mRecursiveLibraryFetchStarted |= recursive;
+				}
+				if (id == gInventory.getRootFolderID())
+				{
+					mRecursiveInventoryFetchStarted |= recursive;
+				}
 			}
 		}
-		else
+	}
+	else if (LLViewerInventoryItem* itemp = gInventory.getItem(id))
+	{
+		if (!itemp->mIsComplete && (mFetchQueue.empty() || mFetchQueue.front().mUUID != id))
 		{
-			// Specific folder requests go to front of queue.
-			if (mFetchQueue.empty() || mFetchQueue.front().mCatUUID != cat_id)
-			{
-				mFetchQueue.push_front(FetchQueueInfo(cat_id, recursive));
-				gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
-			}
-			if (cat_id == gInventory.getLibraryRootFolderID())
-			{
-				mRecursiveLibraryFetchStarted |= recursive;
-			}
-			if (cat_id == gInventory.getRootFolderID())
-			{
-				mRecursiveInventoryFetchStarted |= recursive;
-			}
+			mBackgroundFetchActive = TRUE;
+
+			mFetchQueue.push_front(FetchQueueInfo(id, false, false));
+			gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
 		}
 	}
 }
@@ -158,7 +174,7 @@ void LLInventoryModelBackgroundFetch::stopBackgroundFetch()
 	{
 		mBackgroundFetchActive = FALSE;
 		gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
-		mBulkFetchCount=0;
+		mFetchCount=0;
 		mMinTimeBetweenFetches=0.0f;
 	}
 }
@@ -183,10 +199,9 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
 	if (mBackgroundFetchActive && gAgent.getRegion())
 	{
 		// If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
-		std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2");   
-		if (gSavedSettings.getBOOL("UseHTTPInventory") && !url.empty()) 
+		if (gSavedSettings.getBOOL("UseHTTPInventory")) 
 		{
-			bulkFetch(url);
+			bulkFetch();
 			return;
 		}
 		
@@ -230,7 +245,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
 			}
 
 			const FetchQueueInfo info = mFetchQueue.front();
-			LLViewerInventoryCategory* cat = gInventory.getCategory(info.mCatUUID);
+			LLViewerInventoryCategory* cat = gInventory.getCategory(info.mUUID);
 
 			// Category has been deleted, remove from queue.
 			if (!cat)
@@ -258,7 +273,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
 				}
 			}
 			// Do I have all my children?
-			else if (gInventory.isCategoryComplete(info.mCatUUID))
+			else if (gInventory.isCategoryComplete(info.mUUID))
 			{
 				// Finished with this category, remove from queue.
 				mFetchQueue.pop_front();
@@ -313,15 +328,35 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
 	}
 }
 
-void LLInventoryModelBackgroundFetch::incrBulkFetch(S16 fetching) 
+void LLInventoryModelBackgroundFetch::incrFetchCount(S16 fetching) 
 {  
-	mBulkFetchCount += fetching; 
-	if (mBulkFetchCount < 0)
+	mFetchCount += fetching; 
+	if (mFetchCount < 0)
 	{
-		mBulkFetchCount = 0; 
+		mFetchCount = 0; 
 	}
 }
 
+class LLInventoryModelFetchItemResponder : public LLInventoryModel::fetchInventoryResponder
+{
+public:
+	LLInventoryModelFetchItemResponder(const LLSD& request_sd) : LLInventoryModel::fetchInventoryResponder(request_sd) {};
+	void result(const LLSD& content);			
+	void error(U32 status, const std::string& reason);
+};
+
+void LLInventoryModelFetchItemResponder::result( const LLSD& content )
+{
+	LLInventoryModel::fetchInventoryResponder::result(content);
+	LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
+}
+
+void LLInventoryModelFetchItemResponder::error( U32 status, const std::string& reason )
+{
+	LLInventoryModel::fetchInventoryResponder::error(status, reason);
+	LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
+}
+
 
 class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder
 {
@@ -458,7 +493,7 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
 		}
 	}
 
-	fetcher->incrBulkFetch(-1);
+	fetcher->incrFetchCount(-1);
 	
 	if (fetcher->isBulkFetchProcessingComplete())
 	{
@@ -477,7 +512,7 @@ void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::str
 	llinfos << "LLInventoryModelFetchDescendentsResponder::error "
 		<< status << ": " << reason << llendl;
 						
-	fetcher->incrBulkFetch(-1);
+	fetcher->incrFetchCount(-1);
 
 	if (status==499) // timed out
 	{
@@ -508,12 +543,14 @@ BOOL LLInventoryModelFetchDescendentsResponder::getIsRecursive(const LLUUID& cat
 
 // Bundle up a bunch of requests to send all at once.
 // static   
-void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)
+void LLInventoryModelBackgroundFetch::bulkFetch()
 {
 	//Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
 	//If there are items in mFetchQueue, we want to check the time since the last bulkFetch was 
 	//sent.  If it exceeds our retry time, go ahead and fire off another batch.  
 	//Stopbackgroundfetch will be run from the Responder instead of here.  
+	LLViewerRegion* region = gAgent.getRegion();
+	if (!region) return;
 
 	S16 max_concurrent_fetches=8;
 	F32 new_min_time = 0.5f;			//HACK!  Clean this up when old code goes away entirely.
@@ -523,12 +560,13 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)
 	}
 	
 	if (gDisconnected ||
-		(mBulkFetchCount > max_concurrent_fetches) ||
+		(mFetchCount > max_concurrent_fetches) ||
 		(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))
 	{
 		return; // just bail if we are disconnected
 	}	
 
+	U32 item_count=0;
 	U32 folder_count=0;
 	U32 max_batch_size=5;
 
@@ -536,83 +574,159 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)
 
 	uuid_vec_t recursive_cats;
 
-	LLSD body;
-	LLSD body_lib;
+	LLSD folder_request_body;
+	LLSD folder_request_body_lib;
+	LLSD item_request_body;
+	LLSD item_request_body_lib;
 
-	while (!(mFetchQueue.empty()) && (folder_count < max_batch_size))
+	while (!(mFetchQueue.empty()) && ((item_count + folder_count) < max_batch_size))
 	{
 		const FetchQueueInfo& fetch_info = mFetchQueue.front();
-		const LLUUID &cat_id = fetch_info.mCatUUID;
-        if (cat_id.isNull()) //DEV-17797
-        {
-			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;
-			body["folders"].append(folder_sd);
-            folder_count++;
-        }
-        else
-        {
-		    const LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+		if (fetch_info.mIsCategory)
+		{
+
+			const LLUUID &cat_id = fetch_info.mUUID;
+			if (cat_id.isNull()) //DEV-17797
+			{
+				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_request_body["folders"].append(folder_sd);
+				folder_count++;
+			}
+			else
+			{
+				const LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
 		
-		    if (cat)
-		    {
-			    if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
-			    {
-				    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"]	= TRUE; //(LLSD::Boolean)sFullFetchStarted;
-				    folder_sd["fetch_items"]	= (LLSD::Boolean)TRUE;
-				    
-				    if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
-					    body_lib["folders"].append(folder_sd);
-				    else
-					    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;
-					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)
+				if (cat)
+				{
+					if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
 					{
-						mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive));
-				    }
-			    }
-		    }
-        }
-		if (fetch_info.mRecursive)
-			recursive_cats.push_back(cat_id);
+						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"]	= TRUE; //(LLSD::Boolean)sFullFetchStarted;
+						folder_sd["fetch_items"]	= (LLSD::Boolean)TRUE;
+				    
+						if (ALEXANDRIA_LINDEN_ID == 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;
+						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(), fetch_info.mRecursive));
+						}
+					}
+				}
+			}
+			if (fetch_info.mRecursive)
+				recursive_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++;
+			}
+		}
 
 		mFetchQueue.pop_front();
 	}
 		
-	if (folder_count > 0)
+	if (item_count + folder_count > 0)
 	{
-		mBulkFetchCount++;
-		if (body["folders"].size())
+		if (folder_count)
 		{
-			LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body, recursive_cats);
-			LLHTTPClient::post(url, body, fetcher, 300.0);
+			std::string url = region->getCapability("FetchInventoryDescendents2");   
+			mFetchCount++;
+			if (folder_request_body["folders"].size())
+			{
+				LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats);
+				LLHTTPClient::post(url, folder_request_body, fetcher, 300.0);
+			}
+			if (folder_request_body_lib["folders"].size())
+			{
+				std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2");
+
+				LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats);
+				LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0);
+			}
 		}
-		if (body_lib["folders"].size())
+		if (item_count)
 		{
-			std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2");
-			
-			LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body_lib, recursive_cats);
-			LLHTTPClient::post(url_lib, body_lib, fetcher, 300.0);
+			std::string url;
+
+			if (item_request_body.size())
+			{
+				mFetchCount++;
+				url = region->getCapability("FetchInventory2");
+				if (!url.empty())
+				{
+					LLSD body;
+					body["agent_id"]	= gAgent.getID();
+					body["items"] = item_request_body;
+
+					LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body));
+				}
+				//else
+				//{
+				//	LLMessageSystem* msg = gMessageSystem;
+				//	msg->newMessage("FetchInventory");
+				//	msg->nextBlock("AgentData");
+				//	msg->addUUID("AgentID", gAgent.getID());
+				//	msg->addUUID("SessionID", gAgent.getSessionID());
+				//	msg->nextBlock("InventoryData");
+				//	msg->addUUID("OwnerID", mPermissions.getOwner());
+				//	msg->addUUID("ItemID", mUUID);
+				//	gAgent.sendReliableMessage();
+				//}
+			}
+
+			if (item_request_body_lib.size())
+			{
+				mFetchCount++;
+
+				url = region->getCapability("FetchLib2");
+				if (!url.empty())
+				{
+					LLSD body;
+					body["agent_id"]	= gAgent.getID();
+					body["items"] = item_request_body_lib;
+
+					LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body));
+				}
+			}
 		}
 		mFetchTimer.reset();
 	}
+
 	else if (isBulkFetchProcessingComplete())
 	{
 		setAllFoldersFetched();
@@ -624,7 +738,7 @@ bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LL
 	for (fetch_queue_t::const_iterator it = mFetchQueue.begin();
 		 it != mFetchQueue.end(); ++it)
 	{
-		const LLUUID& fetch_id = (*it).mCatUUID;
+		const LLUUID& fetch_id = (*it).mUUID;
 		if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
 			return false;
 	}
diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h
index c35c785ceb..0745407a8c 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.h
+++ b/indra/newview/llinventorymodelbackgroundfetch.h
@@ -60,10 +60,10 @@ public:
 	bool inventoryFetchInProgress() const;
 
     void findLostItems();	
+	void incrFetchCount(S16 fetching);
 protected:
-	void incrBulkFetch(S16 fetching);
 	bool isBulkFetchProcessingComplete() const;
-	void bulkFetch(std::string url);
+	void bulkFetch();
 
 	void backgroundFetch();
 	static void backgroundFetchCB(void*); // background fetch idle function
@@ -77,7 +77,7 @@ private:
 	BOOL mAllFoldersFetched;
 
 	BOOL mBackgroundFetchActive;
-	S16 mBulkFetchCount;
+	S16 mFetchCount;
 	BOOL mTimelyFetchPending;
 	S32 mNumFetchRetries;
 
@@ -87,11 +87,11 @@ private:
 
 	struct FetchQueueInfo
 	{
-		FetchQueueInfo(const LLUUID& id, BOOL recursive) :
-			mCatUUID(id), mRecursive(recursive)
-		{
-		}
-		LLUUID mCatUUID;
+		FetchQueueInfo(const LLUUID& id, BOOL recursive, bool is_category = true) :
+			mUUID(id), mRecursive(recursive), mIsCategory(is_category)
+		{}
+		LLUUID mUUID;
+		bool mIsCategory;
 		BOOL mRecursive;
 	};
 	typedef std::deque<FetchQueueInfo> fetch_queue_t;
-- 
cgit v1.2.3