From 56a7ba61f631924e36c779f7efcabfd755c4beb2 Mon Sep 17 00:00:00 2001
From: Armin Weatherwax
Date: Tue, 10 Jan 2012 22:39:31 +0100
Subject: New inventory categrory capability code - needs testing.

* Original code from: https://bitbucket.org/lindenlab/viewer-development/changeset/d327dcc8ae51
* Port by Henri Beauchamp: https://lists.secondlife.com/pipermail/opensource-dev/2012-January/008544.html
* 3 Lines of debug by /me (find the Hippos -remove after testing)
---
 linden/indra/newview/llfloateropenobject.cpp |  76 +++++++++++++++-----
 linden/indra/newview/llfloateropenobject.h   |  15 ++++
 linden/indra/newview/llinventorybridge.cpp   |  18 +++--
 linden/indra/newview/llinventorymodel.cpp    | 103 ++++++++++++++++++++++++++-
 linden/indra/newview/llinventorymodel.h      |   8 ++-
 linden/indra/newview/llviewerregion.cpp      |   1 +
 6 files changed, 192 insertions(+), 29 deletions(-)

(limited to 'linden/indra')

diff --git a/linden/indra/newview/llfloateropenobject.cpp b/linden/indra/newview/llfloateropenobject.cpp
index fc483dd..4190c3e 100644
--- a/linden/indra/newview/llfloateropenobject.cpp
+++ b/linden/indra/newview/llfloateropenobject.cpp
@@ -155,29 +155,71 @@ void LLFloaterOpenObject::moveToInventory(bool wear)
 	{
 		parent_category_id = gAgent.getInventoryRootID();
 	}
+
+	LLCategoryCreate* cat_data = new LLCategoryCreate(object_id, wear);
 	LLUUID category_id = gInventory.createNewCategory(parent_category_id, 
-		LLAssetType::AT_NONE, 
-		name);
-
-	LLCatAndWear* data = new LLCatAndWear;
-	data->mCatID = category_id;
-	data->mWear = wear;
-
-	// 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;
+ 		LLAssetType::AT_NONE,
+													  name,
+													  callbackCreateInventoryCategory,
+													  (void*)cat_data);
+
 
-		LLNotifications::instance().add("OpenObjectCannotCopy");
+	// 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())
+	{
+		delete cat_data;
+
+		LLCatAndWear* data = new LLCatAndWear;
+		data->mCatID = category_id;
+		data->mWear = wear;
+		data->mFolderResponded = false;
+
+		// 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;
+	
+			LLNotifications::instance().add("OpenObjectCannotCopy");
+		}
 	}
 }
 
 // static
