Statistics
| Revision:

svn-gvsig-desktop / branches / v10 / applications / appgvSIG / src / com / iver / cit / gvsig / project / documents / view / toc / DnDJTree.java @ 10656

History | View | Annotate | Download (19.2 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.project.documents.view.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.Point;
63
import java.awt.datatransfer.Transferable;
64
import java.awt.datatransfer.UnsupportedFlavorException;
65
import java.awt.dnd.DnDConstants;
66
import java.awt.dnd.DragGestureEvent;
67
import java.awt.dnd.DragGestureListener;
68
import java.awt.dnd.DragGestureRecognizer;
69
import java.awt.dnd.DragSource;
70
import java.awt.dnd.DragSourceDragEvent;
71
import java.awt.dnd.DragSourceDropEvent;
72
import java.awt.dnd.DragSourceEvent;
73
import java.awt.dnd.DragSourceListener;
74
import java.awt.dnd.DropTarget;
75
import java.awt.dnd.DropTargetDragEvent;
76
import java.awt.dnd.DropTargetDropEvent;
77
import java.awt.dnd.DropTargetEvent;
78
import java.awt.dnd.DropTargetListener;
79
import java.awt.event.InputEvent;
80
import java.io.IOException;
81
import java.util.ArrayList;
82

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

    
94
import com.iver.andami.PluginServices;
95
import com.iver.cit.gvsig.fmap.layers.FLayer;
96
import com.iver.cit.gvsig.fmap.layers.FLayers;
97
import com.iver.cit.gvsig.project.documents.view.gui.View;
98

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

    
104
  protected ArrayList m_Listeners = new ArrayList();
105

    
106
  private static DnDJTree oDnDtocOrigin = null;
107
  private static DnDJTree oDnDtocDestination = null;
108
  /** Stores the parent Frame of the component */
109
  // private Frame Parent = null;
110

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

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

    
129
    //addTreeSelectionListener(this);
130

    
131
                /* ********************** CHANGED ********************** */
132
    dragSource = DragSource.getDefaultDragSource() ;
133
                /* ****************** END OF CHANGE ******************** */
134

    
135
    DragGestureRecognizer dgr =
136
      dragSource.createDefaultDragGestureRecognizer(
137
        this,                             //DragSource
138
        DnDConstants.ACTION_COPY_OR_MOVE, //specifies valid actions
139
        this                              //DragGestureListener
140
      );
141

    
142

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

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

    
191
  ///////////////////////// Interface stuff ////////////////////
192

    
193

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

    
200

    
201
      if (!(dragNode.getUserObject() instanceof Transferable)) return;
202

    
203
//    Get the Transferable Object
204
      Transferable transferable = (Transferable) dragNode.getUserObject();
205

    
206
                        /* ********************** CHANGED ********************** */
207

    
208
      //Select the appropriate cursor;
209
      // Cursor cursor = DragSource.DefaultCopyNoDrop;
210
      int action = e.getDragAction();
211
      /* if (action == DnDConstants.ACTION_MOVE)
212
        cursor = DragSource.DefaultMoveDrop; */
213

    
214

    
215
      //In fact the cursor is set to NoDrop because once an action is rejected
216
      // by a dropTarget, the dragSourceListener are no more invoked.
217
      // Setting the cursor to no drop by default is so more logical, because
218
      // when the drop is accepted by a component, then the cursor is changed by the
219
      // dropActionChanged of the default DragSource.
220
                        /* ****************** END OF CHANGE ******************** */
221

    
222
      //begin the drag
223
      oDnDtocOrigin = this;
224
      dragSource.startDrag(e, null, transferable, this);
225
    }
226
  }
227

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

    
232
  /** DragSourceListener interface method */
233
  public void dragEnter(DragSourceDragEvent dsde) {
234
                /* ********************** CHANGED ********************** */
235
      // System.err.println("dragOver" + dsde.getDragSourceContext().getComponent());
236

    
237
                /* ****************** END OF CHANGE ******************** */
238
  }
239

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

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

    
251
  /** DragSourceListener interface method */
252
  public void dragExit(DragSourceEvent dsde) {
253
  }
254

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

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

    
300
          DefaultMutableTreeNode nodoTocado =
301
        (DefaultMutableTreeNode) destinationPath.getLastPathComponent();
302
          //        get old parent node
303
      DefaultMutableTreeNode oldParent = (DefaultMutableTreeNode) getSelectedNode().getParent();
304
      if (nodoTocado.getParent().equals(getSelectedNode())){
305
              return;
306
      }
307
      //oldParent.setUserObject(new TocItemBranch(((TocItemBranch)getSelectedNode().getUserObject()).getLayer().getParentLayer()));
