Tuesday March 17, 2009
Drag a Node from a BeanTreeView onto a Node
Let's extend the example from yesterday to support a drop of the Node onto a BeanTreeView instead of our TopComponent. In the end, we'll have two TopComponents, like this:
When you hold down the Ctrl key and drag a Node from the list of boy names, you can drop it onto a name in the list of girl names, which will cause the boy name to be added to the list of girl names:
Do the following:
- Take the steps outlined in yesterday's blog entry. That's the starting point for the steps that follow.
- In the NodeChildFactory, which defines the list of boy names (shown yesterday), remove the drag() override. Yesterday, we were dragging Customer objects. Today, we want to be dragging the Node instead, which is the default behavior of the drag() method. We want to drag the Node instead of the Customer, because later we will be using org.openide.nodes.NodeTransfer to retrieve a Node from the Transferable.
- Next, open the second TopComponent. Yesterday it contained a JLabel, with a text that changed on the drop of the Customer onto the TopComponent. Today, remove the JLabel and replace it with a BeanTreeView, which means you need to implement ExplorerManager.Provider. Also remove the DropTargetListener, because we will be using the BeanTreeView's own DropTargetListener, which delegates to the Node. Create the Node like this in the constructor:
em.setRootContext(new AbstractNode(Children.create(new DummyChildFactory(), true)));
Then define the children of the Node as follows, taking special note of the section in bold below:
import java.awt.datatransfer.Transferable; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.NodeTransfer; import org.openide.util.datatransfer.PasteType; class DummyChildFactory extends ChildFactory<String> { ArrayList<String> names = new ArrayList<String>(); public DummyChildFactory() { names.add( "Jane"); names.add( "Judy"); names.add( "Paula"); } @Override protected boolean createKeys(List<String> list) { for (String name : names) { list.add(name); } return true; } @Override protected Node createNodeForKey(String name) { Node node = new AbstractNode(Children.LEAF){ @Override public PasteType getDropType(Transferable t, int arg1, int arg2) { final Node node = NodeTransfer.node(t, arg1); return new PasteType() { @Override public Transferable paste() throws IOException { names.add(node.getDisplayName()); refresh(true); return null; } }; } }; node.setDisplayName(name); return node; } }Optionally, instead of the Node, you can drop a Customer object instead, assuming you've overridden the drag() as explained yesterday (take note of the two lines in bold below, which are the only ones different to the dropping of the Node described above):
@Override public PasteType getDropType(Transferable t, int arg1, int arg2) { try { final Customer c = (Customer) t.getTransferData(Customer.DATA_FLAVOR); //final Node node = NodeTransfer.node(t, arg1); return new PasteType() { @Override public Transferable paste() throws IOException { names.add(c.getName()); refresh(true); return null; } }; } catch (UnsupportedFlavorException ex) { Exceptions.printStackTrace(ex); } catch (IOException ex) { Exceptions.printStackTrace(ex); } return null; }
Make sure to drop onto a girl name, not between them, because in between the Nodes is handled by the root Node, which is the AbstractNode defined in the TopComponent, in this case. So, to support the in between bits, you'd have to also add drop functionality to a custom root Node. I.e., create a new Node that extends AbstractNode and then use that Node as the root of your children.
Thanks to Stan Aubrecht for helping with this scenario.
Mar 17 2009, 03:19:46 AM PDT Permalink
I've just noticed that you finally switched to GTK LAF on Ubuntu. If you like the Default Ubuntu Human theme, but also would like NetBeans to look even cooler, then select: System -> Preferences -> Appearance -> Theme -> Human-Clearlooks
Posted by Laszlo Kishalmi on March 17, 2009 at 04:17 AM PDT #
Honestly, I prefer Metal. I've never understood what's so wrong with it. I only don't use it when I can't be bothered to set the requisite switch in the IDE that enables it.
Posted by Geertjan Wielenga on March 17, 2009 at 04:20 AM PDT #
I have implemented pretty much what you have suggested. I am using a BeanTree View and wanting to just support the moving and copying of nodes within the Tree itself. What I am doing differently is that the data each node contains is actually part of a separate collection so I have to maintain that myself in the paste mehtod. I notice that when getDropType is called that the action value is a large number whenever a move is performed and the correct value when a copy is performed. Second, when a move is performed the icon doesn't change to show that it is allowed to be dropped but always remains as not allowed.
I have gone over and over your tutorials and I can't see that you are doing anything that would enable or disable support for moving so I would assume yours just works so what could I be doing wrong?
Thanks in advance.
Posted by Blaine on March 23, 2009 at 11:32 AM PDT #
Posted by Dave Rigsby's Blog on August 26, 2009 at 09:17 PM PDT #
Posted by Dave Rigsby's Blog on August 26, 2009 at 09:19 PM PDT #
Posted by Dave Rigsby's Blog on August 26, 2009 at 09:20 PM PDT #
Posted by Dave Rigsby's Blog on August 26, 2009 at 09:24 PM PDT #
Posted by Dave Rigsby's Blog on August 26, 2009 at 09:26 PM PDT #
Posted by Dave Rigsby's Blog-o-Code on August 26, 2009 at 09:32 PM PDT #
Posted by Dave Rigsby's Blog-o-Code on August 26, 2009 at 09:33 PM PDT #