+void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLSD& result, void* data)
+{
+	LLCategoryCreate* cat_data = (LLCategoryCreate*)data;
+
+	LLUUID category_id = result["folder_id"].asUUID();
+	LLCatAndWear* wear_data = new LLCatAndWear;
+
+	wear_data->mCatID = category_id;
+	wear_data->mWear = cat_data->mWear;
+	wear_data->mFolderResponded = true;
+
+ 	// 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(cat_data->mObjectID, category_id, TRUE,
+ 													callbackMoveInventory, 
+													(void*)wear_data);
+ 	if (!success)
+ 	{
+		delete wear_data;
+		wear_data = NULL;
+
+ 		LLNotifications::instance().add("OpenObjectCannotCopy");
+ 	}
+	delete cat_data;	
+ }
+
+// static
 void LLFloaterOpenObject::callbackMoveInventory(S32 result, void* data)
 {
 	LLCatAndWear* cat = (LLCatAndWear*)data;
diff --git a/linden/indra/newview/llfloateropenobject.h b/linden/indra/newview/llfloateropenobject.h
index 27653a5..4b89158 100644
--- a/linden/indra/newview/llfloateropenobject.h
+++ b/linden/indra/newview/llfloateropenobject.h
@@ -50,10 +50,24 @@ public:
 	static void show();
 	static void dirty();
 	
+	class LLCategoryCreate
+	{
+		public:
+			LLCategoryCreate(LLUUID object_id, bool wear)
+			:	mObjectID(object_id),
+				mWear(wear)
+			{}
+
+		public:
+			LLUUID mObjectID;
+			bool mWear;
+	};
+
 	struct LLCatAndWear
 	{
 		LLUUID mCatID;
 		bool mWear;
+		bool mFolderResponded;
 	};
 
 protected:
@@ -67,6 +81,7 @@ protected:
 
 	static void onClickMoveToInventory(void* data);
 	static void onClickMoveAndWear(void* data);
+	static void callbackCreateInventoryCategory(const LLSD& result, void* data);
 	static void callbackMoveInventory(S32 result, void* data);
 	static void* createPanelInventory(void* data);
 
diff --git a/linden/indra/newview/llinventorybridge.cpp b/linden/indra/newview/llinventorybridge.cpp
index f71df2d..bd08773 100644
--- a/linden/indra/newview/llinventorybridge.cpp
+++ b/linden/indra/newview/llinventorybridge.cpp
@@ -1610,18 +1610,21 @@ void LLRightClickInventoryFetchDescendentsObserver::done()
 class LLInventoryCopyAndWearObserver : public LLInventoryObserver
 {
 public:
-	LLInventoryCopyAndWearObserver(const LLUUID& cat_id, int count) :mCatID(cat_id), mContentsCount(count), mFolderAdded(FALSE) {}
+	LLInventoryCopyAndWearObserver(const LLUUID& cat_id,
+								   int count,
+								   bool folder_added = false)
+	:	mCatID(cat_id),
+		mContentsCount(count),
+		mFolderAdded(FALSE) {}
 	virtual ~LLInventoryCopyAndWearObserver() {}
 	virtual void changed(U32 mask);
 
 protected:
 	LLUUID mCatID;
 	int    mContentsCount;
-	BOOL   mFolderAdded;
+	bool   mFolderAdded;
 };
 
-
-
 void LLInventoryCopyAndWearObserver::changed(U32 mask)
 {
 	if((mask & (LLInventoryObserver::ADD)) != 0)
@@ -2331,13 +2334,16 @@ bool move_task_inventory_callback(const LLSD& notification, const LLSD& response
 
 	if(option == 0 && object)
 	{
-		if (cat_and_wear && cat_and_wear->mWear)
+		if (cat_and_wear && cat_and_wear->mWear) // && !cat_and_wear->mFolderResponded)
 		{
 			InventoryObjectList inventory_objects;
 			object->getInventoryContents(inventory_objects);
 			int contents_count = inventory_objects.size()-1; //subtract one for containing folder
 
-			LLInventoryCopyAndWearObserver* inventoryObserver = new LLInventoryCopyAndWearObserver(cat_and_wear->mCatID, contents_count);
+			LLInventoryCopyAndWearObserver* inventoryObserver;
+			inventoryObserver = new LLInventoryCopyAndWearObserver(cat_and_wear->mCatID,
+																   contents_count,
+																   cat_and_wear->mFolderResponded);
 			gInventory.addObserver(inventoryObserver);
 		}
 
diff --git a/linden/indra/newview/llinventorymodel.cpp b/linden/indra/newview/llinventorymodel.cpp
index 58a2bdc..0200ed0 100644
--- a/linden/indra/newview/llinventorymodel.cpp
+++ b/linden/indra/newview/llinventorymodel.cpp
@@ -396,13 +396,63 @@ LLUUID LLInventoryModel::findCategoryByName(std::string name)
 	return LLUUID::null;
 }
 
+class LLCreateInventoryCategoryResponder : public LLHTTPClient::Responder
+{
+public:
+	LLCreateInventoryCategoryResponder(LLInventoryModel* model, 
+									   void (*callback)(const LLSD&, void*),
+									   void* user_data)
+	:	mModel(model),
+		mCallback(callback), 
+		mData(user_data) 
+	{
+	}
+
+	virtual void error(U32 status, const std::string& reason)
+	{
+		llwarns << "CreateInventoryCategory failed. status = " << status
+				<< ", reason = \"" << reason << "\"" << llendl;
+	}
+
+	virtual void result(const LLSD& content)
+	{
+		// Server has created folder.
+
+		LLUUID category_id = content["folder_id"].asUUID();
+
+		// Add the category to the internal representation
+		LLPointer<LLViewerInventoryCategory> cat;
+		cat = new LLViewerInventoryCategory(category_id,
+											content["parent_id"].asUUID(),
+											(LLAssetType::EType)content["type"].asInteger(),
+											content["name"].asString(), 
+											gAgent.getID());
+		cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL);
+		cat->setDescendentCount(0);
+		LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1);
+		mModel->accountForUpdate(update);
+		mModel->updateCategory(cat);
+
+		if (mCallback && mData)
+		{
+			mCallback(content, mData);
+		}
+	}
+
+private:
+	void (*mCallback)(const LLSD&, void*);
+	void* mData;
+	LLInventoryModel* mModel;
+};
+
 // 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,
-										   LLAssetType::EType preferred_type,
-										   const std::string& pname)
+ 										   LLAssetType::EType preferred_type,										   const std::string& pname,
+										   void (*callback)(const LLSD&, void*),
+										   void* user_data)
 {
 	LLUUID id;
 	if(!isInventoryUsable())
@@ -433,6 +483,53 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
 		name.assign(NEW_CATEGORY_NAME);
 	}
 
