Drag a Node from a Palette onto a Node

The original question asked by John on the mailing list was about dragging an item from a palette and dropping it in a BeanTreeView. So, after following the previous two blog entries on this topic (here and here), I reimplemented the scenario to use a Palette instead. Note that a Palette only works if it is created for a TopComponent that is in the "editor" position (read about that in German here), as is the case below:

I drag the palette item and then I hold down the Ctrl key, causing the icon over the node where I'm going to drop it to indicate that I am allowed to drop it:

I then drop it, and the node is added right after the node on which I dropped it:

In the constructor of my editor TopComponent, this is how I define the Palette:

Node node = new AbstractNode(Children.create(new PaletteChildFactory(), true));

associateLookup(Lookups.fixed(PaletteFactory.createPalette(node, new PaletteActions() {

    @Override
    public Action[] getImportActions() {
        return null;
    }

    @Override
    public Action[] getCustomPaletteActions() {
        return null;
    }

    @Override
    public Action[] getCustomCategoryActions(Lookup arg0) {
        return null;
    }

    @Override
    public Action[] getCustomItemActions(Lookup arg0) {
        return null;
    }

    @Override
    public Action getPreferredAction(Lookup arg0) {
        return null;
    }

})));

And this is how the "PaletteChildFactory", referred to above, is defined:

import java.awt.datatransfer.Transferable;
import java.io.IOException;
import java.util.List;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;

public class PaletteChildFactory extends ChildFactory<String> {

    @Override
    protected boolean createKeys(List<String> list) {
        list.add("Names");
        return true;
    }

    @Override
    protected Node createNodeForKey(String name) {
        Node node = new AbstractNode(Children.create(new PaletteItemChildFactory(), true));
        node.setDisplayName(name);
        return node;
    }

    private class PaletteItemChildFactory extends ChildFactory<Customer> {

        @Override
        protected boolean createKeys(List<Customer> list) {
            String[] names = {"Tom", "Dick", "Harry"};
            for (String name : names) {
                Customer c = new Customer();
                c.setName(name);
                list.add(c);
            }
            return true;
        }

        @Override
        protected Node createNodeForKey(final Customer c) {
            Node node = new AbstractNode(Children.LEAF) {
                @Override
                public Transferable drag() throws IOException {
                    return c;
                }
            };
            node.setDisplayName(c.getName());
            return node;
        }
        
    }

}

This is the same as shown previously. For the above to be possible, the Customer class needs to implement Transferable, as described in one of the two earlier blog entries on this topic.

So, we now have a Palette. Next, our editor TopComponent needs to have a BeanTreeView (or any other explorer view, of course). Implement ExplorerManager.Provider and then create the nodes in the BeanTreeView in the constructor of the editor TopComponent like this:

em.setRootContext(new AbstractNode(Children.create(new EditorChildFactory(), true)));

Finally, the "EditorChildFactory" is defined as follows, pay particular attention to the getDropType override:

import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
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.util.Exceptions;
import org.openide.util.datatransfer.PasteType;

class EditorChildFactory extends ChildFactory<String> {

    ArrayList<String> names = new ArrayList<String>();

    public EditorChildFactory() {
        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(final String name) {


        Node node = new AbstractNode(Children.LEAF) {

            @Override
            public PasteType getDropType(Transferable t, final int action, final int index) {
                try {
                    //We get the current customer from the transferable:
                    final Customer customer = (Customer) t.getTransferData(Customer.DATA_FLAVOR);
                    //We use the current name to get the current index
                    //in the ArrayList:
                    final int dropIndex = names.indexOf(name);
                    return new PasteType() {
                        @Override
                        public Transferable paste() throws IOException {
                            //We add a new node after the current index,
                            //setting its name to the name of the current customer:
                            names.add(dropIndex + 1, customer.getName());
                            //We refresh the node:
                            refresh(true);
                            //We put nothing in the clipboard:
                            return null;
                        }
                    };
                } catch (UnsupportedFlavorException ex) {
                    Exceptions.printStackTrace(ex);
                } catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
                return null;
            }

        };

        node.setDisplayName(name);
        
        return node;

    }

}

Thanks again to Stan Aubrecht for helping with this.

 

Comments:

Dear Geertjan, I'll be just great if you could complete this series on nodes dragging with an example of: dragging one node, not onto another node, but between nodes.

Sample scenario: I have a list of nodes whose keys I'm holding in a sorted list. I would like to be able to change their order by simply dragging the node up or down to the position I want it to be. That'll also fire the code to change the property of my node'd item which I'm using in the Comparator (simply int index; in my case).

You already mentioned that dragging between nodes (as opposed to onto them) makes the Children get the event and not the node. What I have not been able to find out is how to know the position (index in BeanTreeView, in my case) it has been dropped to.

Just a little selfish suggestion :)

Posted by Miguel Garcia-Lopez on March 20, 2009 at 02:19 AM PDT #

Dear Geertjan,
Thank you very much for this tutorial.
As you have mentioned before, if a drop from the palette between nodes or onto the rootNode is to be supported, one would have to add drop functionality, namely override getDropType() ,to a custom node that extends AbstractNode and then use that node as the root of the children nodes.
My question is how the getDropType()method of the rootNode should be overridden, in order to add a new node to its children, when it accepts a drop from the palette.
Thanks in advance…

Posted by John Vasilopoulos on April 10, 2009 at 06:10 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
12
13
14
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today