Statistics
| Revision:

svn-gvsig-desktop / branches / gvSIG_03_SLD / applications / appgvSIG / src / com / iver / cit / gvsig / gui / toc / DnDJTree.java @ 2078

History | View | Annotate | Download (13.7 KB)

1
/*
2
 * Created on 02-jun-2004
3
 *
4
 */
5
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
6
 *
7
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation; either version 2
12
 * of the License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
22
 *
23
 * For more information, contact:
24
 *
25
 *  Generalitat Valenciana
26
 *   Conselleria d'Infraestructures i Transport
27
 *   Av. Blasco Ib??ez, 50
28
 *   46010 VALENCIA
29
 *   SPAIN
30
 *
31
 *      +34 963862235
32
 *   gvsig@gva.es
33
 *      www.gvsig.gva.es
34
 *
35
 *    or
36
 *
37
 *   IVER T.I. S.A
38
 *   Salamanca 50
39
 *   46005 Valencia
40
 *   Spain
41
 *
42
 *   +34 963163400
43
 *   dac@iver.es
44
 */
45
package com.iver.cit.gvsig.gui.toc;
46
/*
47
**  This is version II of DnDJTree. The first version allowed for what I 
48
**  thought was a JDK oversight. However, we can set the cursor appropriately,
49
**  relative to whether the current cursor location is a valid drop target.
50
**
51
**  If this is your first time reading the source code. Just ignore the above
52
**  comment and ignore the "CHANGED" comments below. Otherwise, the 
53
**  "CHANGED" comments will show where the code has changed.
54
**
55
**  Credit for finding this shortcoming in my code goes Laurent Hubert.
56
**  Thanks Laurent.
57
**
58
**  Rob. [ rkenworthy@hotmail.com ]
59
*/
60

    
61

    
62
import java.awt.Cursor;
63
import java.awt.Point;
64
import java.awt.datatransfer.Transferable;
65
import java.awt.datatransfer.UnsupportedFlavorException;
66
import java.awt.dnd.DnDConstants;
67
import java.awt.dnd.DragGestureEvent;
68
import java.awt.dnd.DragGestureListener;
69
import java.awt.dnd.DragGestureRecognizer;
70
import java.awt.dnd.DragSource;
71
import java.awt.dnd.DragSourceContext;
72
import java.awt.dnd.DragSourceDragEvent;
73
import java.awt.dnd.DragSourceDropEvent;
74
import java.awt.dnd.DragSourceEvent;
75
import java.awt.dnd.DragSourceListener;
76
import java.awt.dnd.DropTarget;
77
import java.awt.dnd.DropTargetDragEvent;
78
import java.awt.dnd.DropTargetDropEvent;
79
import java.awt.dnd.DropTargetEvent;
80
import java.awt.dnd.DropTargetListener;
81
import java.awt.event.InputEvent;
82
import java.io.IOException;
83
import java.util.ArrayList;
84

    
85
import javax.swing.JTree;
86
import javax.swing.SwingUtilities;
87
import javax.swing.event.TreeSelectionEvent;
88
import javax.swing.event.TreeSelectionListener;
89
import javax.swing.tree.DefaultMutableTreeNode;
90
import javax.swing.tree.DefaultTreeModel;
91
import javax.swing.tree.MutableTreeNode;
92
import javax.swing.tree.TreeModel;
93
import javax.swing.tree.TreePath;
94

    
95
import com.iver.cit.gvsig.fmap.layers.FLayer;
96
import com.iver.cit.gvsig.fmap.layers.FLayers;
97

    
98
public class DnDJTree extends JTree
99
                  implements TreeSelectionListener, 
100
                  DragGestureListener, DropTargetListener,
