From 3282c5ff73176cb9fe8a8be6a372790516237448 Mon Sep 17 00:00:00 2001
From: Michelle2 Zenovka
Date: Sat, 20 Sep 2008 13:16:14 -0500
Subject: VWR-5082: 'Set permissions on selected task inventory' feature.

---
 linden/indra/newview/llfloaterbulkpermission.cpp   | 595 +++++++++++++++++++++
 linden/indra/newview/llfloaterbulkpermission.h     | 143 +++++
 linden/indra/newview/llviewermenu.cpp              |  13 +
 .../skins/default/xui/en-us/floater_bulk_perms.xml | 127 +++++
 .../skins/default/xui/en-us/menu_viewer.xml        |   5 +
 5 files changed, 883 insertions(+)
 create mode 100644 linden/indra/newview/llfloaterbulkpermission.cpp
 create mode 100644 linden/indra/newview/llfloaterbulkpermission.h
 create mode 100644 linden/indra/newview/skins/default/xui/en-us/floater_bulk_perms.xml

(limited to 'linden')

diff --git a/linden/indra/newview/llfloaterbulkpermission.cpp b/linden/indra/newview/llfloaterbulkpermission.cpp
new file mode 100644
index 0000000..29d94bc
--- /dev/null
+++ b/linden/indra/newview/llfloaterbulkpermission.cpp
@@ -0,0 +1,595 @@
+/** 
+ * @file llfloaterbulkpermissions.cpp
+ * @brief A floater which allows task inventory item's properties to be changed on mass.
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+/* Allow multiple task inventory properties to be set in one go, by Michelle2 Zenovka */
+
+/* TODO
+	
+	* Add in the option to select objects or task inventory
+s
+
+It would be nice to set the permissions on groups of prims as well as task inventory
+
+*/
+
+
+#include "llviewerprecompiledheaders.h"
+#include "llfloaterbulkpermission.h"
+#include "llagent.h"
+#include "llchat.h"
+#include "llviewerwindow.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "lscript_rt_interface.h"
+#include "llviewercontrol.h"
+#include "llviewerobject.h"
+#include "llviewerregion.h"
+#include "llresmgr.h"
+#include "llbutton.h"
+#include "lldir.h"
+#include "llfloaterchat.h"
+#include "llviewerstats.h"
+#include "lluictrlfactory.h"
+#include "llselectmgr.h"
+#include "llinventory.h"
+
+
+#include <algorithm>
+#include <functional>
+#include "llcachename.h"
+#include "lldbstrings.h"
+#include "llinventory.h"
+
+#include "llagent.h"
+#include "llbutton.h"
+#include "llcheckboxctrl.h"
+#include "llfloateravatarinfo.h"
+#include "llfloatergroupinfo.h"
+#include "llinventorymodel.h"
+#include "lllineeditor.h"
+#include "llradiogroup.h"
+#include "llresmgr.h"
+#include "roles_constants.h"
+#include "llselectmgr.h"
+#include "lltextbox.h"
+#include "lluiconstants.h"
+#include "llviewerinventory.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llviewercontrol.h"
+
+#include "lluictrlfactory.h"
+
+
+const char* BULKPERM_QUEUE_TITLE = "Update Progress";
+const char* BULKPERM_START_STRING = "update";
+
+namespace
+{
+	struct BulkQueueObjects : public LLSelectedObjectFunctor
+	{
+		BOOL scripted;
+		BOOL modifiable;
+		LLFloaterBulkPermission* mQueue;
+		BulkQueueObjects(LLFloaterBulkPermission* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {}
+		virtual bool apply(LLViewerObject* obj)
+		{
+			scripted = obj->flagScripted();
+			modifiable = obj->permModify();
+
+			mQueue->addObject(obj->getID());
+			return false;
+			
+		}
+	};
+}
+
+///----------------------------------------------------------------------------
+/// Class LLFloaterBulkPermission
+///----------------------------------------------------------------------------
+
+// static
+LLMap<LLUUID, LLFloaterBulkPermission*> LLFloaterBulkPermission::sInstances;
+
+
+// Default constructor
+LLFloaterBulkPermission::LLFloaterBulkPermission(const std::string& name,
+											 const LLRect& rect,
+											 const char* title,
+											 const char* start_string) :
+	LLFloater(name, rect, title,
+			  RESIZE_YES, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT,
+			  DRAG_ON_TOP, MINIMIZE_YES, CLOSE_YES)
+{
+
+	req_perm_mask=0; // This should match the default state the checkboxes are set to
+	recurse=false;
+
+	LLUICtrlFactory::getInstance()->buildFloater(this,"floater_bulk_perms.xml");
+
+	childSetAction("Apply...",onApplyBtn,this);
+	childSetEnabled("Apply...",TRUE);
+
+	childSetCommitCallback("Modify",&onCommitPermissions, this);
+	childSetCommitCallback("Trans",&onCommitPermissions, this);
+	childSetCommitCallback("Copy",&onCommitPermissions, this);
+
+	//childSetCommitCallback("Recurse",&onRecurse, this);
+
+	childSetCommitCallback("Parent",&onParent, this);
+
+	childSetCommitCallback("objects",&InvSelection, this);
+	childSetCommitCallback("scripts",&InvSelection, this);
+	childSetCommitCallback("textures",&InvSelection, this);
+	childSetCommitCallback("sounds",&InvSelection, this);
+	childSetCommitCallback("animations",&InvSelection, this);
+	childSetCommitCallback("notecards",&InvSelection, this);
+	childSetCommitCallback("landmarks",&InvSelection, this);
+	childSetCommitCallback("bodyparts",&InvSelection, this);
+	childSetCommitCallback("clothing",&InvSelection, this);
+	childSetCommitCallback("gestures",&InvSelection, this);
+
+	//Set variable state to XUI default state consistancy
+	processObject=getChild<LLCheckBoxCtrl>("objects")->get();
+	processScript=getChild<LLCheckBoxCtrl>("scripts")->get();
+	processTexture=getChild<LLCheckBoxCtrl>("textures")->get();
+	processSound=getChild<LLCheckBoxCtrl>("sounds")->get();
+	processAnimation=getChild<LLCheckBoxCtrl>("animations")->get();
+	processNotecard=getChild<LLCheckBoxCtrl>("notecards")->get();
+	processGesture=getChild<LLCheckBoxCtrl>("gestures")->get();
+	processClothing=getChild<LLCheckBoxCtrl>("clothing")->get();
+	processBodypart=getChild<LLCheckBoxCtrl>("bodyparts")->get();
+	processLandmark=getChild<LLCheckBoxCtrl>("landmarks")->get();
+	parent=getChild<LLCheckBoxCtrl>("Parent")->get();
+
+
+	setTitle(title);
+	
+	if (!getHost())
+	{
+		LLRect curRect = getRect();
+		translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop);
+	}
+	
+	mStartString = start_string;
+	mDone = FALSE;
+	sInstances.addData(mID, this);
+
+}
+
+void LLFloaterBulkPermission::doApply()
+{
+	// Its alive now do the nasty work that the ScriptQueue and friends try to do in the menu code
+	// but first grab the user options
+
+	LLScrollListCtrl* list = getChild<LLScrollListCtrl>("queue output");
+	list->deleteAllItems();
+
+	//Apply to selected objects if requested first
+
+	if(parent)
+	{
+		llinfos<< "Setting permission on parent items" << llendl;
+		LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_NEXT_OWNER,true, req_perm_mask);
+		LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_NEXT_OWNER,false, ~req_perm_mask); //How annoying need to set and unset
+	}
+
+
+	LLFloaterBulkPermission* q;
+	q=(LLFloaterBulkPermission*)this;
+
+	BulkQueueObjects func(q);
+	const bool firstonly = false;
+	bool fail = LLSelectMgr::getInstance()->getSelection()->applyToObjects(&func, firstonly);
+	if(fail)
+	{
+		if ( !func.modifiable )
+		{
+			gViewerWindow->alertXml("NO MODIFY");
+		}
+		else
+		{
+			llwarns << "Bad logic. Are there actualy any items in that prim?" << llendl;
+		}
+	}
+	else
+	{
+		if (!q->start())
+		{
+			llwarns << "Unexpected failure attepmting to set permissions." << llendl;
+		}
+	}
+}
+
+// Destroys the object
+LLFloaterBulkPermission::~LLFloaterBulkPermission()
+{
+	sInstances.removeData(mID);
+}
+
+// find an instance by ID. Return NULL if it does not exist.
+// static
+LLFloaterBulkPermission* LLFloaterBulkPermission::findInstance(const LLUUID& id)
+{
+	if(sInstances.checkData(id))
+	{
+		return sInstances.getData(id);
+	}
+	return NULL;
+}
+
+
+// This is the callback method for the viewer object currently being
+// worked on.
+// NOT static, virtual!
+void LLFloaterBulkPermission::inventoryChanged(LLViewerObject* viewer_object,
+											 InventoryObjectList* inv,
+											 S32,
+											 void* q_id)
+{
+	llinfos << "LLFloaterBulkPermission::inventoryChanged() for  object "
+			<< viewer_object->getID() << llendl;
+
+	//Remove this listener from the object since its
+	//listener callback is now being executed.
+	
+	//We remove the listener here because the function
+	//removeVOInventoryListener removes the listener from a ViewerObject
+	//which it internally stores.
+	
+	//If we call this further down in the function, calls to handleInventory
+	//and nextObject may update the interally stored viewer object causing
+	//the removal of the incorrect listener from an incorrect object.
+	
+	//Fixes SL-6119:Recompile scripts fails to complete
+	removeVOInventoryListener();
+
+	if (viewer_object && inv && (viewer_object->getID() == mCurrentObjectID) )
+	{
+		handleInventory(viewer_object, inv);
+	}
+	else
+	{
+		// something went wrong...
+		// note that we're not working on this one, and move onto the
+		// next object in the list.
+		llwarns << "No inventory for " << mCurrentObjectID
+				<< llendl;
+		nextObject();
+	}
+}
+
+void LLFloaterBulkPermission::onApplyBtn(void* user_data)
+{
+	LLFloaterBulkPermission* self = (LLFloaterBulkPermission*)user_data;
+	self->doApply();
+}
+
+
+// static
+void LLFloaterBulkPermission::InvSelection(LLUICtrl* ctrl, void* data)
+{
+	LLFloaterBulkPermission* self = (LLFloaterBulkPermission*)data;
+
+	self->processObject=self->getChild<LLCheckBoxCtrl>("objects")->get();
+	self->processScript=self->getChild<LLCheckBoxCtrl>("scripts")->get();
+	self->processTexture=self->getChild<LLCheckBoxCtrl>("textures")->get();
+	self->processSound=self->getChild<LLCheckBoxCtrl>("sounds")->get();
+	self->processAnimation=self->getChild<LLCheckBoxCtrl>("animations")->get();
+	self->processNotecard=self->getChild<LLCheckBoxCtrl>("notecards")->get();
+	self->processGesture=self->getChild<LLCheckBoxCtrl>("gestures")->get();
+	self->processClothing=self->getChild<LLCheckBoxCtrl>("clothing")->get();
+	self->processBodypart=self->getChild<LLCheckBoxCtrl>("bodyparts")->get();
+	self->processLandmark=self->getChild<LLCheckBoxCtrl>("landmarks")->get();
+
+
+}
+
+// static
+void LLFloaterBulkPermission::onParent(LLUICtrl* ctrl, void* data)
+{
+	LLFloaterBulkPermission* self = (LLFloaterBulkPermission*)data;
+	self->parent=self->getChild<LLCheckBoxCtrl>("Parent")->get();
+}
+
+// static
+void LLFloaterBulkPermission::onRecurse(LLUICtrl* ctrl, void* data)
+{
+	LLFloaterBulkPermission* self = (LLFloaterBulkPermission*)data;
+	self->recurse=self->getChild<LLCheckBoxCtrl>("Recurse")->get();
+}
+
+// static
+void LLFloaterBulkPermission::onCommitPermissions(LLUICtrl* ctrl, void* data)
+{
+	LLFloaterBulkPermission* self = (LLFloaterBulkPermission*)data;
+	LLCheckBoxCtrl* CheckModify = self->getChild<LLCheckBoxCtrl>("Modify");
+	LLCheckBoxCtrl* CheckCopy = self->getChild<LLCheckBoxCtrl>("Copy");
+	LLCheckBoxCtrl* CheckTrans = self->getChild<LLCheckBoxCtrl>("Trans");
+
+	self->req_perm_mask=0;
+
+	if(CheckModify->get())
+	{
+		self->req_perm_mask|=PERM_MODIFY;
+	}
+	else
+	{
+		self->req_perm_mask&=~PERM_MODIFY;
+	}
+
+	if(CheckCopy->get())
+	{
+		self->req_perm_mask|=PERM_COPY;
+	}
+	else
+	{
+		self->req_perm_mask&=~PERM_COPY;
+	}
+
+	if(CheckTrans->get())
+	{
+		self->req_perm_mask|=PERM_TRANSFER;
+	}
+	else
+	{
+		self->req_perm_mask&=~PERM_TRANSFER;
+	}
+
+
+}
+
+void LLFloaterBulkPermission::addObject(const LLUUID& id)
+{
+	mObjectIDs.put(id);
+}
+
+BOOL LLFloaterBulkPermission::start()
+{
+	llinfos << "LLFloaterBulkPermission::start()" << llendl;
+	char buffer[MAX_STRING]; 				/*Flawfinder: ignore*/
+	snprintf(buffer, sizeof(buffer), "Starting %s of %d items.", mStartString, mObjectIDs.count()); 		/* Flawfinder: ignore */
+
+	LLScrollListCtrl* list = getChild<LLScrollListCtrl>("queue output");
+	list->addCommentText(buffer);
+
+	return nextObject();
+}
+
+BOOL LLFloaterBulkPermission::isDone() const
+{
+	return (mCurrentObjectID.isNull() || (mObjectIDs.count() == 0));
+}
+
+// go to the next object. If no objects left, it falls out silently
+// and waits to be killed by the window being closed.
+BOOL LLFloaterBulkPermission::nextObject()
+{
+	S32 count;
+	BOOL successful_start = FALSE;
+	do
+	{
+		count = mObjectIDs.count();
+		llinfos << "LLFloaterBulkPermission::nextObject() - " << count
+				<< " objects left to process." << llendl;
+		mCurrentObjectID.setNull();
+		if(count > 0)
+		{
+			successful_start = popNext();
+		}
+		llinfos << "LLFloaterBulkPermission::nextObject() "
+				<< (successful_start ? "successful" : "unsuccessful")
+				<< llendl; 
+	} while((mObjectIDs.count() > 0) && !successful_start);
+
+	if(isDone() && !mDone)
+	{
+		
+		LLScrollListCtrl* list = getChild<LLScrollListCtrl>("queue output");
+		mDone = TRUE;
+		char buffer[MAX_STRING];		/*Flawfinder: ignore*/
+		snprintf(buffer, sizeof(buffer), "Done.");				/* Flawfinder: ignore */
+		list->addCommentText(buffer);
+
+	}
+	return successful_start;
+}
+
+// returns true if the queue has started, otherwise false.  This
+// method pops the top object off of the queue.
+BOOL LLFloaterBulkPermission::popNext()
+{
+	// get the first element off of the container, and attempt to get
+	// the inventory.
+	BOOL rv = FALSE;
+	S32 count = mObjectIDs.count();
+	if(mCurrentObjectID.isNull() && (count > 0))
+	{
+		mCurrentObjectID = mObjectIDs.get(0);
+		llinfos << "LLFloaterBulkPermission::popNext() - mCurrentID: "
+				<< mCurrentObjectID << llendl;
+		mObjectIDs.remove(0);
+		LLViewerObject* obj = gObjectList.findObject(mCurrentObjectID);
+		if(obj)
+		{
+			llinfos << "LLFloaterBulkPermission::popNext() requesting inv for "
+					<< mCurrentObjectID << llendl;
+			LLUUID* id = new LLUUID(mID);
+
+			registerVOInventoryListener(obj,id);
+			requestVOInventory();
+			rv = TRUE;
+		}
+		else
+		{
+			llinfos<<"LLFloaterBulkPermission::popNext() returned a NULL LLViewerObject" <<llendl;
+			//Arrrg what do we do here?
+		}
+	}
+
+	return rv;
+}
+
+
+// static
+LLFloaterBulkPermission* LLFloaterBulkPermission::create()
+{
+	S32 left, top;
+	gFloaterView->getNewFloaterPosition(&left, &top);
+	LLRect rect = gSavedSettings.getRect("CompileOutputRect");
+	rect.translate(left - rect.mLeft, top - rect.mTop);
+	LLFloaterBulkPermission* new_queue = new LLFloaterBulkPermission("queue",rect,"Setting Bulk permissions","Results");
+	new_queue->open();	 /*Flawfinder: ignore*/
+	return new_queue;
+}
+
+
+void LLFloaterBulkPermission::handleInventory(LLViewerObject* viewer_obj, InventoryObjectList* inv)
+{
+	// find all of the lsl, leaving off duplicates. We'll remove
+	// all matching asset uuids on compilation success.
+
+	llinfos<<"handleInventory"<<llendl;
+
+	char buffer[MAX_STRING];		 /*Flawfinder: ignore*/
+	LLScrollListCtrl* list = getChild<LLScrollListCtrl>("queue output");
+
+	InventoryObjectList::const_iterator it = inv->begin();
+	InventoryObjectList::const_iterator end = inv->end();
+	for ( ; it != end; ++it)
+	{
+		llinfos<<"Doing iterator of inventory"<<llendl;
+
+		if(  ( (*it)->getType() == LLAssetType::AT_LSL_TEXT && processScript) ||
+  		     ( (*it)->getType() == LLAssetType::AT_TEXTURE && processTexture) ||
+	             ( (*it)->getType() == LLAssetType::AT_SOUND && processSound) ||
+	             ( (*it)->getType() == LLAssetType::AT_LANDMARK && processLandmark) ||
+    		     ( (*it)->getType() == LLAssetType::AT_CLOTHING && processClothing) ||
+    		     ( (*it)->getType() == LLAssetType::AT_OBJECT && processObject) ||
+   		     ( (*it)->getType() == LLAssetType::AT_NOTECARD && processNotecard) ||
+   		     ( (*it)->getType() == LLAssetType::AT_BODYPART && processBodypart) ||
+   		     ( (*it)->getType() == LLAssetType::AT_ANIMATION && processAnimation) ||
+   		     ( (*it)->getType() == LLAssetType::AT_GESTURE && processGesture))
+		{
+
+			LLViewerObject* object = gObjectList.findObject(viewer_obj->getID());
+
+			if (object)
+			{
+				LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it));
+				LLViewerInventoryItem* new_item = (LLViewerInventoryItem*)item;
+				LLPermissions perm(new_item->getPermissions());
+
+				// chomp the inventory name so it fits in the scroll window nicely
+				// and the user can see the [OK]
+				std::string invname;
+				invname=item->getName().substr(0,item->getName().size() < 30 ? item->getName().size() : 30 );
+				
+				// My attempt at checking valid permissions, CHECK ME
+				// note its not actually bad to try to set permissions that are not allowed as the
+				// server will protect against this, but it will piss the user off if its wrong
+				if(
+				(perm.getCreator()==gAgentID) ||
+				(perm.getMaskOwner() & PERM_TRANSFER) && (perm.getMaskOwner() & PERM_MODIFY) || 
+				(gAgent.getGroupID()==perm.getGroup() && (perm.getMaskGroup() & PERM_TRANSFER) && (perm.getMaskGroup() & PERM_MODIFY))
+				){	
+					llinfos<<"Setting perms"<<llendl;
+					perm.setMaskNext(req_perm_mask);
+					new_item->setPermissions(perm);
+					updateInventory(object,new_item,TASK_INVENTORY_ITEM_KEY,FALSE);				
+					snprintf(buffer, sizeof(buffer), "Setting perms on '%s' [OK]", invname.c_str());		 	/* Flawfinder: ignore */
+				}
+				else
+				{
+					llinfos<<"NOT setting perms"<<llendl;
+					snprintf(buffer, sizeof(buffer), "Setting perms on '%s' [FAILED]", invname.c_str());		 	/* Flawfinder: ignore */
+
+				}
+				
+				list->addCommentText(buffer);
+
+				if(recurse &&  ( (*it)->getType() == LLAssetType::AT_OBJECT && processObject))
+				{
+					//Add this object back to the queue to be processed as it has inventory
+					snprintf(buffer, sizeof(buffer), "Queueing object '%s' for open", invname.c_str());
+					llwarns << "Queueing object "<<	invname.c_str() << " ID "<< (*it)->getUUID()<<llendl;
+					mObjectIDs.put((*it)->getUUID());
+					// This will not YET work. as this is not a viewer object the unpack will fail			
+				}
+
+			}
+		}
+	}
+
+	nextObject();	
+}
+
+
+// Avoid inventory callbacks etc by just fire and forgetting the message with the permissions update
+// we could do this via LLViewerObject::updateInventory but that uses inventory call backs and buggers
+// us up and we would have a dodgy item iterator
+
+void LLFloaterBulkPermission::updateInventory(
+	LLViewerObject* object,
+	LLViewerInventoryItem* item,
+	U8 key,
+	bool is_new)
+{
+	LLMemType mt(LLMemType::MTYPE_OBJECT);
+	
+
+	// This slices the object into what we're concerned about on the
+	// viewer. The simulator will take the permissions and transfer
+	// ownership.
+	LLPointer<LLViewerInventoryItem> task_item =
+		new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(),
+								  item->getAssetUUID(), item->getType(),
+								  item->getInventoryType(),
+								  item->getName(), item->getDescription(),
+								  item->getSaleInfo(),
+								  item->getFlags(),
+								  item->getCreationDate());
+	task_item->setTransactionID(item->getTransactionID());
+	LLMessageSystem* msg = gMessageSystem;
+	msg->newMessageFast(_PREHASH_UpdateTaskInventory);
+	msg->nextBlockFast(_PREHASH_AgentData);
+	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+	msg->nextBlockFast(_PREHASH_UpdateData);
+	msg->addU32Fast(_PREHASH_LocalID, object->mLocalID);
+	msg->addU8Fast(_PREHASH_Key, key);
+	msg->nextBlockFast(_PREHASH_InventoryData);
+	task_item->packMessage(msg);
+	msg->sendReliable(object->getRegion()->getHost());
+
+}
+
diff --git a/linden/indra/newview/llfloaterbulkpermission.h b/linden/indra/newview/llfloaterbulkpermission.h
new file mode 100644
index 0000000..3de871b
--- /dev/null
+++ b/linden/indra/newview/llfloaterbulkpermission.h
@@ -0,0 +1,143 @@
+/** 
+ * @file llfloaterbulkpermissions.h
+ * @brief A floater which allows task inventory item's properties to be changed on mass.
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+/* Allow multiple task inventory properties to be set in one go, by Michelle2 Zenovka */
+
+#ifndef LL_LLBULKPERMISSION_H
+#define LL_LLBULKPERMISSION_H
+
+#include "lldarray.h"
+#include "llinventory.h"
+#include "llviewerobject.h"
+#include "llvoinventorylistener.h"
+#include "llmap.h"
+#include "lluuid.h"
+
+#include "llfloater.h"
+#include "llscrolllistctrl.h"
+
+#include "llviewerinventory.h"
+
+class LLFloaterBulkPermission : public LLFloater, public LLVOInventoryListener
+{
+public:
+	// addObject() accepts an object id.
+	void addObject(const LLUUID& id);
+
+	// start() returns TRUE if the queue has started, otherwise FALSE.
+	BOOL start();
+
+	// Use this method to create a reset queue. Once created, it
+	// will be responsible for it's own destruction.
+	static LLFloaterBulkPermission * create();
+
+protected:
+	LLFloaterBulkPermission(const std::string& name, const LLRect& rect,
+						 const char* title, const char* start_string);
+	virtual ~LLFloaterBulkPermission();
+
+	// This is the callback method for the viewer object currently
+	// being worked on.
+	/*virtual*/ void inventoryChanged(LLViewerObject* obj,
+								 InventoryObjectList* inv,
+								 S32 serial_num,
+								 void* queue);
+	
+	// This is called by inventoryChanged
+	void handleInventory(LLViewerObject* viewer_obj,
+								InventoryObjectList* inv);
+
+
+	void updateInventory(LLViewerObject* object,
+								LLViewerInventoryItem* item,
+								U8 key,
+								bool is_new);
+
+
+	static void onCloseBtn(void* user_data);
+	static void onApplyBtn(void* user_data);
+	static void onCommitPermissions(LLUICtrl* ctrl, void* data);
+	static void InvSelection(LLUICtrl* ctrl, void* data);
+	static void onRecurse(LLUICtrl* ctrl, void* data);	
+	static void onParent(LLUICtrl* ctrl, void* data);
+
+	// returns true if this is done
+	BOOL isDone() const;
+
+	//Read the settings and Apply the permissions
+	void doApply();
+
+	// go to the next object. If no objects left, it falls out
+	// silently and waits to be killed by the deleteIfDone() callback.
+	BOOL nextObject();
+	BOOL popNext();
+
+	// Get this instances ID.
+	const LLUUID& getID() const { return mID; } 
+
+	// find an instance by ID. Return NULL if it does not exist.
+	static LLFloaterBulkPermission* findInstance(const LLUUID& id);
+
+	U32 req_perm_mask;
+
+	BOOL processObject;
+	BOOL processScript;
+	BOOL processTexture;
+	BOOL processSound;
+	BOOL processAnimation;
+	BOOL processCallingcard;
+	BOOL processNotecard;
+	BOOL processGesture;
+	BOOL processClothing;
+	BOOL processBodypart;
+	BOOL processLandmark;
+
+	BOOL recurse;
+	BOOL parent;
+
+protected:
+	// UI
+	LLScrollListCtrl* mMessages;
+	LLButton* mCloseBtn;
+
+	// Object Queue
+	LLDynamicArray<LLUUID> mObjectIDs;
+	LLUUID mCurrentObjectID;
+	BOOL mDone;
+
+	LLUUID mID;
+	static LLMap<LLUUID, LLFloaterBulkPermission*> sInstances;
+
+	const char* mStartString;
+
+};
+
+#endif
diff --git a/linden/indra/newview/llviewermenu.cpp b/linden/indra/newview/llviewermenu.cpp
index 3e99384..1ec71ac 100644
--- a/linden/indra/newview/llviewermenu.cpp
+++ b/linden/indra/newview/llviewermenu.cpp
@@ -86,6 +86,7 @@
 #include "llfloateravatarinfo.h"
 #include "llfloateravatartextures.h"
 #include "llfloaterbuildoptions.h"
