TOptional<EItemDropZone> FSequencerFolderNode::CanDrop( FSequencerDisplayNodeDragDropOp& DragDropOp, EItemDropZone ItemDropZone ) const
{
	DragDropOp.ResetToDefaultToolTip();

	if ( ItemDropZone == EItemDropZone::AboveItem )
	{
		if ( GetParent().IsValid() )
		{
			// When dropping above, only allow it for root level nodes.
			return TOptional<EItemDropZone>();
		}
		else
		{
			// Make sure there are no folder name collisions with the root folders
			UMovieScene* FocusedMovieScene = GetParentTree().GetSequencer().GetFocusedMovieSceneSequence()->GetMovieScene();
			TSet<FName> RootFolderNames;
			for ( UMovieSceneFolder* RootFolder : FocusedMovieScene->GetRootFolders() )
			{
				RootFolderNames.Add( RootFolder->GetFolderName() );
			}

			for ( TSharedRef<FSequencerDisplayNode> DraggedNode : DragDropOp.GetDraggedNodes() )
			{
				if ( DraggedNode->GetType() == ESequencerNode::Folder )
				{
					TSharedRef<FSequencerFolderNode> DraggedFolder = StaticCastSharedRef<FSequencerFolderNode>( DraggedNode );
					if ( RootFolderNames.Contains( DraggedFolder->GetFolder().GetFolderName() ) )
					{
						DragDropOp.CurrentHoverText = FText::Format(
							NSLOCTEXT( "SeqeuencerFolderNode", "DuplicateRootFolderDragErrorFormat", "Root folder with name '{0}' already exists." ),
							FText::FromName( DraggedFolder->GetFolder().GetFolderName() ) );
						return TOptional<EItemDropZone>();
					}
				}
			}
		}
		return TOptional<EItemDropZone>( EItemDropZone::AboveItem );
	}
	else
	{
		// When dropping onto, don't allow dropping into the same folder, don't allow dropping
		// parents into children, and don't allow duplicate folder names.
		TSet<FName> ChildFolderNames;
		for ( UMovieSceneFolder* ChildFolder : GetFolder().GetChildFolders() )
		{
			ChildFolderNames.Add( ChildFolder->GetFolderName() );
		}

		for ( TSharedRef<FSequencerDisplayNode> DraggedNode : DragDropOp.GetDraggedNodes() )
		{
			TSharedPtr<FSequencerDisplayNode> ParentSeqNode = DraggedNode->GetParent();
			if ( ParentSeqNode.IsValid() && ParentSeqNode.Get() == this )
			{
				DragDropOp.CurrentHoverText = NSLOCTEXT( "SeqeuencerFolderNode", "SameParentDragError", "Can't drag a node onto the same parent." );
				return TOptional<EItemDropZone>();
			}

			if ( DraggedNode->GetType() == ESequencerNode::Folder )
			{
				TSharedRef<FSequencerFolderNode> DraggedFolder = StaticCastSharedRef<FSequencerFolderNode>( DraggedNode );
				if ( ChildFolderNames.Contains( DraggedFolder->GetFolder().GetFolderName() ) )
				{
					DragDropOp.CurrentHoverText = FText::Format(
						NSLOCTEXT( "SeqeuencerFolderNode", "DuplicateChildFolderDragErrorFormat", "Folder with name '{0}' already exists." ),
						FText::FromName( DraggedFolder->GetFolder().GetFolderName() ) );
					return TOptional<EItemDropZone>();
				}
			}
		}
		TSharedPtr<FSequencerDisplayNode> CurrentNode = SharedThis( ( FSequencerDisplayNode* )this );
		while ( CurrentNode.IsValid() )
		{
			if ( DragDropOp.GetDraggedNodes().Contains( CurrentNode ) )
			{
				DragDropOp.CurrentHoverText = NSLOCTEXT( "SeqeuencerFolderNode", "ParentIntoChildDragError", "Can't drag a parent node into one of it's children." );
				return TOptional<EItemDropZone>();
			}
			CurrentNode = CurrentNode->GetParent();
		}
		return TOptional<EItemDropZone>( EItemDropZone::OntoItem );
	}
}
void FSequencerFolderNode::Drop( const TArray<TSharedRef<FSequencerDisplayNode>>& DraggedNodes, EItemDropZone ItemDropZone )
{
	const FScopedTransaction Transaction( NSLOCTEXT( "SequencerFolderNode", "MoveIntoFolder", "Move items into folder." ) );
	GetFolder().SetFlags(RF_Transactional);
	GetFolder().Modify();
	for ( TSharedRef<FSequencerDisplayNode> DraggedNode : DraggedNodes )
	{
		TSharedPtr<FSequencerDisplayNode> ParentSeqNode = DraggedNode->GetParent();
		switch ( DraggedNode->GetType() )
		{
			case ESequencerNode::Folder:
			{
				TSharedRef<FSequencerFolderNode> DraggedFolderNode = StaticCastSharedRef<FSequencerFolderNode>( DraggedNode );
				UMovieScene* FocusedMovieScene = GetParentTree().GetSequencer().GetFocusedMovieSceneSequence()->GetMovieScene();

				if ( ItemDropZone == EItemDropZone::OntoItem )
				{
					GetFolder().AddChildFolder( &DraggedFolderNode->GetFolder() );
				}
				else
				{
					FocusedMovieScene->Modify();
					FocusedMovieScene->GetRootFolders().Add( &DraggedFolderNode->GetFolder() );
				}
				
				if ( ParentSeqNode.IsValid() )
				{
					checkf( ParentSeqNode->GetType() == ESequencerNode::Folder, TEXT( "Can not remove from unsupported parent node." ) );
					TSharedPtr<FSequencerFolderNode> ParentFolder = StaticCastSharedPtr<FSequencerFolderNode>( ParentSeqNode );
					ParentFolder->GetFolder().Modify();
					ParentFolder->GetFolder().RemoveChildFolder( &DraggedFolderNode->GetFolder() );
				}
				else
				{
					FocusedMovieScene->Modify();
					FocusedMovieScene->GetRootFolders().Remove( &DraggedFolderNode->GetFolder() );
				}

				break;
			}
			case ESequencerNode::Track:
			{
				TSharedRef<FSequencerTrackNode> DraggedTrackNode = StaticCastSharedRef<FSequencerTrackNode>( DraggedNode );
				
				if( ItemDropZone == EItemDropZone::OntoItem )
				{
					GetFolder().AddChildMasterTrack( DraggedTrackNode->GetTrack() );
				}
				
				if ( ParentSeqNode.IsValid() )
				{
					checkf( ParentSeqNode->GetType() == ESequencerNode::Folder, TEXT( "Can not remove from unsupported parent node." ) );
					TSharedPtr<FSequencerFolderNode> ParentFolder = StaticCastSharedPtr<FSequencerFolderNode>( ParentSeqNode );
					ParentFolder->GetFolder().Modify();
					ParentFolder->GetFolder().RemoveChildMasterTrack( DraggedTrackNode->GetTrack() );
				}

				break;
			}
			case ESequencerNode::Object:
			{
				TSharedRef<FSequencerObjectBindingNode> DraggedObjectBindingNode = StaticCastSharedRef<FSequencerObjectBindingNode>( DraggedNode );
				
				if ( ItemDropZone == EItemDropZone::OntoItem )
				{
					GetFolder().AddChildObjectBinding( DraggedObjectBindingNode->GetObjectBinding() );
				}

				if ( ParentSeqNode.IsValid() )
				{
					checkf( ParentSeqNode->GetType() == ESequencerNode::Folder, TEXT( "Can not remove from unsupported parent node." ) );
					TSharedPtr<FSequencerFolderNode> ParentFolder = StaticCastSharedPtr<FSequencerFolderNode>( ParentSeqNode );
					ParentFolder->GetFolder().Modify();
					ParentFolder->GetFolder().RemoveChildObjectBinding( DraggedObjectBindingNode->GetObjectBinding() );
				}

				break;
			}
		}
	}
	SetExpansionState( true );
	ParentTree.GetSequencer().NotifyMovieSceneDataChanged( EMovieSceneDataChangeType::MovieSceneStructureItemsChanged );
}