101
                  DragSourceListener {
102

    
103
  protected ArrayList m_Listeners = new ArrayList();
104
        
105
  /** Stores the parent Frame of the component */
106
  // private Frame Parent = null;
107

    
108
  /** Stores the selected node info */
109
  protected TreePath SelectedTreePath = null;
110
  protected DefaultMutableTreeNode SelectedNode = null;
111

    
112
  /** Variables needed for DnD */
113
  private DragSource dragSource = null;
114
  private DragSourceContext dragSourceContext = null;
115

    
116

    
117
  /** Constructor 
118
  @param root The root node of the tree
119
  @param parent Parent JFrame of the JTree */
120
  public DnDJTree(TreeModel treeModel) {
121
    super(treeModel);
122
    // Parent = parent;
123

    
124
    addTreeSelectionListener(this);
125

    
126
                /* ********************** CHANGED ********************** */
127
    dragSource = DragSource.getDefaultDragSource() ;
128
                /* ****************** END OF CHANGE ******************** */
129
    
130
    DragGestureRecognizer dgr = 
131
      dragSource.createDefaultDragGestureRecognizer(
132
        this,                             //DragSource
133
        DnDConstants.ACTION_COPY_OR_MOVE, //specifies valid actions
134
        this                              //DragGestureListener
135
      );
136

    
137

    
138
    /* Eliminates right mouse clicks as valid actions - useful especially
139
     * if you implement a JPopupMenu for the JTree
140
     */
141
    dgr.setSourceActions(dgr.getSourceActions() & ~InputEvent.BUTTON3_MASK);
142

    
143
    /* First argument:  Component to associate the target with
144
     * Second argument: DropTargetListener 
145
    */
146
    DropTarget dropTarget = new DropTarget(this, this);
147

    
148
  }
149

    
150
  /** Returns The selected node */
151
  public DefaultMutableTreeNode getSelectedNode() {
152
    return SelectedNode;
153
  }
154

    
155
  ///////////////////////// Interface stuff ////////////////////
156

    
157

    
158
  /** DragGestureListener interface method */
159
  public void dragGestureRecognized(DragGestureEvent e) {
160
    //Get the selected node
161
    DefaultMutableTreeNode dragNode = getSelectedNode();
162
    if (dragNode != null) {
163

    
164
      
165
      if (!(dragNode.getUserObject() instanceof Transferable)) return;
166
      
167
//    Get the Transferable Object
168
      Transferable transferable = (Transferable) dragNode.getUserObject();
169
      
170
                        /* ********************** CHANGED ********************** */
171

    
172
      //Select the appropriate cursor;
173
      Cursor cursor = DragSource.DefaultCopyNoDrop;
174
      int action = e.getDragAction();
175
      if (action == DnDConstants.ACTION_MOVE) 
176
        cursor = DragSource.DefaultMoveDrop;
177
        
178
        
179
      //In fact the cursor is set to NoDrop because once an action is rejected
180
      // by a dropTarget, the dragSourceListener are no more invoked.
181
      // Setting the cursor to no drop by default is so more logical, because 
182
      // when the drop is accepted by a component, then the cursor is changed by the
183
      // dropActionChanged of the default DragSource.
184
                        /* ****************** END OF CHANGE ******************** */
185
   
186
      //begin the drag
187
      dragSource.startDrag(e, cursor, transferable, this);
188
    }
189
  }
190

    
191
  /** DragSourceListener interface method */
192
  public void dragDropEnd(DragSourceDropEvent dsde) {
193
  }
194

    
195
  /** DragSourceListener interface method */
196
  public void dragEnter(DragSourceDragEvent dsde) {
197
                /* ********************** CHANGED ********************** */
198
                /* ****************** END OF CHANGE ******************** */
199
  }
200

    
201
  /** DragSourceListener interface method */
202
  public void dragOver(DragSourceDragEvent dsde) {
203
                /* ********************** CHANGED ********************** */
204
                /* ****************** END OF CHANGE ******************** */
205
  }
206

    
207
  /** DragSourceListener interface method */
208
  public void dropActionChanged(DragSourceDragEvent dsde) {
209
  }
210

    
211
  /** DragSourceListener interface method */
212
  public void dragExit(DragSourceEvent dsde) {
213
  }
214

    
215
  
216
  
217
  
218
  /** DropTargetListener interface method - What we do when drag is released */
219
  public void drop(DropTargetDropEvent e) {
220
    try {
221
      Transferable tr = e.getTransferable();
222
      //flavor not supported, reject drop
223
      if (!tr.isDataFlavorSupported( TocItemBranch.INFO_FLAVOR)) e.rejectDrop();
224
      //cast into appropriate data type
225
      TocItemBranch childInfo = 
226
        (TocItemBranch) tr.getTransferData( TocItemBranch.INFO_FLAVOR ); 
227
      //get new parent node
228
      Point loc = e.getLocation();
229
      TreePath destinationPath = getPathForLocation(loc.x, loc.y);
230

    
231
      final String msg = testDropTarget(destinationPath, SelectedTreePath);
232
      if (msg != null) {
233
        e.rejectDrop();
234

    
235
        SwingUtilities.invokeLater(new Runnable() {
236
          public void run() {
237
                 System.err.println(msg);
238
          }
239
        });
240
        return;
241
      }
242
      int oldPos,newPos;
243
          boolean isContainer=false;
244

    
245
          DefaultMutableTreeNode nodoTocado =
246
        (DefaultMutableTreeNode) destinationPath.getLastPathComponent(); 
247
          //        get old parent node
248
      DefaultMutableTreeNode oldParent = (DefaultMutableTreeNode) getSelectedNode().getParent();
249
          oldPos = oldParent.getIndex(getSelectedNode());
250
          // Para no tener en cuenta los nodos de s?mbolos:
251
      if (!(nodoTocado.getUserObject() instanceof TocItemBranch)){
252
                      nodoTocado = (DefaultMutableTreeNode) nodoTocado.getParent();
253
      }
254
      
255
      ///posActual = oldParent.getIndex(getSelectedNode());
256
      //Destino
257
          DefaultMutableTreeNode destParent=null;
258
          
259
          if (((TocItemBranch)nodoTocado.getUserObject()).getLayer() instanceof FLayers){
260
                 isContainer=true;
261
                  newPos=0;
262
                  destParent=nodoTocado;
263
      }else{//Si donde se deja la capa seleccionada no es un contenedor de capas.
264
                destParent= (DefaultMutableTreeNode)nodoTocado.getParent();
265
        newPos=destParent.getIndex(nodoTocado);
266
      }
267
          
268
      
269
      
270

    
271
      int action = e.getDropAction();
272
      boolean copyAction = (action == DnDConstants.ACTION_COPY);
273

    
274
      //make new child node
275
      DefaultMutableTreeNode newChild = new DefaultMutableTreeNode(childInfo);
276
          if (getSelectedNode().getAllowsChildren()){
277
                  int childs=getSelectedNode().getChildCount();
278
                  
279
                  for (int i=0;i<childs;i++){
280
                          newChild.add((MutableTreeNode)getSelectedNode().getChildAt(0));
281
                  }
282
          }
283
          
284
          try { 
285
        if (!copyAction) oldParent.remove(getSelectedNode());
286
        destParent.insert(newChild,newPos);
287
        // newParent.add(newChild);
288
          
289
        if (copyAction) e.acceptDrop (DnDConstants.ACTION_COPY);
290
        else e.acceptDrop (DnDConstants.ACTION_MOVE);
291
      }
292
      catch (java.lang.IllegalStateException ils) {
293
        e.rejectDrop();
294
      }
295
          
296
      e.getDropTargetContext().dropComplete(true);
297
      
298
      //expand nodes appropriately - this probably isnt the best way...
299
      DefaultTreeModel model = (DefaultTreeModel) getModel();
300
      model.reload(oldParent);
301
          
302
          model.reload(destParent);
303
          if (oldParent.getUserObject() instanceof TocItemBranch){
304
          FLayers lpo=(FLayers)((TocItemBranch)oldParent.getUserObject()).getLayer();
305
          FLayers lpd=(FLayers)((TocItemBranch)destParent.getUserObject()).getLayer();
306
          
307
          if (destParent.equals(oldParent)){
308
                  callListeners(oldPos,newPos,lpd);
309
                  ///callListeners((FLayers)((TocItemBranch)oldParent.getUserObject()).getLayer(),(FLayers)((TocItemBranch)destParent.getUserObject()).getLayer(),((TocItemBranch)newChild.getUserObject()).getLayer(),newPos);
310
          }else{
311
                  callListeners(lpo,lpd,((TocItemBranch)newChild.getUserObject()).getLayer());
312
                ///  callListeners(newPos,newPos+1);
313
          }
314
          }
315
          ///callListeners(posActual, newPos);
316
      /* model.reload(newParent);
317
      TreePath parentPath = new TreePath(newParent.getPath());
318
      expandPath(parentPath); */
319
    }
320
    catch (IOException io) { e.rejectDrop(); }
321
    catch (UnsupportedFlavorException ufe) {e.rejectDrop();}
322
  } //end of method
323

    
324

    
325
  /** DropTaregetListener interface method */
326
  public void dragEnter(DropTargetDragEvent e) {
327
  }
328

    
329
  /** DropTaregetListener interface method */
330
  public void dragExit(DropTargetEvent e) { 
331
  }
332

    
333
  /** DropTaregetListener interface method */
334
  public void dragOver(DropTargetDragEvent e) {
335
                /* ********************** CHANGED ********************** */
336
    //set cursor location. Needed in setCursor method
337
    Point cursorLocationBis = e.getLocation();
338
        TreePath destinationPath = 
339
      getPathForLocation(cursorLocationBis.x, cursorLocationBis.y);
340

    
341

    
342
    // if destination path is okay accept drop...
343
    if (testDropTarget(destinationPath, SelectedTreePath) == null){
344
            e.acceptDrag(DnDConstants.ACTION_MOVE) ;
345
    }
346
    // ...otherwise reject drop
347
    else {
348
            e.rejectDrag() ;
349
    }
350
                /* ****************** END OF CHANGE ******************** */
351
  }
352

    
353
  /** DropTaregetListener interface method */
354
  public void dropActionChanged(DropTargetDragEvent e) {
355
  }
356

    
357

    
358
  /** TreeSelectionListener - sets selected node */
359
  public void valueChanged(TreeSelectionEvent evt) {
360
    SelectedTreePath = evt.getNewLeadSelectionPath();
361
    if (SelectedTreePath == null) {
362
      SelectedNode = null;
363
      return;
364
    }
365
    SelectedNode = 
366
      (DefaultMutableTreeNode)SelectedTreePath.getLastPathComponent();
367
  }
368

    
369
  /** Convenience method to test whether drop location is valid
370
  @param destination The destination path 
371
  @param dropper The path for the node to be dropped
372
  @return null if no problems, otherwise an explanation
373
  */
374
  private String testDropTarget(TreePath destination, TreePath dropper) {
375
    //Typical Tests for dropping
376
 
377
    //Test 1.
378
    boolean destinationPathIsNull = destination == null;
379
    if (destinationPathIsNull) 
380
      return "Invalid drop location.";
381

    
382
    //Test 2.
383
    DefaultMutableTreeNode node = (DefaultMutableTreeNode) destination.getLastPathComponent();
384
    if ( !node.getAllowsChildren() )
385
      return "This node does not allow children";
386

    
387
    if (destination.equals(dropper))
388
      return "Destination cannot be same as source";
389

    
390
    //Test 3.
391
    /* if ( dropper.isDescendant(destination)) 
392
       return "Destination node cannot be a descendant.";
393

394
    //Test 4.
395
    if ( dropper.getParentPath().equals(destination)) 
396
       return "Destination node cannot be a parent."; */
397

    
398
    return null;
399
  }
400

    
401
        /**
402
         * @param arg0
403
         * @return
404
         */
405
        public boolean addOrderListener(ITocOrderListener arg0) {
406
                return m_Listeners.add(arg0);
407
        }
408
        /**
409
         * @param arg0
410
         * @return
411
         */
412
        public boolean removeOrderListener(ITocOrderListener arg0) {
413
                return m_Listeners.remove(arg0);
414
        }
415
        private void callListeners(int oldPos, int newPos,FLayers lpd)
416
        {
417
                for (int i=0; i < m_Listeners.size(); i++)
418
                {
419
                        ITocOrderListener listener = (ITocOrderListener) m_Listeners.get(i);
420
                        listener.orderChanged(oldPos, newPos,lpd);
421
                }
422
        }
423
        
424
  private void callListeners(FLayers lpo,FLayers lpd,FLayer ls){
425
          for (int i=0; i < m_Listeners.size(); i++)
426
                {
427
                        ITocOrderListener listener = (ITocOrderListener) m_Listeners.get(i);
428
                        listener.parentChanged(lpo,lpd,ls);
429
                }
430
  }
431

    
432
} //end of DnDJTree