Statistics
| Revision:

root / branches / v2_0_0_prep / applications / appgvSIG / src / org / gvsig / app / project / documents / view / toc / DnDJTree.java @ 31496

History | View | Annotate | Download (19.4 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 org.gvsig.app.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.dnd.MouseDragGestureRecognizer;
80
import java.awt.event.InputEvent;
81
import java.awt.event.MouseEvent;
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 org.gvsig.andami.PluginServices;
97
import org.gvsig.app.project.documents.view.gui.DefaultViewPanel;
98
import org.gvsig.fmap.mapcontext.layers.FLayer;
99
import org.gvsig.fmap.mapcontext.layers.FLayers;
100

    
101

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

    
107
  protected ArrayList m_Listeners = new ArrayList();
108

    
109
  private static DnDJTree oDnDtocOrigin = null;
110
  private static DnDJTree oDnDtocDestination = null;
111
  /** Stores the parent Frame of the component */
112
  // private Frame Parent = null;
113

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

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

    
132
    //addTreeSelectionListener(this);
133

    
134
                /* ********************** CHANGED ********************** */
135
    dragSource = DragSource.getDefaultDragSource() ;
136
                /* ****************** END OF CHANGE ******************** */
137

    
138
    DragGestureRecognizer dgr =
139
      dragSource.createDefaultDragGestureRecognizer(
140
        this,                             //DragSource
141
        DnDConstants.ACTION_COPY_OR_MOVE, //specifies valid actions
142
        this                              //DragGestureListener
143
      );
144

    
145

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

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

    
194
  ///////////////////////// Interface stuff ////////////////////
195

    
196

    
197
  /** DragGestureListener interface method */
198
  public void dragGestureRecognized(DragGestureEvent e) {
199
          if (((MouseEvent)((MouseDragGestureRecognizer)e.getSource()).getTriggerEvent()).getButton()==MouseEvent.BUTTON3){
200
                  return;
201
          }
202
    //Get the selected node
203
    DefaultMutableTreeNode dragNode = getSelectedNode();
204
    if (dragNode != null) {
205

    
206

    
207
      if (!(dragNode.getUserObject() instanceof Transferable)) {
208
                return;
209
        }
210

    
211
//    Get the Transferable Object
212
      Transferable transferable = (Transferable) dragNode.getUserObject();
213

    
214
                        /* ********************** CHANGED ********************** */
215

    
216
      //Select the appropriate cursor;
217
      // Cursor cursor = DragSource.DefaultCopyNoDrop;
218
      int action = e.getDragAction();
219
      /* if (action == DnDConstants.ACTION_MOVE)
220
        cursor = DragSource.DefaultMoveDrop; */
221

    
222

    
223
      //In fact the cursor is set to NoDrop because once an action is rejected
224
      // by a dropTarget, the dragSourceListener are no more invoked.
225
      // Setting the cursor to no drop by default is so more logical, because
226
      // when the drop is accepted by a component, then the cursor is changed by the
227
      // dropActionChanged of the default DragSource.
228
                        /* ****************** END OF CHANGE ******************** */
229

    
230
      //begin the drag
231
      oDnDtocOrigin = this;
232
      dragSource.startDrag(e, null, transferable, this);
233
    }
234
  }
235

    
236
  /** DragSourceListener interface method */
237
  public void dragDropEnd(DragSourceDropEvent dsde) {
238
  }
239

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

    
245
                /* ****************** END OF CHANGE ******************** */
246
  }
247

    
248
  /** DragSourceListener interface method */
249
  public void dragOver(DragSourceDragEvent dsde) {
250
                /* ********************** CHANGED ********************** */
251
      // System.err.println("dragOver" + dsde.getDragSourceContext().getComponent());
252
                /* ****************** END OF CHANGE ******************** */
253
  }
254

    
255
  /** DragSourceListener interface method */
256
  public void dropActionChanged(DragSourceDragEvent dsde) {
257
  }
258

    
259
  /** DragSourceListener interface method */
260
  public void dragExit(DragSourceEvent dsde) {
261
  }
262

    
263
  /** DropTargetListener interface method - What we do when drag is released */
