Statistics
| Revision:

svn-gvsig-desktop / tags / v10_RC2c / applications / appgvSIG / src / com / iver / cit / gvsig / gui / toc / DnDJTree.java @ 8745

History | View | Annotate | Download (19.3 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.Component;
63
import java.awt.Cursor;
64
import java.awt.Point;
65
import java.awt.datatransfer.Transferable;
66
import java.awt.datatransfer.UnsupportedFlavorException;
67
import java.awt.dnd.DnDConstants;
68
import java.awt.dnd.DragGestureEvent;
69
import java.awt.dnd.DragGestureListener;
70
import java.awt.dnd.DragGestureRecognizer;
71
import java.awt.dnd.DragSource;
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.TreeNode;
94
import javax.swing.tree.TreePath;
95

    
96
import com.iver.andami.PluginServices;
97
import com.iver.cit.gvsig.fmap.layers.FLayer;
98
import com.iver.cit.gvsig.fmap.layers.FLayers;
99
import com.iver.cit.gvsig.gui.View;
100

    
101
public class DnDJTree extends JTree
102
                  implements TreeSelectionListener, 
103
                  DragGestureListener, DropTargetListener,
104
                  DragSourceListener {
105

    
106
  protected ArrayList m_Listeners = new ArrayList();
107
  
108
  private static DnDJTree oDnDtocOrigin = null;
109
  private static DnDJTree oDnDtocDestination = null;
110
  /** Stores the parent Frame of the component */
111
  // private Frame Parent = null;
112

    
113
  /** Stores the selected node info */
114
  protected TreePath SelectedTreePath = null;
115
  protected DefaultMutableTreeNode SelectedNode = null;
116

    
117
  /** Variables needed for DnD */
118
  private DragSource dragSource = null;
119
  //private DragSourceContext dragSourceContext = null;
120
  private DropTarget dropTarget;
121
  //private ArrayList treeListeners=new ArrayList();
122
  //private ArrayList dropListeners=new ArrayList();
123
 // private TreeModel model1;
124
  /** Constructor 
125
  @param root The root node of the tree
126
  @param parent Parent JFrame of the JTree */
127
  public DnDJTree(TreeModel treeModel) {
128
    super(treeModel);
129
    // Parent = parent;
130

    
131
    //addTreeSelectionListener(this);
132

    
133
                /* ********************** CHANGED ********************** */
134
    dragSource = DragSource.getDefaultDragSource() ;
135
                /* ****************** END OF CHANGE ******************** */
136
    
137
    DragGestureRecognizer dgr = 
138
      dragSource.createDefaultDragGestureRecognizer(
139
        this,                             //DragSource
140
        DnDConstants.ACTION_COPY_OR_MOVE, //specifies valid actions
141
        this                              //DragGestureListener
142
      );
143

    
144

    
145
    /* Eliminates right mouse clicks as valid actions - useful especially
146
     * if you implement a JPopupMenu for the JTree
147
     */
148
    dgr.setSourceActions(dgr.getSourceActions() & ~InputEvent.BUTTON3_MASK);
149

    
150
    /* First argument:  Component to associate the target with
151
     * Second argument: DropTargetListener 
152
    */
153
    //DropTarget dropTarget = new DropTarget(this, this);
154
    setDropTarget();
155
  }
156
  public void invalidateListeners(){
157
          removeDropListener();
158
          removeTreeListener();
159
  }
160
  private void addDropListener(){
161
          dropTarget= new DropTarget(this, this); 
162
  }
163
  private void removeDropListener(){
164
          dropTarget=null;
165
  }
166
  private void addTreeListener(){
167
          addTreeSelectionListener(this);
168
  }
169
  private void removeTreeListener(){
170
          removeTreeSelectionListener(this);
171
  }
172
  public void setDropTarget(){
173
      // TODO: COMENTADO POR FJP
174
          /* com.iver.andami.ui.mdiManager.View[] views=PluginServices.getMDIManager().getAllViews();
175
          for(int i=0;i<views.length;i++){
176
                  if (views[i] instanceof View){
177
                         // model1=((View)views[i]).getTOC().getTree().getModel();
178
                          ((View)views[i]).getTOC().getTree().removeTreeListener();
179
                          ((View)views[i]).getTOC().getTree().addTreeListener();
180
                          ((View)views[i]).getTOC().getTree().removeDropListener();
181
                          ((View)views[i]).getTOC().getTree().addDropListener();
182
                  } */
183
                  addTreeListener();
184
                  addDropListener();
185
          // }
186
         ////////// new DropTarget(this, this);
187
  }
188
  /** Returns The selected node */
189
  public DefaultMutableTreeNode getSelectedNode() {
190
    return SelectedNode;
191
  }
192

    
193
  ///////////////////////// Interface stuff ////////////////////
194

    
195

    
196
  /** DragGestureListener interface method */
197
  public void dragGestureRecognized(DragGestureEvent e) {
198
    //Get the selected node
199
    DefaultMutableTreeNode dragNode = getSelectedNode();
200
    if (dragNode != null) {
201

    
202
      
203
      if (!(dragNode.getUserObject() instanceof Transferable)) return;
204
      
205
//    Get the Transferable Object
206
      Transferable transferable = (Transferable) dragNode.getUserObject();
207
      
208
                        /* ********************** CHANGED ********************** */
209

    
210
      //Select the appropriate cursor;
211
      // Cursor cursor = DragSource.DefaultCopyNoDrop;
212
      int action = e.getDragAction();
213
      /* if (action == DnDConstants.ACTION_MOVE) 
214
        cursor = DragSource.DefaultMoveDrop; */
215
        
216
        
217
      //In fact the cursor is set to NoDrop because once an action is rejected
218
      // by a dropTarget, the dragSourceListener are no more invoked.
219
      // Setting the cursor to no drop by default is so more logical, because 
220
      // when the drop is accepted by a component, then the cursor is changed by the
221
      // dropActionChanged of the default DragSource.
222
                        /* ****************** END OF CHANGE ******************** */
223
   
224
      //begin the drag
225
      oDnDtocOrigin = this;
226
      dragSource.startDrag(e, null, transferable, this);
227
    }
228
  }
229

    
230
  /** DragSourceListener interface method */
231
  public void dragDropEnd(DragSourceDropEvent dsde) {
232
  }
233

    
234
  /** DragSourceListener interface method */
235
  public void dragEnter(DragSourceDragEvent dsde) {
236
                /* ********************** CHANGED ********************** */
237
      // System.err.println("dragOver" + dsde.getDragSourceContext().getComponent());
238
      
239
                /* ****************** END OF CHANGE ******************** */
240
  }
241

    
242
  /** DragSourceListener interface method */
243
  public void dragOver(DragSourceDragEvent dsde) {
244
                /* ********************** CHANGED ********************** */
245
      // System.err.println("dragOver" + dsde.getDragSourceContext().getComponent());
246
                /* ****************** END OF CHANGE ******************** */
247
  }
248

    
249
  /** DragSourceListener interface method */
250
  public void dropActionChanged(DragSourceDragEvent dsde) {
251
  }
252

    
253
  /** DragSourceListener interface method */
254
  public void dragExit(DragSourceEvent dsde) {
255
  }
256
  
257
  /** DropTargetListener interface method - What we do when drag is released */
258
  public void drop(DropTargetDropEvent e) {
259
    try {
260
      Transferable tr = e.getTransferable();
261
      //flavor not supported, reject drop
262
      if (!tr.isDataFlavorSupported( TocItemBranch.INFO_FLAVOR)) e.rejectDrop();
263
      //cast into appropriate data type
264
      TocItemBranch childInfo = 
265
        (TocItemBranch) tr.getTransferData( TocItemBranch.INFO_FLAVOR ); 
266
      //get new parent node
267
      Point loc = e.getLocation();
268
      TreePath destinationPath = getPathForLocation(loc.x, loc.y);
269

    
270
      final String msg = testDropTarget(destinationPath, SelectedTreePath);
271
      if (msg != null) {
272
          /* if (testSameComponent())
273
          { */
274
              e.rejectDrop();
275
              SwingUtilities.invokeLater(new Runnable() {
276
                  public void run() {
277
                      System.err.println(msg);
278
                  }
279
              });           
280
              return;
281
          /* }
282
          else
283
          {
284
              // TODO: Por ahora solo dejamos mover, no copiar
285
              // TODO: ?Y qu? pasa si la vista a la que vamos
286
              // no tiene la misma proyecci?n? MEJOR DESHABILITO ESTO POR AHORA
287
              if (e.getDropAction() == DnDConstants.ACTION_MOVE)
288
                  dropRoot(SelectedNode);
289
              else
290
                  e.rejectDrop();
291
              return;
292
          } */
293
      }
294
      if (!testSameComponent(e))
295
      {
296
          e.rejectDrop();
297
          return;
298
      }
299
      int oldPos,newPos;
300
          //boolean isContainer=false;
301

    
302
          DefaultMutableTreeNode nodoTocado =
303
        (DefaultMutableTreeNode) destinationPath.getLastPathComponent(); 
304
          //        get old parent node
305
      DefaultMutableTreeNode oldParent = (DefaultMutableTreeNode) getSelectedNode().getParent();
306
      if (nodoTocado.getParent().equals(getSelectedNode())){
307
              return;
308
      }
309
      //oldParent.setUserObject(new TocItemBranch(((TocItemBranch)getSelectedNode().getUserObject()).getLayer().getParentLayer()));
310
          oldPos = oldParent.getIndex(getSelectedNode());
311
          // Para no tener en cuenta los nodos de s?mbolos:
312
      if (!(nodoTocado.getUserObject() instanceof TocItemBranch)){
313
                      nodoTocado = (DefaultMutableTreeNode) nodoTocado.getParent();
314
      }
315
      
316
      ///posActual = oldParent.getIndex(getSelectedNode());
317
      //Destino
318
          DefaultMutableTreeNode destParent=null;
319
          
320
          if (((TocItemBranch)nodoTocado.getUserObject()).getLayer() instanceof FLayers){
321
                  //isContainer=true;
322
                  newPos=0;
323
                  destParent=nodoTocado;
324
      }else{//Si donde se deja la capa seleccionada no es un contenedor de capas.
325
                destParent= (DefaultMutableTreeNode)nodoTocado.getParent();
326
        newPos=destParent.getIndex(nodoTocado);
327
      }
328
          
329
      
330
      
331

    
332
      int action = e.getDropAction();
333
      boolean copyAction = (action == DnDConstants.ACTION_COPY);
334

    
335
      //make new child node
336
      DefaultMutableTreeNode newChild = new DefaultMutableTreeNode(childInfo);
337
          if (getSelectedNode().getAllowsChildren()){
338
                  int childs=getSelectedNode().getChildCount();
339
                  
340
                  for (int i=0;i<childs;i++){
341
                          newChild.add((MutableTreeNode)getSelectedNode().getChildAt(0));
342
                  }
343
          }
344
          
345
          try { 
346
        if (!copyAction){
347
                oldParent.remove(getSelectedNode());
348
            destParent.insert(newChild,newPos);
349
            // newParent.add(newChild);
350
        }
351
        if (copyAction) e.acceptDrop (DnDConstants.ACTION_COPY);
352
        else e.acceptDrop (DnDConstants.ACTION_MOVE);
353
      }
354
      catch (java.lang.IllegalStateException ils) {
355
        e.rejectDrop();
356
      }
357
          
358
      e.getDropTargetContext().dropComplete(true);
359
      
360
      //expand nodes appropriately - this probably isnt the best way...
361
      
362
      // TODO: COMENTADO POR FJP
363
      /* com.iver.andami.ui.mdiManager.View[] views=PluginServices.getMDIManager().getAllViews();
364
          for(int i=0;i<views.length;i++){
365
                  if (views[i] instanceof View){
366
                          ((DefaultTreeModel)((View)views[i]).getTOC().getTree().getModel()).reload(oldParent);
367
                  }
368
          } */
369
      
370
      
371
      
372
     // ((DefaultTreeModel)model1).reload(oldParent);
373
      DefaultTreeModel model = (DefaultTreeModel) getModel();
374
          model.reload(destParent);
375
          FLayers lpo=null;
376
          FLayers lpd=null;
377
          
378
          if (oldParent.getUserObject() instanceof TocItemBranch){
379
          lpo=(FLayers)((TocItemBranch)oldParent.getUserObject()).getLayer();
380
          //lpd=(FLayers)((TocItemBranch)destParent.getUserObject()).getLayer();
381
          }/*else if (((TocItemBranch)nodoTocado.getUserObject()).getLayer().getParentLayer()!=null){
382
                  lpo=((TocItemBranch)nodoTocado.getUserObject()).getLayer().getParentLayer();
383
          }*/else{
384
                  lpo=(FLayers)((TocItemBranch)getSelectedNode().getUserObject()).getLayer().getParentLayer();
385
          }
386
                  if (destParent.getUserObject() instanceof TocItemBranch){
387
                  lpd=(FLayers)((TocItemBranch)destParent.getUserObject()).getLayer();
388
                  }else{
389
                  lpd=((TocItemBranch)nodoTocado.getUserObject()).getLayer().getParentLayer();
390
                  }
391
          
392
          
393
          if (destParent.equals(oldParent)){
394
                  callListeners(oldPos,newPos,lpd);
395
          }else{
396
                  callListeners(lpo,lpd,((TocItemBranch)newChild.getUserObject()).getLayer());
397
          }
398
          }
399
        
400
    catch (IOException io) { e.rejectDrop(); }
401
    catch (UnsupportedFlavorException ufe) {e.rejectDrop();}
402
  } //end of method
403
public void dropRoot(TreeNode tn){
404
        int oldPos,newPos;
405
        DefaultMutableTreeNode nodoTocado =
406
                (DefaultMutableTreeNode) tn; 
407
                  //        get old parent node
408
            if (getSelectedNode()==null)return;  
409
                DefaultMutableTreeNode oldParent = (DefaultMutableTreeNode) getSelectedNode().getParent();
410
                  if (oldParent!=null){
411
              oldPos = oldParent.getIndex(getSelectedNode());
412
              //Destino
413
                  DefaultMutableTreeNode destParent=null;
414
                  newPos=0;
415
                  destParent=nodoTocado;
416
        
417
              //make new child node
418
              DefaultMutableTreeNode newChild = (DefaultMutableTreeNode)getSelectedNode().clone();
419
              oldParent.remove(getSelectedNode());
420
              destParent.insert(newChild,newPos);
421
             
422
              com.iver.andami.ui.mdiManager.IWindow[] views=PluginServices.getMDIManager().getAllWindows();
423
                  for(int i=0;i<views.length;i++){
424
                          if (views[i] instanceof View){
425
                                  ((DefaultTreeModel)((View)views[i]).getTOC().getTree().getModel()).reload(oldParent);
426
                          }
427
                  }
428
             // ((DefaultTreeModel)model1).reload(oldParent);
429
              DefaultTreeModel model = (DefaultTreeModel) getModel();
430
                  model.reload(destParent);
431
                  FLayers lpo=null;
432
                  FLayers lpd=null;
433
                  
434
                  lpo=(FLayers)((TocItemBranch)getSelectedNode().getUserObject()).getLayer().getParentLayer();
435
                  for(int i=0;i<views.length;i++){
436
                          if (views[i] instanceof View){
437
                                  if (((View)views[i]).getTOC().getTree().equals(this)){
438
                                          lpd= ((View)views[i]).getMapControl().getMapContext().getLayers();
439
                                  }
440
                          }
441
                  }
442
                  if (destParent.equals(oldParent)){
443
                          callListeners(oldPos,newPos,lpd);
444
                  }else{
445
                          callListeners(lpo,lpd,((TocItemBranch)newChild.getUserObject()).getLayer());
446
                  }
447
                  }
448
        }
449

    
450
  /** DropTaregetListener interface method */
451
  public void dragEnter(DropTargetDragEvent e) {
452
  }
453

    
454
  /** DropTaregetListener interface method */
455
  public void dragExit(DropTargetEvent e) { 
456
  }
457

    
458
  /** DropTaregetListener interface method */
459
  public void dragOver(DropTargetDragEvent e) {
460
                /* ********************** CHANGED ********************** */
461
    //set cursor location. Needed in setCursor method
462
    Point cursorLocationBis = e.getLocation();
463
        TreePath destinationPath = 
464
      getPathForLocation(cursorLocationBis.x, cursorLocationBis.y);
465

    
466

    
467
    // if destination path is okay accept drop...
468
    
469
    if (testSameComponent(e))
470
    {
471
        String msg = testDropTarget(destinationPath, SelectedTreePath);
472
        if ( msg == null) {        
473
            e.acceptDrag(DnDConstants.ACTION_MOVE) ;
474
            return;
475
        }
476
            
477
    }
478
    // ...otherwise reject drop
479
    // else {
480
        // System.err.println(e.getDropTargetContext().getComponent());
481
        
482
        // if (testSameComponent(e))
483
            e.rejectDrag() ;
484
        /* else 
485
            e.acceptDrag(DnDConstants.ACTION_MOVE); */
486
    // }
487
                /* ****************** END OF CHANGE ******************** */
488
  }
489

    
490
  /** DropTaregetListener interface method */
491
  public void dropActionChanged(DropTargetDragEvent e) {
492
  }
493
  private void setSelectedNode(DefaultMutableTreeNode smtn){
494
          if (smtn!=null)
495
          SelectedNode=smtn;
496
  }
497

    
498
  /** TreeSelectionListener - sets selected node */
499
  public void valueChanged(TreeSelectionEvent evt) {
500
    SelectedTreePath = evt.getNewLeadSelectionPath();
501
    /* com.iver.andami.ui.mdiManager.View[] views=PluginServices.getMDIManager().getAllViews();
502
          for(int i=0;i<views.length;i++){
503
                  if (views[i] instanceof View){
504
                          if (SelectedTreePath == null) {
505
                                ((View)views[i]).getTOC().getTree().setSelectedNode(null);
506
                          }else{
507
                                   ((View)views[i]).getTOC().getTree().setSelectedNode((DefaultMutableTreeNode)SelectedTreePath.getLastPathComponent());
508
                          }
509
                  }
510
          } */
511
          if (SelectedTreePath == null){
512
                  setSelectedNode(null);
513
          }else{
514
                  setSelectedNode((DefaultMutableTreeNode)SelectedTreePath.getLastPathComponent());
515
          }
516
  }
517

    
518
  /** Convenience method to test whether drop location is valid
519
  @param destination The destination path 
520
  @param dropper The path for the node to be dropped
521
  @return null if no problems, otherwise an explanation
522
  */
523
  private String testDropTarget(TreePath destination, TreePath dropper) {
524
    //Typical Tests for dropping
525
 
526
    //Test 1.
527
    boolean destinationPathIsNull = destination == null;
528
    if (destinationPathIsNull) 
529
      return "Invalid drop location.";
530

    
531
    //Test 2.
532
    DefaultMutableTreeNode node = (DefaultMutableTreeNode) destination.getLastPathComponent();
533
    if ( !node.getAllowsChildren() )
534
      return "This node does not allow children";
535

    
536
    if (destination.equals(dropper))
537
      return "Destination cannot be same as source";
538

    
539
    //Test 3.
540
    /* if ( dropper.isDescendant(destination)) 
541
       return "Destination node cannot be a descendant.";
542

543
    //Test 4.
544
    if ( dropper.getParentPath().equals(destination)) 
545
       return "Destination node cannot be a parent."; */
546

    
547
    return null;
548
  }
549

    
550
  private boolean testSameComponent(DropTargetEvent e)
551
  {
552
      oDnDtocDestination = this;
553
      return (oDnDtocOrigin == oDnDtocDestination);
554
  }
555
        /**
556
         * @param arg0
557
         * @return
558
         */
559
        public boolean addOrderListener(ITocOrderListener arg0) {
560
                return m_Listeners.add(arg0);
561
        }
562
        /**
563
         * @param arg0
564
         * @return
565
         */
566
        public boolean removeOrderListener(ITocOrderListener arg0) {
567
                return m_Listeners.remove(arg0);
568
        }
569
        private void callListeners(int oldPos, int newPos,FLayers lpd)
570
        {
571
                for (int i=0; i < m_Listeners.size(); i++)
572
                {
573
                        ITocOrderListener listener = (ITocOrderListener) m_Listeners.get(i);
574
                        listener.orderChanged(oldPos, newPos,lpd);
575
                }
576
        }
577
        
578
  private void callListeners(FLayers lpo,FLayers lpd,FLayer ls){
579
          for (int i=0; i < m_Listeners.size(); i++)
580
                {
581
                        ITocOrderListener listener = (ITocOrderListener) m_Listeners.get(i);
582
                        listener.parentChanged(lpo,lpd,ls);
583
                }
584
  }
585

    
586
} //end of DnDJTree