--- /dev/null
+package fr.orsay.lri.varna.components;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DragGestureEvent;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragGestureRecognizer;
+import java.awt.dnd.DragSource;
+import java.awt.dnd.DragSourceDragEvent;
+import java.awt.dnd.DragSourceDropEvent;
+import java.awt.dnd.DragSourceEvent;
+import java.awt.dnd.DragSourceListener;
+import java.awt.dnd.DropTarget;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
+import java.io.IOException;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.DefaultListModel;
+import javax.swing.JList;
+
+public class ReorderableJList extends JList
+implements DragSourceListener, DropTargetListener, DragGestureListener {
+
+static DataFlavor localObjectFlavor;
+static {
+ try {
+ localObjectFlavor =
+ new DataFlavor (DataFlavor.javaJVMLocalObjectMimeType);
+ } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); }
+}
+static DataFlavor[] supportedFlavors = { localObjectFlavor };
+DragSource dragSource;
+DropTarget dropTarget;
+int dropTargetIndex;
+int draggedIndex = -1;
+
+public ReorderableJList () {
+ super();
+ setCellRenderer (new ReorderableListCellRenderer());
+ setModel (new DefaultListModel());
+ dragSource = new DragSource();
+ DragGestureRecognizer dgr =
+ dragSource.createDefaultDragGestureRecognizer (this,
+ DnDConstants.ACTION_MOVE,
+ this);
+ dropTarget = new DropTarget (this, this);
+}
+
+// DragGestureListener
+public void dragGestureRecognized (DragGestureEvent dge) {
+ //System.out.println ("dragGestureRecognized");
+ // find object at this x,y
+ Point clickPoint = dge.getDragOrigin();
+ int index = locationToIndex(clickPoint);
+ if (index == -1)
+ return;
+ Object target = getModel().getElementAt(index);
+ Transferable trans = new RJLTransferable (target);
+ draggedIndex = index;
+ dragSource.startDrag (dge,Cursor.getDefaultCursor(),
+ trans, this);
+}
+// DragSourceListener events
+public void dragDropEnd (DragSourceDropEvent dsde) {
+ //System.out.println ("dragDropEnd()");
+ dropTargetIndex = -1;
+ draggedIndex = -1;
+ repaint();
+}
+public void dragEnter (DragSourceDragEvent dsde) {}
+public void dragExit (DragSourceEvent dse) {}
+public void dragOver (DragSourceDragEvent dsde) {}
+public void dropActionChanged (DragSourceDragEvent dsde) {}
+// DropTargetListener events
+public void dragEnter (DropTargetDragEvent dtde) {
+ //System.out.println ("dragEnter");
+ if (dtde.getSource() != dropTarget)
+ dtde.rejectDrag();
+ else {
+ dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
+ //System.out.println ("accepted dragEnter");
+ }
+}
+public void dragExit (DropTargetEvent dte) {}
+
+public void dropActionChanged (DropTargetDragEvent dtde) {}
+
+public void dragOver (DropTargetDragEvent dtde) {
+ // figure out which cell it's over, no drag to self
+ if (dtde.getSource() != dropTarget)
+ dtde.rejectDrag();
+ Point dragPoint = dtde.getLocation();
+ int index = locationToIndex (dragPoint);
+ dropTargetIndex = index;
+ if (dropTargetIndex != -1)
+ {
+ Rectangle r = getCellBounds(dropTargetIndex,dropTargetIndex);
+ if (dragPoint.y > r.y+r.height/2)
+ {
+ dropTargetIndex += 1;
+ }
+ }
+ //System.out.println(dropTargetIndex);
+ repaint();
+}
+
+public void drop (DropTargetDropEvent dtde) {
+ //System.out.println ("drop()!");
+ if (dtde.getSource() != dropTarget) {
+ //System.out.println ("rejecting for bad source (" +
+ // dtde.getSource().getClass().getName() + ")");
+ dtde.rejectDrop();
+ return;
+ }
+ Point dropPoint = dtde.getLocation();
+ int index = locationToIndex (dropPoint);
+ if (index != -1)
+ {
+ Rectangle r = getCellBounds(index,index);
+ if (dropPoint.y > r.y+r.height/2)
+ {
+ index += 1;
+ }
+ }
+
+ //System.out.println ("drop index is " + index);
+ boolean dropped = false;
+ try {
+ if ((index == -1) || (index == draggedIndex)|| (index == draggedIndex+1)) {
+ //System.out.println ("dropped onto self");
+ dtde.rejectDrop();
+ return;
+ }
+ dtde.acceptDrop (DnDConstants.ACTION_MOVE);
+ //System.out.println ("accepted");
+ Object dragged =
+ dtde.getTransferable().getTransferData(localObjectFlavor);
+ // move items - note that indicies for insert will
+ // change if [removed] source was before target
+ //System.out.println ("drop " + draggedIndex + " to " + index);
+ boolean sourceBeforeTarget = (draggedIndex < index);
+ //System.out.println ("source is" +
+ // (sourceBeforeTarget ? "" : " not") +
+ // " before target");
+ //System.out.println ("insert at " +
+ // (sourceBeforeTarget ? index-1 : index));
+ DefaultListModel mod = (DefaultListModel) getModel();
+ mod.remove (draggedIndex);
+ mod.add ((sourceBeforeTarget ? index-1 : index), dragged);
+ dropped = true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ dtde.dropComplete (dropped);
+}
+
+private class ReorderableListCellRenderer
+extends DefaultListCellRenderer {
+boolean isTargetCell;
+boolean isLastItem;
+public ReorderableListCellRenderer() {
+ super();
+}
+public Component getListCellRendererComponent (JList list,
+ Object value,
+ int index,
+ boolean isSelected, boolean hasFocus) {
+ isTargetCell = (index == dropTargetIndex);
+ isLastItem = (index == list.getModel().getSize()-1) && (dropTargetIndex == list.getModel().getSize());
+ boolean showSelected = isSelected;
+ return super.getListCellRendererComponent (list, value,
+ index, showSelected,
+ hasFocus);
+}
+public void paintComponent (Graphics g) {
+ super.paintComponent(g);
+ if (isTargetCell) {
+ g.setColor(Color.black);
+ g.drawLine (0, 0, getSize().width, 0);
+ }
+ if (isLastItem) {
+ g.setColor(Color.black);
+ g.drawLine (0, getSize().height-1, getSize().width, getSize().height-1);
+ }
+ }
+}
+
+private class RJLTransferable implements Transferable {
+ Object object;
+ public RJLTransferable (Object o) {
+ object = o;
+ }
+ public Object getTransferData(DataFlavor df)
+ throws UnsupportedFlavorException, IOException {
+ if (isDataFlavorSupported (df))
+ return object;
+ else
+ throw new UnsupportedFlavorException(df);
+ }
+ public boolean isDataFlavorSupported (DataFlavor df) {
+ return (df.equals (localObjectFlavor));
+ }
+ public DataFlavor[] getTransferDataFlavors () {
+ return supportedFlavors; }
+}
+
+
+}