+#include "llfloaterbulkpermission.h"
 #include "llfloaterbump.h"
 #include "llfloaterbuy.h"
 #include "llfloaterbuycontents.h"
@@ -6239,6 +6240,17 @@ void queue_actions(LLFloaterScriptQueue* q, const std::string& noscriptmsg, cons
 	}
 }
 
+class LLToolsSetBulkPerms : public view_listener_t
+{
+	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
+	{
+		LLFloaterBulkPermission* queue = NULL;
+		queue = LLFloaterBulkPermission::create();
+		return true;
+	}
+};
+
+
 class LLToolsSelectedScriptAction : public view_listener_t
 {
 	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
@@ -7827,6 +7839,7 @@ void initialize_menus()
 	addMenu(new LLToolsSaveToInventory(), "Tools.SaveToInventory");
 	addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory");
 	addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction");
+	addMenu(new LLToolsSetBulkPerms(), "Tools.SetBulkPerms");
 
 	addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie");
 	addMenu(new LLToolsEnableLink(), "Tools.EnableLink");
diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_bulk_perms.xml b/linden/indra/newview/skins/default/xui/en-us/floater_bulk_perms.xml
new file mode 100644
index 0000000..3dd838a
--- /dev/null
+++ b/linden/indra/newview/skins/default/xui/en-us/floater_bulk_perms.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater bottom="-554" can_close="true" can_drag_on_left="false" can_minimize="true"
+     can_resize="false" can_tear_off="false" enabled="true" height="420"
+     left="367" min_height="1000" min_width="460" mouse_opaque="true"
+     name="floaterrecursiveperms" title="Bulk permission settings"
+     width="460">
+
+<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
+			     bottom="-40" drop_shadow_visible="true" enabled="true" follows="left|top"
+			     font="SansSerifSmall" h_pad="0" halign="left" height="10" left="10"
+			     mouse_opaque="true" name="applyto" v_pad="0" width="206">Apply to</text>
+
+<check_box bottom="-70" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Scripts" left="10" mouse_opaque="true"
+			     name="scripts" radio_style="false"
+			     tool_tip="Apply bulk permissions to scripts"
+			     width="219"/>
+
+<check_box bottom="-90" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Textures" left="10" mouse_opaque="true"
+			     name="textures" radio_style="false"
+			     tool_tip="Apply bulk permissions to textures"
+			     width="219"/>
+
+<check_box bottom="-110" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Animations" left="10" mouse_opaque="true"
+			     name="animations" radio_style="false"
+			     tool_tip="Apply bulk permissions to animations"
+			     width="219"/>
+
+<check_box bottom="-130" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Sounds" left="10" mouse_opaque="true"
+			     name="sounds" radio_style="false"
+			     tool_tip="Apply bulk permissions to sounds"
+			     width="219"/>
+
+<check_box bottom="-150" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Contained objects" left="10" mouse_opaque="true"
+			     name="objects" radio_style="false"
+			     tool_tip="Apply bulk permissions to objects inside inventory"
+			     width="219"/>
+
+<check_box bottom="-170" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Landmarks" left="10" mouse_opaque="true"
+			     name="landmarks" radio_style="false"
+			     tool_tip="Apply bulk permissions to landmarks"
+			     width="219"/>
+
+<check_box bottom="-190" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Notecards" left="10" mouse_opaque="true"
+			     name="notecards" radio_style="false"
+			     tool_tip="Apply bulk permissions to notecards"
+			     width="219"/>
+
+<check_box bottom="-210" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Gesture" left="10" mouse_opaque="true"
+			     name="gestures" radio_style="false"
+			     tool_tip="Apply bulk permissions to gestures"
+			     width="219"/>
+
+<check_box bottom="-230" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Clothing" left="10" mouse_opaque="true"
+			     name="clothing" radio_style="false"
+			     tool_tip="Apply bulk permissions to clothing"
+			     width="219"/>
+
+<check_box bottom="-250" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Bodypart" left="10" mouse_opaque="true"
+			     name="bodyparts" radio_style="false"
+			     tool_tip="Apply bulk permissions to bodyparts"
+			     width="219"/>
+
+<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
+			     bottom="-40" drop_shadow_visible="true" enabled="true" follows="left|top"
+			     font="SansSerifSmall" h_pad="0" halign="left" height="10" left="200"
+			     mouse_opaque="true" name="applyto" v_pad="0" width="206">Permissions</text>
+
+
+<check_box bottom="-110" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Copy" left="200" mouse_opaque="true"
+			     name="Copy" radio_style="false"
+			     tool_tip="Next owner can copy"
+			     width="219"/>
+
+<check_box bottom="-130" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Modify" left="200" mouse_opaque="true"
+			     name="Modify" radio_style="false"
+			     tool_tip="Next owner can modify"
+			     width="219"/>
+
+<check_box bottom="-150" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Trans" left="200" mouse_opaque="true"
+			     name="Trans" radio_style="false"
+			     tool_tip="Next owner can transfer"
+			     width="219"/>
+
+<check_box bottom="-230" enabled="true" follows="left|top" font="SansSerifSmall"
+			     height="16" initial_value="false"
+			     label="Modify Parent Prims" left="200" mouse_opaque="true"
+			     name="Parent" radio_style="false"
+			     tool_tip="Modify parent prims not just inventory"
+			     width="219" default="true"/>
+
+<scroll_list background_visible="true" bottom="-410" column_padding="5" draw_border="true"
+	     draw_heading="false" draw_stripes="true" enabled="true"
+	     follows="left|top|right|bottom" height="140" left="10" mouse_opaque="true"
+	     multi_select="false" name="queue output" width="440" />
+
+<button bottom="-70" enabled="true" follows="left|top" font="SansSerif"
+			     halign="center" height="20" label="Apply..."
+			     label_selected="Apply..." left="295" mouse_opaque="true"
+			     name="Apply..." scale_image="true" width="145" />
+
+</floater>
diff --git a/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml b/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml
index 054f867..eacd0ed 100644
--- a/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml
+++ b/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml
@@ -756,6 +756,11 @@
 			<on_click function="Tools.SelectedScriptAction" userdata="stop" />
 			<on_enable function="EditableSelected" />
 		</menu_item_call>
+		<menu_item_call bottom="-468" enabled="false" height="19" label="Set permissions on selected task inventory"
+		     left="0" mouse_opaque="true" name="Set permissions on selected task inventory" width="250">
+			<on_click function="Tools.SetBulkPerms" userdata="" />
+			<on_enable function="EditableSelected" />
+		</menu_item_call>
 	</menu>
 	<menu bottom="219" create_jump_keys="true" drop_shadow="true" enabled="true"
 	     height="317" label="Help" left="227" mouse_opaque="false" name="Help"
-- 
cgit v1.1