Seth ProductEngine avatar Seth ProductEngine committed ce58d5f

EXP-1335 FIXED Dragging folders into Recent Items disabled.
- Dragging folder into Recent Items disabled, but allowed within Recent Items.
- Dragging Contents folder from task inventory disabled.
- Filtering folder contents upon dragging to any inventory panel added, to make the behavior consistent with items filtering during DnD.

Comments (0)

Files changed (4)

indra/newview/llinventorybridge.cpp

 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 check_category(LLInventoryModel* model,
+						   const LLUUID& cat_id,
+						   LLFolderView* active_folder_view,
+						   LLInventoryFilter* filter);
+static bool check_item(const LLUUID& item_id,
+					   LLFolderView* active_folder_view,
+					   LLInventoryFilter* filter);
 
 // Helper functions
 
 	if (!isAgentAvatarValid()) return FALSE;
 	if (!isAgentInventory()) return FALSE; // cannot drag categories into library
 
+	LLInventoryPanel* destination_panel = mInventoryPanel.get();
+	if (!destination_panel) return false;
+
+	LLInventoryFilter* filter = destination_panel->getFilter();
+	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 &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
 			}
 		}
 
+		if (is_movable)
+		{
+			LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
+			is_movable = active_panel != NULL;
+
+			// For a folder to pass the filter all its descendants are required to pass.
+			// We make this exception to allow reordering folders within an inventory panel,
+			// which has a filter applied, like Recent tab for example.
+			// There may be folders which are displayed because some of their descendants pass
+			// the filter, but other don't, and thus remain hidden. Without this check,
+			// such folders would not be allowed to be moved within a panel.
+			if (destination_panel == active_panel)
+			{
+				is_movable = true;
+			}
+			else
+			{
+				LLFolderView* active_folder_view;
+
+				if (is_movable)
+				{
+					active_folder_view = active_panel->getRootFolder();
+					is_movable = active_folder_view != NULL;
+				}
+
+				if (is_movable)
+				{
+					// Check whether the folder being dragged from active inventory panel
+					// passes the filter of the destination panel.
+					is_movable = check_category(model, cat_id, active_folder_view, filter);
+				}
+			}
+		}
 		// 
 		//--------------------------------------------------------------------------------
 
 		}
 		else
 		{
-			accept = move_inv_category_world_to_agent(cat_id, mUUID, drop);
+			accept = move_inv_category_world_to_agent(cat_id, mUUID, drop, NULL, NULL, filter);
 		}
 	}
 	else if (LLToolDragAndDrop::SOURCE_LIBRARY == source)
 									  const LLUUID& category_id,
 									  BOOL drop,
 									  void (*callback)(S32, void*),
-									  void* user_data)
+									  void* user_data,
+									  LLInventoryFilter* filter)
 {
 	// Make sure the object exists. If we allowed dragging from
 	// anonymous objects, it would be possible to bypass
 		return FALSE;
 	}
 
-	BOOL accept = TRUE;
+	BOOL accept = FALSE;
 	BOOL is_move = FALSE;
 
 	// coming from a task. Need to figure out if the person can
 	LLInventoryObject::object_list_t::iterator end = inventory_objects.end();
 	for ( ; it != end; ++it)
 	{
+		LLInventoryItem* item = dynamic_cast<LLInventoryItem*>(it->get());
+		if (!item)
+		{
+			llwarns << "Invalid inventory item for drop" << llendl;
+			continue;
+		}
+
 		// coming from a task. Need to figure out if the person can
 		// move/copy this item.
-		LLPermissions perm(((LLInventoryItem*)((LLInventoryObject*)(*it)))->getPermissions());
+		LLPermissions perm(item->getPermissions());
 		if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID())
 			&& perm.allowTransferTo(gAgent.getID())))
 //			|| gAgent.isGodlike())
 			is_move = TRUE;
 			accept = TRUE;
 		}