264
  public void drop(DropTargetDropEvent e) {
265
    try {
266
      Transferable tr = e.getTransferable();
267
      //flavor not supported, reject drop
268
      if (!tr.isDataFlavorSupported( TocItemBranch.INFO_FLAVOR)) {
269
                e.rejectDrop();
270
        }
271
      //cast into appropriate data type
272
      TocItemBranch childInfo =
273
        (TocItemBranch) tr.getTransferData( TocItemBranch.INFO_FLAVOR );
274
      //get new parent node
275
      Point loc = e.getLocation();
276
      TreePath destinationPath = getPathForLocation(loc.x, loc.y);
277

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

    
310
          DefaultMutableTreeNode nodoTocado =
311
        (DefaultMutableTreeNode) destinationPath.getLastPathComponent();
312
          //        get old parent node
313
      DefaultMutableTreeNode oldParent = (DefaultMutableTreeNode) getSelectedNode().getParent();
314
      if (nodoTocado.getParent().equals(getSelectedNode())){
315
              return;
316
      }
317
      //oldParent.setUserObject(new TocItemBranch(((TocItemBranch)getSelectedNode().getUserObject()).getLayer().getParentLayer()));
318
          if (oldParent==null) {
319
                return;
320
        }
321
      oldPos = oldParent.getIndex(getSelectedNode());
322
          // Para no tener en cuenta los nodos de s?mbolos:
323
      if (!(nodoTocado.getUserObject() instanceof TocItemBranch)){
324
                      nodoTocado = (DefaultMutableTreeNode) nodoTocado.getParent();
325
      }
326

    
327
      ///posActual = oldParent.getIndex(getSelectedNode());
328
      //Destino
329
          DefaultMutableTreeNode destParent=null;
330

    
331
          if (((TocItemBranch)nodoTocado.getUserObject()).getLayer() instanceof FLayers){
332
                  //isContainer=true;
333
                  newPos=0;
334
                  destParent=nodoTocado;
335
      }else{//Si donde se deja la capa seleccionada no es un contenedor de capas.
336
                destParent= (DefaultMutableTreeNode)nodoTocado.getParent();
337
        newPos=destParent.getIndex(nodoTocado);
338
      }
339

    
340

    
341

    
342

    
343
      int action = e.getDropAction();
344
      boolean copyAction = (action == DnDConstants.ACTION_COPY);
345

    
346
      //make new child node
347
      DefaultMutableTreeNode newChild = new DefaultMutableTreeNode(childInfo);
348
          if (getSelectedNode().getAllowsChildren()){
349
                  int childs=getSelectedNode().getChildCount();
350

    
351
                  for (int i=0;i<childs;i++){
352
                          newChild.add((MutableTreeNode)getSelectedNode().getChildAt(0));
353
                  }
354
          }
355

    
356
          try {
357
        if (!copyAction){
358
                oldParent.remove(getSelectedNode());
359
            destParent.insert(newChild,newPos);
360
            // newParent.add(newChild);
361
        }
362
        if (copyAction) {
363
                        e.acceptDrop (DnDConstants.ACTION_COPY);
364
                } else {
365
                        e.acceptDrop (DnDConstants.ACTION_MOVE);
366
                }
367
      }
368
      catch (java.lang.IllegalStateException ils) {
369
        e.rejectDrop();
370
      }
371

    
372
      e.getDropTargetContext().dropComplete(true);
373

    
374
      //expand nodes appropriately - this probably isnt the best way...
375

    
376
      // TODO: COMENTADO POR FJP
377
      /* com.iver.andami.ui.mdiManager.View[] views=PluginServices.getMDIManager().getAllViews();
378
          for(int i=0;i<views.length;i++){
379
                  if (views[i] instanceof View){
380
                          ((DefaultTreeModel)((View)views[i]).getTOC().getTree().getModel()).reload(oldParent);
381
                  }
382
          } */
383

    
384

    
385

    
386
     // ((DefaultTreeModel)model1).reload(oldParent);
387
      DefaultTreeModel model = (DefaultTreeModel) getModel();
388

    
389
          model.reload(getSelectedNode().getRoot());
390
          FLayers lpo=null;
391
          FLayers lpd=null;
392

    
393
          if (oldParent.getUserObject() instanceof TocItemBranch){
394
          lpo=(FLayers)((TocItemBranch)oldParent.getUserObject()).getLayer();
395
          //lpd=(FLayers)((TocItemBranch)destParent.getUserObject()).getLayer();
396
          }/*else if (((TocItemBranch)nodoTocado.getUserObject()).getLayer().getParentLayer()!=null){
397
                  lpo=((TocItemBranch)nodoTocado.getUserObject()).getLayer().getParentLayer();
398
          }*/else{
399
                  lpo=((TocItemBranch)getSelectedNode().getUserObject()).getLayer().getParentLayer();
400
          }
401
                  if (destParent.getUserObject() instanceof TocItemBranch){
402
                  lpd=(FLayers)((TocItemBranch)destParent.getUserObject()).getLayer();
403
                  }else{
404
                  lpd=((TocItemBranch)nodoTocado.getUserObject()).getLayer().getParentLayer();
405
                  }
406

    
407

    
408
          if (destParent.equals(oldParent)){
409
                  callListeners(oldPos,newPos,lpd);
410
          }else{
411
                  callListeners(lpo,lpd,((TocItemBranch)newChild.getUserObject()).getLayer());
412
          }
413
          }
414

    
415
    catch (IOException io) { e.rejectDrop(); }
416
    catch (UnsupportedFlavorException ufe) {e.rejectDrop();}
417
  } //end of method
