Drag a Node from a BeanTreeView onto a TopComponent

The question of the day comes from someone only known as John, who wants to drag an item from the Palette into an explorer view, such as the BeanTreeView. Well, I don't have the complete answer yet, but the first steps, which might end up providing the beginning of the end for John.

At the end of this blog entry, you'll be able to drag a Node from a BeanTreeView (which could be a Node anywhere, such as in a Palette) into a TopComponent, where the drop results in the change to the text in the JLabel that is found there:

Do this:

  1. Create a new module and then create two TopComponents. The first TopComponent contains the Node shown in the Explorer mode on the left above, the second TopComponent is in the Output mode, containing a JLabel.

  2. In the TopComponent in the explorer mode, implement ExplorerManager.Provider, with a BeanTreeView, and then create a Children.Keys or ChildFactory that provides the Node. You also need a Customer domain class that implements Transferable:
    import java.awt.datatransfer.DataFlavor;
    import java.awt.datatransfer.Transferable;
    import java.awt.datatransfer.UnsupportedFlavorException;
    import java.io.IOException;
    
    public class Customer implements Transferable {
    
        public static final DataFlavor DATA_FLAVOR = new DataFlavor(Customer.class, "customer");
        String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public DataFlavor[] getTransferDataFlavors() {
            return new DataFlavor[]{DATA_FLAVOR};
        }
    
        public boolean isDataFlavorSupported(DataFlavor flavor) {
            return flavor == DATA_FLAVOR;
        }
    
        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
            if (flavor == DATA_FLAVOR) {
                return this;
            } else {
                throw new UnsupportedFlavorException(flavor);
            }
        }
    
    }

    In the class that creates the Children, make sure to override the drag() to return the current Customer, as shown here:

    private class NodeChildFactory 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;
        }
    
    }

  3. At the end of the constructor of the TopComponent in the Output mode, add the following code:
    MyDropTargetListener dtl = new MyDropTargetListener();
    DropTarget dt = new DropTarget(this, dtl);
    dt.setDefaultActions(DnDConstants.ACTION_COPY);
    dt.setActive(true);

    Then create the MyDropTargetListener, as an inner class of the same TopComponent, like this:

    public class MyDropTargetListener implements DropTargetListener {
    
        public void dragEnter(DropTargetDragEvent dtde) {}
        public void dragExit(DropTargetEvent dtde) {}
        public void dragOver(DropTargetDragEvent dtde) {}
        public void dropActionChanged(DropTargetDragEvent dtde) {}
    
        public void drop(DropTargetDropEvent dtde) {
            if (dtde.isDataFlavorSupported(Customer.DATA_FLAVOR)) {
                try {
                    Object transData = dtde.getTransferable().getTransferData(Customer.DATA_FLAVOR);
                    if (transData instanceof Customer) {
                        dtde.acceptDrop(DnDConstants.ACTION_COPY);
                        Customer c = (Customer) dtde.getTransferable().getTransferData(Customer.DATA_FLAVOR);
                        StatusDisplayer.getDefault().setStatusText(c.getName());
                        jLabel1.setText(c.getName());
                    }
                } catch (UnsupportedFlavorException ufe) {
                    ufe.printStackTrace();
                    dtde.rejectDrop();
                    dtde.dropComplete(true);
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                    dtde.rejectDrop();
                    dtde.dropComplete(false);
                }
            } else {
                dtde.rejectDrop();
                dtde.dropComplete(false);
            }
        }
    
    }

  4. Now run the application and you should be able to drag and drop a Node into the window that is in the Output mode, because you have set that window to be the DropTarget. Make sure that you hold down the Ctrl key as you move the Node into the drop window, since that's what the Copy action requires. Then the cursor changes to the accept cursor and you can drop your Node, causing the label's text to change to the current customer name.

Now, since the Palette can display Nodes, just like any of the explorer views, you should be able to adapt this example to use a Palette instead of a BeanTreeView. Plus, you should then create a BeanTreeView in the second window, with a LookupListener that detects whenever an InstanceContent contains a new Customer class. But I'll explore that approach next time. For now, refer here and here for further details.

Comments:

Could you please post the full source code of this example.

Posted by Rajiv on March 17, 2009 at 07:04 PM PDT #

Dear Geertjan these two last posts are such useful writings! I need to congratulate you again for the contents. Since I began developing my first NBP-based app your articles and the book you co-authored have been the most helpful contributions I've found.

I must also admit I admire how productive and knowledge-spreading you remain in time... you have a huge work output throughput and quality!!

And now, please excuse me while I go and add DnD functionality to my nodes :)

Posted by Miguel Garcia-Lopez on March 17, 2009 at 07:47 PM PDT #

Hi Miguel, thanks very much for appreciating these blog entries. It would be pretty cool if I could interview you about your application (via e-mail) and write an article about it. If you like that idea, drop me an e-mail at geertjan DOT wielenga AT sun DOT com.

Posted by Geertjan Wielenga on March 18, 2009 at 10:22 PM PDT #

Great example code. Would have taken me much longer to get D&D working without it. Though had to change a couple of lines in the Customer Class from

flavor == DATA_FLAVOR

to

flavor.equals(DATA_FLAVOR)

to get it working. Hopefully this comment will save somebody some pain

Posted by Mark on March 08, 2012 at 03:46 AM PST #

Hi Geertjan,

How to drag multiple nodes (meaning tom,dick,harry at once?

Thanks

Posted by guest on March 19, 2012 at 07:01 PM 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