X

Geertjan's Blog

  • June 29, 2006

Drag and Drop without ActiveEditorDrop

Geertjan Wielenga
Product Manager
I have finally (albeit only thanks to intervention by NetBeans engineer Stan Aubrecht) got a sample of something I have wanted to understand for a very long time... how to drag and drop an item that has already been dragged and dropped from the Component Palette onto a TopComponent. It was one of the missing features in my Music NotePad, because after dropping a note, there was no way of changing your mind and moving it somewhere else. I had the same problem with the Organigram Generator shown in yesterday's blog entry: I didn't know how to drag and drop an employee item after the first drop from the Component Palette.

The central problem, after spending some time with Stan, was that org.openide.text.ActiveEditorDrop applies only to JTextComponents, such as the IDE's Source Editor. The NetBeans tutorials assume that you're interested in ActiveEditorDrop (even the one that deals with TopComponents, which is why extending the application described in that particular tutorial is not possible, without creating a new DataFlavor). And that is what I, or in fact Stan, ended up doing. On top of that, you need to create a new loader, specifically for the XML settings file, which can no longer make use of the http://www.netbeans.org/dtds/editor-palette-item-1_0.dtd.

One interesting thing I learnt is that the items in the Component Palette are nodes. So, once you've used the File Type wizard to create a new loader for your XML settings file, which is identical to the original, except for removing the DOCTYPE and replacing the root element with something of your own (like "my_item"), you can use the generated DataNode class to set the name and the icon that you see for each of the Component Palette's items (see the screenshot in yesterday's blog entry to see what I'm talking about). For example, this is the method in the DataNode class that sets the icons in the Component Palette:

public Image getIcon(int type) {
if (getDisplayName().toString().equals("Wendy")) {
return Utilities.loadImage("org/yourorghere/organigarmui/palette/person3-32.png");
} else if (getDisplayName().toString().equals("Joe")) {
return Utilities.loadImage("org/yourorghere/organigarmui/palette/person1-32.png");
} else if (getDisplayName().toString().equals("Henry")) {
return Utilities.loadImage("org/yourorghere/organigarmui/palette/person2-32.png");
} else if (getDisplayName().toString().equals("Jim")) {
return Utilities.loadImage("org/yourorghere/organigarmui/palette/person4-32.png");
} else if (getDisplayName().toString().equals("Peter")) {
return Utilities.loadImage("org/yourorghere/organigarmui/palette/person5-32.png");
} else if (getDisplayName().toString().equals("Monkey")) {
return Utilities.loadImage("org/yourorghere/organigarmui/palette/person6-32.png");
} else if (getDisplayName().toString().equals("Emma")) {
return Utilities.loadImage("org/yourorghere/organigarmui/palette/person7-32.png");
} else if (getDisplayName().toString().equals("Julie")) {
return Utilities.loadImage("org/yourorghere/organigarmui/palette/person8-32.png");
} else {
return Utilities.loadImage("org/yourorghere/organigarmui/palette/person9-32.png");
}
}