418
public void dropRoot(TreeNode tn){
419
        int oldPos,newPos;
420
        DefaultMutableTreeNode nodoTocado =
421
                (DefaultMutableTreeNode) tn;
422
                  //        get old parent node
423
            if (getSelectedNode()==null) {
424
                        return;
425
                }
426
                DefaultMutableTreeNode oldParent = (DefaultMutableTreeNode) getSelectedNode().getParent();
427
                  if (oldParent!=null){
428
              oldPos = oldParent.getIndex(getSelectedNode());
429
              //Destino
430
                  DefaultMutableTreeNode destParent=null;
431
                  newPos=0;
432
                  destParent=nodoTocado;
433

    
434
              //make new child node
435
              DefaultMutableTreeNode newChild = (DefaultMutableTreeNode)getSelectedNode().clone();
436
              oldParent.remove(getSelectedNode());
437
              destParent.insert(newChild,newPos);
438

    
439
              org.gvsig.andami.ui.mdiManager.IWindow[] views=PluginServices.getMDIManager().getAllWindows();
440
                  for(int i=0;i<views.length;i++){
441
                          if (views[i] instanceof DefaultViewPanel){
442
                                  ((DefaultTreeModel)((DefaultViewPanel)views[i]).getTOC().getTree().getModel()).reload(oldParent);
443
                          }
444
                  }
445
             // ((DefaultTreeModel)model1).reload(oldParent);
446
              DefaultTreeModel model = (DefaultTreeModel) getModel();
447
                  model.reload(destParent);
448
                  FLayers lpo=null;
449
                  FLayers lpd=null;
450

    
451
                  lpo=((TocItemBranch)getSelectedNode().getUserObject()).getLayer().getParentLayer();
452
                  for(int i=0;i<views.length;i++){
453
                          if (views[i] instanceof DefaultViewPanel){
454
                                  if (((DefaultViewPanel)views[i]).getTOC().getTree().equals(this)){
455
                                          lpd= ((DefaultViewPanel)views[i]).getMapControl().getMapContext().getLayers();
456
                                  }
457
                          }
458
                  }
459
                  if (destParent.equals(oldParent)){
460
                          callListeners(oldPos,newPos,lpd);
461
                  }else{
462
                          callListeners(lpo,lpd,((TocItemBranch)newChild.getUserObject()).getLayer());
463
                  }
464
                  }
465
        }
466

    
467
  /** DropTaregetListener interface method */
468
  public void dragEnter(DropTargetDragEvent e) {
469
  }
470

    
471
  /** DropTaregetListener interface method */
472
  public void dragExit(DropTargetEvent e) {
473
  }
474

    
475
  /** DropTaregetListener interface method */
476
  public void dragOver(DropTargetDragEvent e) {
477
                /* ********************** CHANGED ********************** */
478
    //set cursor location. Needed in setCursor method
479
    Point cursorLocationBis = e.getLocation();
480
        TreePath destinationPath =
481
      getPathForLocation(cursorLocationBis.x, cursorLocationBis.y);
482

    
483

    
484
    // if destination path is okay accept drop...
485

    
486
    if (testSameComponent(e))
487
    {
488
        String msg = testDropTarget(destinationPath, SelectedTreePath);
489
        if ( msg == null) {
490
            e.acceptDrag(DnDConstants.ACTION_MOVE) ;
491
            return;
492
        }
493

    
494
    }
495
    // ...otherwise reject drop
496
    // else {
497
        // System.err.println(e.getDropTargetContext().getComponent());
498

    
499
        // if (testSameComponent(e))
500
            e.rejectDrag() ;
501
        /* else
502
            e.acceptDrag(DnDConstants.ACTION_MOVE); */
503
    // }
504
                /* ****************** END OF CHANGE ******************** */
505
  }
