JAL-3032 adds Java 8 functionality (2/2)
[jalview.git] / src2 / fr / orsay / lri / varna / components / ReorderableJList.java
1 package fr.orsay.lri.varna.components;
2
3 import java.awt.Color;
4 import java.awt.Component;
5 import java.awt.Cursor;
6 import java.awt.Graphics;
7 import java.awt.Point;
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;
27
28 import javax.swing.DefaultListCellRenderer;
29 import javax.swing.DefaultListModel;
30 import javax.swing.JList;
31
32 public class ReorderableJList extends JList 
33 implements DragSourceListener, DropTargetListener, DragGestureListener {
34
35 static DataFlavor localObjectFlavor;
36 static {
37     try {
38         localObjectFlavor =
39             new DataFlavor (DataFlavor.javaJVMLocalObjectMimeType);
40     } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); } 
41
42 static DataFlavor[] supportedFlavors = { localObjectFlavor }; 
43 DragSource dragSource; 
44 DropTarget dropTarget; 
45 int dropTargetIndex; 
46 int draggedIndex = -1;
47
48 public ReorderableJList () {
49     super();
50     setCellRenderer (new ReorderableListCellRenderer());
51     setModel (new DefaultListModel());
52     dragSource = new DragSource();
53     DragGestureRecognizer dgr =
54         dragSource.createDefaultDragGestureRecognizer (this,
55                                    DnDConstants.ACTION_MOVE,
56                                                        this);
57     dropTarget = new DropTarget (this, this);
58 }
59
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);
66     if (index == -1)
67         return;
68     Object target = getModel().getElementAt(index);
69     Transferable trans = new RJLTransferable (target);
70     draggedIndex = index;
71     dragSource.startDrag (dge,Cursor.getDefaultCursor(),
72                           trans, this);
73 }
74 // DragSourceListener events
75 public void dragDropEnd (DragSourceDropEvent dsde) {
76    //System.out.println ("dragDropEnd()");
77    dropTargetIndex = -1;
78    draggedIndex = -1;
79    repaint();
80 }
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)
89         dtde.rejectDrag();
90     else {
91         dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
92         //System.out.println ("accepted dragEnter");
93     }
94 }
95 public void dragExit (DropTargetEvent dte) {}
96
97 public void dropActionChanged (DropTargetDragEvent dtde) {}
98
99 public void dragOver (DropTargetDragEvent dtde) { 
100     // figure out which cell it's over, no drag to self    
101     if (dtde.getSource() != dropTarget)
102         dtde.rejectDrag();
103     Point dragPoint = dtde.getLocation();
104     int index = locationToIndex (dragPoint);
105     dropTargetIndex = index;
106     if (dropTargetIndex != -1)
107     {
108         Rectangle r = getCellBounds(dropTargetIndex,dropTargetIndex);
109         if (dragPoint.y > r.y+r.height/2)
110         {
111                 dropTargetIndex += 1;           
112         }
113     }
114     //System.out.println(dropTargetIndex);
115     repaint(); 
116 }
117
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() + ")");        
123         dtde.rejectDrop(); 
124         return;
125     }
126     Point dropPoint = dtde.getLocation();
127     int index = locationToIndex (dropPoint);
128     if (index != -1)
129     {
130         Rectangle r = getCellBounds(index,index);
131         if (dropPoint.y > r.y+r.height/2)
132         {
133                 index += 1;             
134         }
135     }
136     
137     //System.out.println ("drop index is " + index);
138     boolean dropped = false;
139     try {
140         if ((index == -1) || (index == draggedIndex)|| (index == draggedIndex+1)) {
141             //System.out.println ("dropped onto self");
142             dtde.rejectDrop();
143             return;
144         }
145         dtde.acceptDrop (DnDConstants.ACTION_MOVE);
146         //System.out.println ("accepted");
147         Object dragged =
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); 
161         dropped = true;
162     } catch (Exception e) {
163         e.printStackTrace();
164     }
165     dtde.dropComplete (dropped);
166 }
167
168 private class ReorderableListCellRenderer 
169 extends DefaultListCellRenderer { 
170 boolean isTargetCell; 
171 boolean isLastItem;    
172 public ReorderableListCellRenderer() {
173     super();
174 }
175 public Component getListCellRendererComponent (JList list,
176                                                Object value, 
177                                                int index, 
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, 
183                                                index, showSelected,                                                 
184                                                hasFocus);
185 }
186 public void paintComponent (Graphics g) {
187     super.paintComponent(g);
188     if (isTargetCell) {
189         g.setColor(Color.black);            
190         g.drawLine (0, 0, getSize().width, 0); 
191     } 
192     if (isLastItem) {
193         g.setColor(Color.black);            
194         g.drawLine (0, getSize().height-1, getSize().width, getSize().height-1); 
195     } 
196  } 
197 }
198
199 private class RJLTransferable implements Transferable { 
200     Object object; 
201     public RJLTransferable (Object o) {
202         object = o;
203     }
204     public Object getTransferData(DataFlavor df)
205         throws UnsupportedFlavorException, IOException {
206         if (isDataFlavorSupported (df))
207             return object;
208         else
209            throw new UnsupportedFlavorException(df);
210     }
211     public boolean isDataFlavorSupported (DataFlavor df) {
212         return (df.equals (localObjectFlavor));
213     }
214     public DataFlavor[] getTransferDataFlavors () {
215         return supportedFlavors; } 
216 }
217
218
219 }