+	if (callback && user_data)  // callback required for acked message.
+	{
+
+
+		LLViewerRegion* viewer_region = gAgent.getRegion();
+		if (!viewer_region->capabilitiesReceived())//awfixme
+		{
+			LL_DEBUGS("Inventory") << "HIPPOS! not capabilitiesReceived()"   << LL_ENDL;
+		}
+		std::string url;
+		if (viewer_region)
+		{
+			url = viewer_region->getCapability("CreateInventoryCategory");
+		}
+
+		if (!url.empty())
+		{
+			LL_DEBUGS("Inventory") << "Using the CreateInventoryCategory capability."   << LL_ENDL;
+			// Let's use the new capability.
+			LLSD request, body;
+			body["folder_id"] = id;
+			body["parent_id"] = parent_id;
+			body["type"] = (LLSD::Integer) preferred_type;
+			body["name"] = name;
+
+			request["message"] = "CreateInventoryCategory";
+			request["payload"] = body;
+
+			LLHTTPClient::post(url, body,
+							   new LLCreateInventoryCategoryResponder(this,
+																	  callback,
+																	  user_data));
+			return LLUUID::null;
+		}
+		else//awfixme
+		{
+			LL_DEBUGS("Inventory") << "HIPPOS! cap url empty"   << LL_ENDL;
+		}
+	}
+	else//awfixme
+	{
+		LL_DEBUGS("Inventory") << "HIPPOS! callback: "
+				<< (callback ? "true" : "false")
+				<< "user_data"  << ((NULL!= user_data) ? "!NULL" : "NULL")
+				<< LL_ENDL;
+	}
+
 	// Add the category to the internal representation
 	LLPointer<LLViewerInventoryCategory> cat =
 		new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID());
@@ -3173,7 +3270,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 		//		<< titem->getParentUUID() << llendl;
 		U32 callback_id;
 		msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id);
-		if(titem->getUUID().notNull())
+		if (titem->getUUID().notNull()) // && callback_id.notNull())
 		{
 			items.push_back(titem);
 			cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID()));
diff --git a/linden/indra/newview/llinventorymodel.h b/linden/indra/newview/llinventorymodel.h
index 7222c60..7788c34 100644
--- a/linden/indra/newview/llinventorymodel.h
+++ b/linden/indra/newview/llinventorymodel.h
@@ -308,9 +308,11 @@ public:
 	// based on preferred type. 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,
-							 LLAssetType::EType preferred_type,
-							 const std::string& name);
+ 	LLUUID createNewCategory(const LLUUID& parent_id,
+ 							 LLAssetType::EType preferred_type,
+							 const std::string& name,
+							 void (*callback)(const LLSD&, void*) = NULL,
+							 void* user_data = NULL);
 
 	LLUUID findCategoryByName(std::string name);
 
diff --git a/linden/indra/newview/llviewerregion.cpp b/linden/indra/newview/llviewerregion.cpp
index a43e0c0..2fafe30 100644
--- a/linden/indra/newview/llviewerregion.cpp
+++ b/linden/indra/newview/llviewerregion.cpp
@@ -1428,6 +1428,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	LLSD capabilityNames = LLSD::emptyArray();
 	capabilityNames.append("ChatSessionRequest");
 	capabilityNames.append("CopyInventoryFromNotecard");
+	capabilityNames.append("CreateInventoryCategory");
 	// Aurora settings -- MC
 	capabilityNames.append("DispatchOpenRegionSettings");
 	capabilityNames.append("DispatchRegionInfo");
-- 
cgit v1.1