506

    
507
  /** DropTaregetListener interface method */
508
  public void dropActionChanged(DropTargetDragEvent e) {
509
  }
510
  private void setSelectedNode(DefaultMutableTreeNode smtn){
511
          if (smtn!=null) {
512
                SelectedNode=smtn;
513
        }
514
  }
515

    
516
  /** TreeSelectionListener - sets selected node */
517
  public void valueChanged(TreeSelectionEvent evt) {
518
    SelectedTreePath = evt.getNewLeadSelectionPath();
519
    /* com.iver.andami.ui.mdiManager.View[] views=PluginServices.getMDIManager().getAllViews();
520
          for(int i=0;i<views.length;i++){
521
                  if (views[i] instanceof View){
522
                          if (SelectedTreePath == null) {
523
                                ((View)views[i]).getTOC().getTree().setSelectedNode(null);
524
                          }else{
525
                                   ((View)views[i]).getTOC().getTree().setSelectedNode((DefaultMutableTreeNode)SelectedTreePath.getLastPathComponent());
526
                          }
527
                  }
528
          } */
529
          if (SelectedTreePath == null){
530
                  setSelectedNode(null);
531
          }else{
532
                  setSelectedNode((DefaultMutableTreeNode)SelectedTreePath.getLastPathComponent());
533
          }
534
  }
535

    
536
  /** Convenience method to test whether drop location is valid
537
  @param destination The destination path
538
  @param dropper The path for the node to be dropped
539
  @return null if no problems, otherwise an explanation
540
  */
541
  private String testDropTarget(TreePath destination, TreePath dropper) {
542
    //Typical Tests for dropping
543

    
544
    //Test 1.
545
    boolean destinationPathIsNull = destination == null;
546
    if (destinationPathIsNull) {
547
                return "Invalid drop location.";
548
        }
549

    
550
    //Test 2.
551
    DefaultMutableTreeNode node = (DefaultMutableTreeNode) destination.getLastPathComponent();
552
    if ( !node.getAllowsChildren() ) {
553
                return "This node does not allow children";
554
        }
555

    
556
    if (destination.equals(dropper)) {
557
                return "Destination cannot be same as source";
558
        }
559

    
560
    //Test 3.
561
    /* if ( dropper.isDescendant(destination))
562
       return "Destination node cannot be a descendant.";
563

564
    //Test 4.
565
    if ( dropper.getParentPath().equals(destination))
566
       return "Destination node cannot be a parent."; */
567

    
568
    return null;
569
  }
570

    
571
  private boolean testSameComponent(DropTargetEvent e)
572
  {
573
      oDnDtocDestination = this;
574
      return (oDnDtocOrigin == oDnDtocDestination);
575
  }
576
        /**
577
         * @param arg0
578
         * @return
579
         */
580
        public boolean addOrderListener(ITocOrderListener arg0) {
581
                return m_Listeners.add(arg0);
582
        }
583
        /**
584
         * @param arg0
585
         * @return
586
         */
587
        public boolean removeOrderListener(ITocOrderListener arg0) {
588
                return m_Listeners.remove(arg0);
589
        }
590
        private void callListeners(int oldPos, int newPos,FLayers lpd)
591
        {
592
                for (int i=0; i < m_Listeners.size(); i++)
593
                {
594
                        ITocOrderListener listener = (ITocOrderListener) m_Listeners.get(i);
595
                        listener.orderChanged(oldPos, newPos,lpd);
596
                }
597
        }
598

    
599
  private void callListeners(FLayers lpo,FLayers lpd,FLayer ls){
600
          for (int i=0; i < m_Listeners.size(); i++)
601
                {
602
                        ITocOrderListener listener = (ITocOrderListener) m_Listeners.get(i);
603
                        listener.parentChanged(lpo,lpd,ls);
604
                }
605
  }
606

    
607
} //end of DnDJTree