-		else
-		{
-			accept = FALSE;
+
+		if (filter && accept)
+		{
+			accept = filter->check(item);
+		}
+
+		if (!accept)
+		{
 			break;
 		}
 	}
 		// passes the filter of the destination panel.
 		if (accept && active_panel)
 		{
-			LLFolderView* active_folder_viev = active_panel->getRootFolder();
-			if (!active_folder_viev) return false;
-
-			LLFolderViewItem* fv_item = active_folder_viev->getItemByID(inv_item->getUUID());
+			LLFolderView* active_folder_view = active_panel->getRootFolder();
+			if (!active_folder_view) return false;
+
+			LLFolderViewItem* fv_item = active_folder_view->getItemByID(inv_item->getUUID());
 			if (!fv_item) return false;
 
 			accept = filter->check(fv_item);
 			// passes the filter of the destination panel.
 			if (accept && active_panel)
 			{
-				LLFolderView* active_folder_viev = active_panel->getRootFolder();
-				if (!active_folder_viev) return false;
-
-				LLFolderViewItem* fv_item = active_folder_viev->getItemByID(inv_item->getUUID());
+				LLFolderView* active_folder_view = active_panel->getRootFolder();
+				if (!active_folder_view) return false;
+
+				LLFolderViewItem* fv_item = active_folder_view->getItemByID(inv_item->getUUID());
 				if (!fv_item) return false;
 
 				accept = filter->check(fv_item);
 	return accept;
 }
 
+// static
+bool check_category(LLInventoryModel* model,
+					const LLUUID& cat_id,
+					LLFolderView* active_folder_view,
+					LLInventoryFilter* filter)
+{
+	if (!model || !active_folder_view || !filter)
+		return false;
+
+	if (!filter->checkFolder(cat_id))
+	{
+		return false;
+	}
+
+	LLInventoryModel::cat_array_t descendent_categories;
+	LLInventoryModel::item_array_t descendent_items;
+	model->collectDescendents(cat_id, descendent_categories, descendent_items, TRUE);
+
+	S32 num_descendent_categories = descendent_categories.count();
+	S32 num_descendent_items = descendent_items.count();
+
+	if (num_descendent_categories + num_descendent_items == 0
+		&& filter->getShowFolderState() != LLInventoryFilter::SHOW_ALL_FOLDERS)
+	{
+		// Empty folders are not allowed if we are not showing all folders
+		return false;
+	}
+
+	for (S32 i = 0; i < num_descendent_categories; ++i)
+	{
+		LLInventoryCategory* category = descendent_categories[i];
+		if(!check_category(model, category->getUUID(), active_folder_view, filter))
+		{
+			return false;
+		}
+	}
+
+	for (S32 i = 0; i < num_descendent_items; ++i)
+	{
+		LLViewerInventoryItem* item = descendent_items[i];
+		if(!check_item(item->getUUID(), active_folder_view, filter))
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+// static
+bool check_item(const LLUUID& item_id,
+				LLFolderView* active_folder_view,
+				LLInventoryFilter* filter)
+{
+	if (!active_folder_view || !filter) return false;
+
+	LLFolderViewItem* fv_item = active_folder_view->getItemByID(item_id);
+	if (!fv_item) return false;
+
+	return filter->check(fv_item);
+}
+
 // +=================================================+
 // |        LLTextureBridge                          |
 // +=================================================+

indra/newview/llinventorybridge.h

 #include "llviewercontrol.h"
 #include "llwearable.h"
 
+class LLInventoryFilter;
 class LLInventoryPanel;
 class LLInventoryModel;
 class LLMenuGL;
 									  const LLUUID& category_id,
 									  BOOL drop,
 									  void (*callback)(S32, void*) = NULL,
-									  void* user_data = NULL);
+									  void* user_data = NULL,
+									  LLInventoryFilter* filter = NULL);
 
 // Utility function to hide all entries except those in the list
 // Can be called multiple times on the same menu (e.g. if multiple items

indra/newview/llinventoryfilter.cpp

 	return passed;
 }
 
-bool LLInventoryFilter::checkFolder(const LLFolderViewFolder* folder)
+bool LLInventoryFilter::checkFolder(const LLFolderViewFolder* folder) const
+{
+	if (!folder)
+	{
+		llwarns << "The filter can not be checked on an invalid folder." << llendl;
+		llassert(false); // crash in development builds
+		return false;
+	}
+
+	const LLFolderViewEventListener* listener = folder->getListener();
+	if (!listener)
+	{
+		llwarns << "Folder view event listener not found." << llendl;
+		llassert(false); // crash in development builds
+		return false;
+	}
+
+	const LLUUID folder_id = listener->getUUID();
+
+	return checkFolder(folder_id);
+}
+
+bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
 {
 	// we're showing all folders, overriding filter
 	if (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS)
 	{
 		return true;
 	}
-
-	const LLFolderViewEventListener* listener = folder->getListener();
-	const LLUUID folder_id = listener->getUUID();
 	
 	if (mFilterOps.mFilterTypes & FILTERTYPE_CATEGORY)
 	{

indra/newview/llinventoryfilter.h

 	// +-------------------------------------------------------------------+
 	BOOL 				check(const LLFolderViewItem* item);
 	bool				check(const LLInventoryItem* item);
-	bool				checkFolder(const LLFolderViewFolder* folder);
+	bool				checkFolder(const LLFolderViewFolder* folder) const;
+	bool				checkFolder(const LLUUID& folder_id) const;
 	BOOL 				checkAgainstFilterType(const LLFolderViewItem* item) const;
 	bool 				checkAgainstFilterType(const LLInventoryItem* item) const;
 	BOOL 				checkAgainstPermissions(const LLFolderViewItem* item) const;
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.