308
          oldPos = oldParent.getIndex(getSelectedNode());
309
          // Para no tener en cuenta los nodos de s?mbolos:
310
      if (!(nodoTocado.getUserObject() instanceof TocItemBranch)){
311
                      nodoTocado = (DefaultMutableTreeNode) nodoTocado.getParent();
312
      }
313

    
314
      ///posActual = oldParent.getIndex(getSelectedNode());
315
      //Destino
316
          DefaultMutableTreeNode destParent=null;
317

    
318
          if (((TocItemBranch)nodoTocado.getUserObject()).getLayer() instanceof FLayers){
319
                  //isContainer=true;
320
                  newPos=0;
321
                  destParent=nodoTocado;
322
      }else{//Si donde se deja la capa seleccionada no es un contenedor de capas.
323
                destParent= (DefaultMutableTreeNode)nodoTocado.getParent();
324
        newPos=destParent.getIndex(nodoTocado);
325
      }
326

    
327

    
328

    
329

    
330
      int action = e.getDropAction();
331
      boolean copyAction = (action == DnDConstants.ACTION_COPY);
332

    
333
      //make new child node
334
      DefaultMutableTreeNode newChild = new DefaultMutableTreeNode(childInfo);
335
          if (getSelectedNode().getAllowsChildren()){
336
                  int childs=getSelectedNode().getChildCount();
337

    
338
                  for (int i=0;i<childs;i++){
339
                          newChild.add((MutableTreeNode)getSelectedNode().getChildAt(0));
340
                  }
341
          }
342

    
343
          try {
344
        if (!copyAction){
345
                oldParent.remove(getSelectedNode());
346
            destParent.insert(newChild,newPos);
347
            // newParent.add(newChild);
348
        }
349
        if (copyAction) e.acceptDrop (DnDConstants.ACTION_COPY);
350
        else e.acceptDrop (DnDConstants.ACTION_MOVE);
351
      }
352
      catch (java.lang.IllegalStateException ils) {
353
        e.rejectDrop();
354
      }
355

    
356
      e.getDropTargetContext().dropComplete(true);
357

    
358
      //expand nodes appropriately - this probably isnt the best way...
359

    
360
      // TODO: COMENTADO POR FJP
361
      /* com.iver.andami.ui.mdiManager.View[] views=PluginServices.getMDIManager().getAllViews();
362
          for(int i=0;i<views.length;i++){
363
                  if (views[i] instanceof View){
364
                          ((DefaultTreeModel)((View)views[i]).getTOC().getTree().getModel()).reload(oldParent);
365
                  }
366
          } */
367

    
368

    
369

    
370
     // ((DefaultTreeModel)model1).reload(oldParent);
371
      DefaultTreeModel model = (DefaultTreeModel) getModel();
372
          model.reload(destParent);
373
          FLayers lpo=null;
374
          FLayers lpd=null;
375

    
376
          if (oldParent.getUserObject() instanceof TocItemBranch){
377
          lpo=(FLayers)((TocItemBranch)oldParent.getUserObject()).getLayer();
378
          //lpd=(FLayers)((TocItemBranch)destParent.getUserObject()).getLayer();
379
          }/*else if (((TocItemBranch)nodoTocado.getUserObject()).getLayer().getParentLayer()!=null){
380
                  lpo=((TocItemBranch)nodoTocado.getUserObject()).getLayer().getParentLayer();
381
          }*/else{
382
                  lpo=(FLayers)((TocItemBranch)getSelectedNode().getUserObject()).getLayer().getParentLayer();
383
          }
384
                  if (destParent.getUserObject() instanceof TocItemBranch){
385
                  lpd=(FLayers)((TocItemBranch)destParent.getUserObject()).getLayer();
386
                  }else{
387
                  lpd=((TocItemBranch)nodoTocado.getUserObject()).getLayer().getParentLayer();
388
                  }
389

    
390

    
391
          if (destParent.equals(oldParent)){
392
                  callListeners(oldPos,newPos,lpd);
393
          }else{
394
                  callListeners(lpo,lpd,((TocItemBranch)newChild.getUserObject()).getLayer());
395
          }
396
          }
397

    
398
    catch (IOException io) { e.rejectDrop(); }
399
    catch (UnsupportedFlavorException ufe) {e.rejectDrop();}
400
  } //end of method
