This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 184858 - Dragging a node from explorer calls both clipboardCut() and drag() on the dragged node
Summary: Dragging a node from explorer calls both clipboardCut() and drag() on the dra...
Status: RESOLVED WONTFIX
Alias: None
Product: platform
Classification: Unclassified
Component: Explorer (show other bugs)
Version: 6.x
Hardware: All All
: P4 normal (vote)
Assignee: Jaroslav Tulach
URL:
Keywords: PLATFORM
Depends on:
Blocks:
 
Reported: 2010-04-23 14:14 UTC by danoliv
Modified: 2013-01-17 14:57 UTC (History)
2 users (show)

See Also:
Issue Type: ENHANCEMENT
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description danoliv 2010-04-23 14:14:42 UTC
When a drag is done the explorer calls the function clipboardCut() and after the function drag() (that is mapped to clipboardCopy() as standard behavior).

This behavior give a problem: when we want to performe a cut on the node case we cannot remove the node from the Children in the clipboardCut() (as suggested in http://wiki.netbeans.org/DevFaqCutCopyPaste) because this will be done also done when a drag is performed.

So, a solution is to remove the node when is pasted in the getDropType function, but this will delay the cut after the paste operation.

Looking in the openide.explorer module source code I found a weird thing in the ExplorerDragSupport class:

// 3. get transferable and start the drag
try {
// for MOVE
Transferable transferable;

if ((possibleNodeAction & DnDConstants.ACTION_MOVE) != 0) {
// for MOVE
transferable = DragDropUtilities.getNodeTransferable(nodes, DnDConstants.ACTION_MOVE);
exDnD.setDraggedTransferable(transferable, true);

// for COPY too
transferable = DragDropUtilities.getNodeTransferable(nodes, DnDConstants.ACTION_COPY);
exDnD.setDraggedTransferable(transferable, false);
} else if ((possibleNodeAction & DnDConstants.ACTION_COPY) != 0) {
// for COPY
transferable = DragDropUtilities.getNodeTransferable(nodes, DnDConstants.ACTION_COPY);
exDnD.setDraggedTransferable(transferable, false);
} else {
// transferable for NONE
transferable = Node.EMPTY.drag();
exDnD.setDraggedTransferable(transferable, false);
}

exDnD.setDraggedNodes(nodes);

When we are performing a move is called first:
transferable = DragDropUtilities.getNodeTransferable(nodes, DnDConstants.ACTION_MOVE); that will cause a clipboardCut() in the node
and after that:
transferable = DragDropUtilities.getNodeTransferable(nodes, DnDConstants.ACTION_COPY); that will cause a clipboardCopy() in the node.

This double call give a lot of problems because the copy will be called after a cut, then will not give as the opportunity to know when a cut is called on a node what is causing that, a drag or a cut? do we can remove the node or not?
I just removed the first if and everythings works fine as I expect: clipboardCut will be called when a user is doing a cut, clipboardCopy when a copy is performed and drag when a drag is done.
Comment 1 Jaroslav Tulach 2010-04-23 16:51:20 UTC
I see. The behavior is unfortunate. However it will be tough to change it to be nice and remain compatible.
Comment 2 Jaroslav Tulach 2010-05-04 08:45:06 UTC
As far as I can tell, the behavior is there because of DataNode. It's clipboardCut is non-destructive, it does something only when paste is performed.

For any other node calling clipboardCut such behavior is a non-sense. So I will stop calling it and replace it with originally designed protocol:
- call only drag()
- deal with the transferable and notify it about acceptable drop types.

However this change will be incompatible, so I am leaving it after 6.9. 

As an ugly workaround for 6.9, get the stack inside clipboardCut method and if called from D'n'D code, do nothing.
Comment 3 Jesse Glick 2010-05-04 14:04:44 UTC
(In reply to comment #0)
> we cannot remove the node from the Children in the clipboardCut()

Nor should you. If and when a paste is performed or drag is finished, remove the node from the old parent and add a comparable node to the new parent. (Or whatever the logical outcome of the data transfer would be - might be e.g. inserting text into an editor.)

> http://wiki.netbeans.org/DevFaqCutCopyPaste

This page is nonsense and I am deleting that section. Even if it were good advice to eagerly remove a node the moment cut is performed or a drag starts, the code sample given there is just wrong. Children.remove(Node[]) should never be called by normal module code. An object should be removed from its natural data model, which will fire changes that the node hierarchy passively reflects.

> a solution is to remove the node when is pasted in the getDropType
> function, but this will delay the cut after the paste operation.

Exactly. Remember that the paste operation might never come, and a drag can be canceled. It is much easier to do nothing than to undo a deletion.

> When we are performing a move is called first:
> transferable = DragDropUtilities.getNodeTransferable(nodes,
> DnDConstants.ACTION_MOVE); that will cause a clipboardCut() in the node
> and after that:
> transferable = DragDropUtilities.getNodeTransferable(nodes,
> DnDConstants.ACTION_COPY); that will cause a clipboardCopy() in the node.

This sounds wrong. Only one of cut or copy should be called in a given operation, since that decides the nature of the transferable.

(In reply to comment #2)
> DataNode's clipboardCut is non-destructive,
> it does something only when paste is performed.
> 
> For any other node calling clipboardCut such behavior is a non-sense.

No, I think this is quite natural across a wide range of domains, not just for file nodes. Suppose a user wants to cut and paste a job across Hudson servers. Should the IDE delete the job on Hudson-A the moment Ctrl-X is pressed? Of course not. If and when Ctrl-V is pressed on Hudson-B then the job should be moved in as close to an atomic operation as possible. Same for DnD, which is also often used to reorder nodes within the same parent - accomplished using Index.reorder, not removing and adding objects.

As a general rule, an isolated Cut on a node should not make any permanent change. Some UIs display a cut node with a grayed-out icon, which is restored to its normal color if that data transfer is canceled.

In text documents it is conventional to remove the text immediately (as happens in NB). This is usually safe enough because Undo is typically fast and precise, and the text selection added to the clipboard is typically an exact representation of the original content. (Modulo formatting, it can even be stored in a native clipboard and recovered in an external text editor if the NB JVM were to crash.) By contrast, a cut node usually does not have a non-lossy external representation - its "content" is implicitly defined by what happens when it is pasted. In some cases there is a precise serialized representation of a cut node but I think this is relatively uncommon.

> I will stop calling it and replace it with originally designed protocol:
> - call only drag()
> - deal with the transferable and notify it about acceptable drop types.

This seems reasonable for new code but may be incompatible. What is the effect on DataNode and similar Node impls if they are not modified? What is the recommended minimal change for such nodes?
Comment 4 danoliv 2010-05-04 15:35:57 UTC
Thanks for the help. I got how to solve my problem (yes http://wiki.netbeans.org/DevFaqCutCopyPaste was really wrong).

Jesse I think that you are right but the behavior of ExplorerDragSupport is still wrong in this case, that's right that a node shoudn't be destroyed when a cut is performed but the problem here is that from a Node prospective there is no way to decide the right behavior do perform because there is double call on drag and clipboardCut on a node.

Also in Netbeans IDE you see that when a user perform a cut on a node (that could be a file) there is no evidence that the action has been performed on that node, and I think that this is a problem because the user could forget what file he is moving when he performe a paste after a while. Just a gray icon will be fine and this bug make difficult from a node to choose its behavior.
Comment 5 Jesse Glick 2010-05-04 16:33:43 UTC
(In reply to comment #4)
> the behavior of ExplorerDragSupport is
> still wrong in this case [...] because there is double call on
> drag and clipboardCut on a node.

I agree this seems wrong.

> in Netbeans IDE you see that when a user perform a cut on a node (that
> could be a file) there is no evidence that the action has been performed on
> that node

Right, we never implemented the grayed-out icon; it would be useful.
Comment 6 Jaroslav Tulach 2011-06-12 19:56:05 UTC
Will I ever have time to work on this?
Comment 7 Jaroslav Tulach 2013-01-17 14:57:11 UTC
Probably I will not. Closing.