OK, so now that the Component Palette is dealt with via a loader and nodes, we need to look at the drag and drop situation. I first wanted to upload my whole application as a ZIP file into my blog for you so that you could have a look at the sources and play with them, but unfortunately the application is too large, so instead of that you can look at the TopComponent class which contains everything of interest (but not many comments yet, maybe I'll change that later):

OrganigramTopComponent_forblog.pdf

(By the way, the PDF file above was generated with my module that integrates iText into NetBeans IDE. The font size is set to 4 so that even all the long lines fit onto a single line. Note that I have applied for a spot on dev.java.net so that I can open source the module and so that "innovation can happen elsewhere". The address, if accepted, will be https://nbitextsupport.dev.java.net/.)

So, anyway, back to the dragging and dropping. In trying to understand this stuff, before Stan helped me out, I found the following links of some interest, for varying reasons:

So, here's the meat of this blog entry. These are the methods you find in the TopComponent (the same one accessible above via PDF):

  • Standard TopComponent methods. There's nothing special going on here (initComponents(), componentClosed(), componentOpened(), findInstance(), preferredID(), getDefault(), getPersistenceType() and writeReplace()).

  • Palette Initializer. The initializePalette() method. This is a standard, empty palette initializer. Just loads the folder "MyPalette" from the layer.xml.

  • OpenOffice.org API calls. There's a long method called setData, which is just copied and pasted from the OpenOffice.org API Developer's Guide, aiming to generate data from the Organigram Generator to the OOo Draw application, with a small difference: instead of hard coded values, the values are generated on the drop of the items in the Component Palette.

  • ActionPerformed events. There are two buttons, one for selecting the OOo executable and the other for kicking off the OOo process (i.e., "Generate Organigram").

So, all of the above are not important (at all, not even slightly), if you're interested in setting up drag and drop (a) from the Component Pallete to the TopComponent and (b) from one spot in the TopComponent to another. Here it comes, (if you're still here and interested):

Firstly, if you want to drag and drop from one spot in a TopComponent (or some other non-JTextComponent), pay very close attention to the following section of code:

final String smileyName = current_employee;
DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer( smiley, DnDConstants.ACTION_MOVE, new DragGestureListener() {
public void dragGestureRecognized(DragGestureEvent dge) {
Transferable transferable = new Transferable() {
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException,IOException {
return smileyName;
}
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { smileyDataFlavor };
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return smileyDataFlavor.equals( flavor );
}
};
dge.startDrag( null, transferable );
}
});

I went and commented out the above lines and ran the application again. It worked perfectly, except that I couldn't drag an item after dropping it. In other words, the above section independently causes all the magic of the dragging and dropping within the TopComponent. Note that a new DataFlavor is referred to. Here it is, and you can find it at the top of the file:

private static final DataFlavor smileyDataFlavor = new DataFlavor( String.class, "smiley" );

Secondly, if you're interested in the mechanism that gets the item from the Component Paltte onto the TopComponent in the first place, take a look at this bit:

dropTargetDropEvent.acceptDrop( DnDConstants.ACTION_COPY );
Node node = NodeTransfer.node( dropTargetDropEvent.getTransferable(), DNDConstants.ACTION_COPY );
if( null == node ) {
if( dropTargetDropEvent.isDataFlavorSupported( smileyDataFlavor ) ) {
try {
current_employee = (String)dropTargetDropEvent.getTransferable().getTransferData( smileyDataFlavor );
} catch (UnsupportedFlavorException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
} else {
dropTargetDropEvent.dropComplete( false );
return;
}
} else {
current_employee = node.getDisplayName();
}

That's where the copy (while the piece above this was a move) from the Component Palette happens. Again, you could comment out the above lines and run the application successfully (except that this time an error would be generated on the drop).

I can't say that I understand everything that's going on here completely (yet). But I definitely know where to look and what my starting point is. And, my ignorance shouldn't block more competent developers from implementing something that is really cool (i.e., dragging from a TopComponent to somewhere else in the same TopComponent), should it? (I welcome Stan and others to jump in and leave comments, later this code or something similar will find itself in a tutorial, so the better it is, the better it will be for the tutorial.)

And, so, basically, with the above pointers and the attached PDF file, you definitely have a good starting point for implementing your own DataFlavor and creating new drag and drop functionality. (Oh wait, I just realized: that includes me too... I can now add this missing piece of functionality to the Music NotePad, at last. Hurray!)

Join the discussion

Comments ( 2 )
  • Oliver Rettig Sunday, February 3, 2013

    Hi,

    the link to OrganigramTopComponent_forblog.pdf seems to be gone.

    best regards

    Oliver


  • Geertjan Monday, February 4, 2013

    Yes, well, as you can see, this is a blog entry from... 2006.


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.