401
public void dropRoot(TreeNode tn){
402
        int oldPos,newPos;
403
        DefaultMutableTreeNode nodoTocado =
404
                (DefaultMutableTreeNode) tn;
405
                  //        get old parent node
406
            if (getSelectedNode()==null)return;
407
                DefaultMutableTreeNode oldParent = (DefaultMutableTreeNode) getSelectedNode().getParent();
408
                  if (oldParent!=null){
409
              oldPos = oldParent.getIndex(getSelectedNode());
410
              //Destino
411
                  DefaultMutableTreeNode destParent=null;
412
                  newPos=0;
413
                  destParent=nodoTocado;
414

    
415
              //make new child node
416
              DefaultMutableTreeNode newChild = (DefaultMutableTreeNode)getSelectedNode().clone();
417
              oldParent.remove(getSelectedNode());
418
              destParent.insert(newChild,newPos);
419

    
420
              com.iver.andami.ui.mdiManager.IWindow[] views=PluginServices.getMDIManager().getAllWindows();
421
                  for(int i=0;i<views.length;i++){
422
                          if (views[i] instanceof View){
423
                                  ((DefaultTreeModel)((View)views[i]).getTOC().getTree().getModel()).reload(oldParent);
424
                          }
425
                  }
426
             // ((DefaultTreeModel)model1).reload(oldParent);
427
              DefaultTreeModel model = (DefaultTreeModel) getModel();
428
                  model.reload(destParent);
429
                  FLayers lpo=null;
430
                  FLayers lpd=null;
431

    
432
                  lpo=(FLayers)((TocItemBranch)getSelectedNode().getUserObject()).getLayer().getParentLayer();
433
                  for(int i=0;i<views.length;i++){
434
                          if (views[i] instanceof View){
435
                                  if (((View)views[i]).getTOC().getTree().equals(this)){
436
                                          lpd= ((View)views[i]).getMapControl().getMapContext().getLayers();
437
                                  }
438
                          }
439
                  }
440
                  if (destParent.equals(oldParent)){
441
                          callListeners(oldPos,newPos,lpd);
442
                  }else{
443
                          callListeners(lpo,lpd,((TocItemBranch)newChild.getUserObject()).getLayer());
444
                  }
445
                  }
446
        }
447

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

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

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

    
464

    
465
    // if destination path is okay accept drop...
466

    
467
    if (testSameComponent(e))
468
    {
469
        String msg = testDropTarget(destinationPath, SelectedTreePath);
470
        if ( msg == null) {
471
            e.acceptDrag(DnDConstants.ACTION_MOVE) ;
472
            return;
473
        }
474

    
475
    }
476
    // ...otherwise reject drop
477
    // else {
478
        // System.err.println(e.getDropTargetContext().getComponent());
479

    
480
        // if (testSameComponent(e))
481
            e.rejectDrag() ;
482
        /* else
483
            e.acceptDrag(DnDConstants.ACTION_MOVE); */
484
    // }
485
                /* ****************** END OF CHANGE ******************** */
486
  }
487

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

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

    
516
  /** Convenience method to test whether drop location is valid
517
  @param destination The destination path
518
  @param dropper The path for the node to be dropped
519
  @return null if no problems, otherwise an explanation
520
  */
521
  private String testDropTarget(TreePath destination, TreePath dropper) {
522
    //Typical Tests for dropping
523

    
524
    //Test 1.
525
    boolean destinationPathIsNull = destination == null;
526
    if (destinationPathIsNull)
527
      return "Invalid drop location.";
528

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

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

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

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

    
545
    return null;
546
  }
547

    
548
  private boolean testSameComponent(DropTargetEvent e)
549
  {
550
      oDnDtocDestination = this;
551
      return (oDnDtocOrigin == oDnDtocDestination);
552
  }
553
        /**
554
         * @param arg0
555
         * @return
556
         */
557
        public boolean addOrderListener(ITocOrderListener arg0) {
558
                return m_Listeners.add(arg0);
559
        }
560
        /**
561
         * @param arg0
562
         * @return
563
         */
564
        public boolean removeOrderListener(ITocOrderListener arg0) {
565
                return m_Listeners.remove(arg0);
566
        }
567
        private void callListeners(int oldPos, int newPos,FLayers lpd)
568
        {
569
                lpd.getMapContext().clearAllCachingImageDrawnLayers();
570
                for (int i=0; i < m_Listeners.size(); i++)
571
                {
572
                        ITocOrderListener listener = (ITocOrderListener) m_Listeners.get(i);
573
                        listener.orderChanged(oldPos, newPos,lpd);
574
                }
575

    
576
        }
577

    
578
  private void callListeners(FLayers lpo,FLayers lpd,FLayer ls){
579
          lpo.getMapContext().clearAllCachingImageDrawnLayers();
580
          for (int i=0; i < m_Listeners.size(); i++)
581
                {
582
                        ITocOrderListener listener = (ITocOrderListener) m_Listeners.get(i);
583
                        listener.parentChanged(lpo,lpd,ls);
584
                }
585

    
586
  }
587

    
588
} //end of DnDJTree