1 package fr.orsay.lri.varna.components;
4 import java.awt.Component;
5 import java.awt.Cursor;
6 import java.awt.Graphics;
8 import java.awt.Rectangle;
9 import java.awt.datatransfer.DataFlavor;
10 import java.awt.datatransfer.Transferable;
11 import java.awt.datatransfer.UnsupportedFlavorException;
12 import java.awt.dnd.DnDConstants;
13 import java.awt.dnd.DragGestureEvent;
14 import java.awt.dnd.DragGestureListener;
15 import java.awt.dnd.DragGestureRecognizer;
16 import java.awt.dnd.DragSource;
17 import java.awt.dnd.DragSourceDragEvent;
18 import java.awt.dnd.DragSourceDropEvent;
19 import java.awt.dnd.DragSourceEvent;
20 import java.awt.dnd.DragSourceListener;
21 import java.awt.dnd.DropTarget;
22 import java.awt.dnd.DropTargetDragEvent;
23 import java.awt.dnd.DropTargetDropEvent;
24 import java.awt.dnd.DropTargetEvent;
25 import java.awt.dnd.DropTargetListener;
26 import java.io.IOException;
28 import javax.swing.DefaultListCellRenderer;
29 import javax.swing.DefaultListModel;
30 import javax.swing.JList;
32 public class ReorderableJList extends JList
33 implements DragSourceListener, DropTargetListener, DragGestureListener {
35 static DataFlavor localObjectFlavor;
39 new DataFlavor (DataFlavor.javaJVMLocalObjectMimeType);
40 } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); }
42 static DataFlavor[] supportedFlavors = { localObjectFlavor };
43 DragSource dragSource;
44 DropTarget dropTarget;
46 int draggedIndex = -1;
48 public ReorderableJList () {
50 setCellRenderer (new ReorderableListCellRenderer());
51 setModel (new DefaultListModel());
52 dragSource = new DragSource();
53 DragGestureRecognizer dgr =
54 dragSource.createDefaultDragGestureRecognizer (this,
55 DnDConstants.ACTION_MOVE,
57 dropTarget = new DropTarget (this, this);
60 // DragGestureListener
61 public void dragGestureRecognized (DragGestureEvent dge) {
62 //System.out.println ("dragGestureRecognized");
63 // find object at this x,y
64 Point clickPoint = dge.getDragOrigin();
65 int index = locationToIndex(clickPoint);
68 Object target = getModel().getElementAt(index);
69 Transferable trans = new RJLTransferable (target);
71 dragSource.startDrag (dge,Cursor.getDefaultCursor(),
74 // DragSourceListener events
75 public void dragDropEnd (DragSourceDropEvent dsde) {
76 //System.out.println ("dragDropEnd()");
81 public void dragEnter (DragSourceDragEvent dsde) {}
82 public void dragExit (DragSourceEvent dse) {}
83 public void dragOver (DragSourceDragEvent dsde) {}
84 public void dropActionChanged (DragSourceDragEvent dsde) {}
85 // DropTargetListener events
86 public void dragEnter (DropTargetDragEvent dtde) {
87 //System.out.println ("dragEnter");
88 if (dtde.getSource() != dropTarget)
91 dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
92 //System.out.println ("accepted dragEnter");
95 public void dragExit (DropTargetEvent dte) {}
97 public void dropActionChanged (DropTargetDragEvent dtde) {}
99 public void dragOver (DropTargetDragEvent dtde) {
100 // figure out which cell it's over, no drag to self
101 if (dtde.getSource() != dropTarget)
103 Point dragPoint = dtde.getLocation();
104 int index = locationToIndex (dragPoint);
105 dropTargetIndex = index;
106 if (dropTargetIndex != -1)
108 Rectangle r = getCellBounds(dropTargetIndex,dropTargetIndex);
109 if (dragPoint.y > r.y+r.height/2)
111 dropTargetIndex += 1;
114 //System.out.println(dropTargetIndex);
118 public void drop (DropTargetDropEvent dtde) {
119 //System.out.println ("drop()!");
120 if (dtde.getSource() != dropTarget) {
121 //System.out.println ("rejecting for bad source (" +
122 // dtde.getSource().getClass().getName() + ")");
126 Point dropPoint = dtde.getLocation();
127 int index = locationToIndex (dropPoint);
130 Rectangle r = getCellBounds(index,index);
131 if (dropPoint.y > r.y+r.height/2)
137 //System.out.println ("drop index is " + index);
138 boolean dropped = false;
140 if ((index == -1) || (index == draggedIndex)|| (index == draggedIndex+1)) {
141 //System.out.println ("dropped onto self");
145 dtde.acceptDrop (DnDConstants.ACTION_MOVE);
146 //System.out.println ("accepted");
148 dtde.getTransferable().getTransferData(localObjectFlavor);
149 // move items - note that indicies for insert will
150 // change if [removed] source was before target
151 //System.out.println ("drop " + draggedIndex + " to " + index);
152 boolean sourceBeforeTarget = (draggedIndex < index);
153 //System.out.println ("source is" +
154 // (sourceBeforeTarget ? "" : " not") +
155 // " before target");
156 //System.out.println ("insert at " +
157 // (sourceBeforeTarget ? index-1 : index));
158 DefaultListModel mod = (DefaultListModel) getModel();
159 mod.remove (draggedIndex);
160 mod.add ((sourceBeforeTarget ? index-1 : index), dragged);
162 } catch (Exception e) {
165 dtde.dropComplete (dropped);
168 private class ReorderableListCellRenderer
169 extends DefaultListCellRenderer {
170 boolean isTargetCell;
172 public ReorderableListCellRenderer() {
175 public Component getListCellRendererComponent (JList list,
178 boolean isSelected, boolean hasFocus) {
179 isTargetCell = (index == dropTargetIndex);
180 isLastItem = (index == list.getModel().getSize()-1) && (dropTargetIndex == list.getModel().getSize());
181 boolean showSelected = isSelected;
182 return super.getListCellRendererComponent (list, value,
186 public void paintComponent (Graphics g) {
187 super.paintComponent(g);
189 g.setColor(Color.black);
190 g.drawLine (0, 0, getSize().width, 0);
193 g.setColor(Color.black);
194 g.drawLine (0, getSize().height-1, getSize().width, getSize().height-1);
199 private class RJLTransferable implements Transferable {
201 public RJLTransferable (Object o) {
204 public Object getTransferData(DataFlavor df)
205 throws UnsupportedFlavorException, IOException {
206 if (isDataFlavorSupported (df))
209 throw new UnsupportedFlavorException(df);
211 public boolean isDataFlavorSupported (DataFlavor df) {
212 return (df.equals (localObjectFlavor));
214 public DataFlavor[] getTransferDataFlavors () {
215 return supportedFlavors; }