Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.plugin / org.gvsig.app / org.gvsig.app.mainplugin / src / main / java / org / gvsig / app / project / documents / view / toc / DnDJTree.java @ 40596

History | View | Annotate | Download (19.2 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24

    
25
package org.gvsig.app.project.documents.view.toc;
26
/*
27
**  This is version II of DnDJTree. The first version allowed for what I
28
**  thought was a JDK oversight. However, we can set the cursor appropriately,
29
**  relative to whether the current cursor location is a valid drop target.
30
**
31
**  If this is your first time reading the source code. Just ignore the above
32
**  comment and ignore the "CHANGED" comments below. Otherwise, the
33
**  "CHANGED" comments will show where the code has changed.
34
**
35
**  Credit for finding this shortcoming in my code goes Laurent Hubert.
36
**  Thanks Laurent.
37
**
38
**  Rob. [ rkenworthy@hotmail.com ]
39
*/
40

    
41

    
42
import java.awt.Point;
43
import java.awt.datatransfer.Transferable;
44
import java.awt.datatransfer.UnsupportedFlavorException;
45
import java.awt.dnd.DnDConstants;
46
import java.awt.dnd.DragGestureEvent;
47
import java.awt.dnd.DragGestureListener;
48
import java.awt.dnd.DragGestureRecognizer;
49
import java.awt.dnd.DragSource;
50
import java.awt.dnd.DragSourceDragEvent;
51
import java.awt.dnd.DragSourceDropEvent;
52
import java.awt.dnd.DragSourceEvent;
53
import java.awt.dnd.DragSourceListener;
54
import java.awt.dnd.DropTarget;
55
import java.awt.dnd.DropTargetDragEvent;
56
import java.awt.dnd.DropTargetDropEvent;
57
import java.awt.dnd.DropTargetEvent;
58
import java.awt.dnd.DropTargetListener;
59
import java.awt.dnd.MouseDragGestureRecognizer;
60
import java.awt.event.InputEvent;
61
import java.awt.event.MouseEvent;
62
import java.io.IOException;
63
import java.util.ArrayList;
64

    
65
import javax.swing.JTree;
66
import javax.swing.SwingUtilities;
67
import javax.swing.event.TreeSelectionEvent;
68
import javax.swing.event.TreeSelectionListener;
69
import javax.swing.tree.DefaultMutableTreeNode;
70
import javax.swing.tree.DefaultTreeModel;
71
import javax.swing.tree.MutableTreeNode;
72
import javax.swing.tree.TreeModel;
73
import javax.swing.tree.TreeNode;
74
import javax.swing.tree.TreePath;
75

    
76
import org.gvsig.andami.PluginServices;
77
import org.gvsig.app.project.documents.view.gui.DefaultViewPanel;
78
import org.gvsig.fmap.mapcontext.layers.FLayer;
79
import org.gvsig.fmap.mapcontext.layers.FLayers;
80

    
81

    
82
public class DnDJTree extends JTree
83
                  implements TreeSelectionListener,
84
                  DragGestureListener, DropTargetListener,
85
                  DragSourceListener {
86

    
87
  protected ArrayList m_Listeners = new ArrayList();
88

    
89
  private static DnDJTree oDnDtocOrigin = null;
90
  private static DnDJTree oDnDtocDestination = null;
91
  /** Stores the parent Frame of the component */
92
  // private Frame Parent = null;
93

    
94
  /** Stores the selected node info */
95
  protected TreePath SelectedTreePath = null;
96
  protected DefaultMutableTreeNode SelectedNode = null;
97

    
98
  /** Variables needed for DnD */
99
  private DragSource dragSource = null;
100
  //private DragSourceContext dragSourceContext = null;
101
  private DropTarget dropTarget;
102
  //private ArrayList treeListeners=new ArrayList();
103
  //private ArrayList dropListeners=new ArrayList();
104
 // private TreeModel model1;
105
  /** Constructor
106
  @param root The root node of the tree
107
  @param parent Parent JFrame of the JTree */
108
  public DnDJTree(TreeModel treeModel) {
109
    super(treeModel);
110
    // Parent = parent;
111

    
112
    //addTreeSelectionListener(this);
113

    
114
                /* ********************** CHANGED ********************** */
115
    dragSource = DragSource.getDefaultDragSource() ;
116
                /* ****************** END OF CHANGE ******************** */
117

    
118
    DragGestureRecognizer dgr =
119
      dragSource.createDefaultDragGestureRecognizer(
120
        this,                             //DragSource
121
        DnDConstants.ACTION_COPY_OR_MOVE, //specifies valid actions
122
        this                              //DragGestureListener
123
      );
124

    
125

    
126
    /* Eliminates right mouse clicks as valid actions - useful especially
127
     * if you implement a JPopupMenu for the JTree
128
     */
129
    dgr.setSourceActions(dgr.getSourceActions() & ~InputEvent.BUTTON3_MASK);
130

    
131
    /* First argument:  Component to associate the target with
132
     * Second argument: DropTargetListener
133
    */
134
    //DropTarget dropTarget = new DropTarget(this, this);
135
    setDropTarget();
136
  }
137
  public void invalidateListeners(){
138
          removeDropListener();
139
          removeTreeListener();
140
  }
141
  private void addDropListener(){
142
          dropTarget= new DropTarget(this, this);
143
  }
144
  private void removeDropListener(){
145
          dropTarget=null;
146
  }
147
  private void addTreeListener(){
148
          addTreeSelectionListener(this);
149
  }
150
  private void removeTreeListener(){
151
          removeTreeSelectionListener(this);
152
  }
153
  public void setDropTarget(){
154
      // TODO: COMENTADO POR FJP
155
          /* com.iver.andami.ui.mdiManager.View[] views=PluginServices.getMDIManager().getAllViews();
156
          for(int i=0;i<views.length;i++){
157
                  if (views[i] instanceof View){
158
                         // model1=((View)views[i]).getTOC().getTree().getModel();
159
                          ((View)views[i]).getTOC().getTree().removeTreeListener();
160
                          ((View)views[i]).getTOC().getTree().addTreeListener();
161
                          ((View)views[i]).getTOC().getTree().removeDropListener();
162
                          ((View)views[i]).getTOC().getTree().addDropListener();
163
                  } */
164
                  addTreeListener();
165
                  addDropListener();
166
          // }
167
         ////////// new DropTarget(this, this);
168
  }
169
  /** Returns The selected node */
170
  public DefaultMutableTreeNode getSelectedNode() {
171
    return SelectedNode;
172
  }
173

    
174
  ///////////////////////// Interface stuff ////////////////////
175

    
176

    
177
  /** DragGestureListener interface method */
178
  public void dragGestureRecognized(DragGestureEvent e) {
179
          if (((MouseEvent)((MouseDragGestureRecognizer)e.getSource()).getTriggerEvent()).getButton()==MouseEvent.BUTTON3){
180
                  return;
181
          }
182
    //Get the selected node
183
    DefaultMutableTreeNode dragNode = getSelectedNode();
184
    if (dragNode != null) {
185

    
186

    
187
      if (!(dragNode.getUserObject() instanceof Transferable)) {
188
                return;
189
        }
190

    
191
//    Get the Transferable Object
192
      Transferable transferable = (Transferable) dragNode.getUserObject();
193

    
194
                        /* ********************** CHANGED ********************** */
195

    
196
      //Select the appropriate cursor;
197
      // Cursor cursor = DragSource.DefaultCopyNoDrop;
198
      int action = e.getDragAction();
199
      /* if (action == DnDConstants.ACTION_MOVE)
200
        cursor = DragSource.DefaultMoveDrop; */
201

    
202

    
203
      //In fact the cursor is set to NoDrop because once an action is rejected
204
      // by a dropTarget, the dragSourceListener are no more invoked.
205
      // Setting the cursor to no drop by default is so more logical, because
206
      // when the drop is accepted by a component, then the cursor is changed by the
207
      // dropActionChanged of the default DragSource.
208
                        /* ****************** END OF CHANGE ******************** */
209

    
210
      //begin the drag
211
      oDnDtocOrigin = this;
212
      dragSource.startDrag(e, null, transferable, this);
213
    }
214
  }
215

    
216
  /** DragSourceListener interface method */
217
  public void dragDropEnd(DragSourceDropEvent dsde) {
218
  }
219

    
220
  /** DragSourceListener interface method */
221
  public void dragEnter(DragSourceDragEvent dsde) {
222
                /* ********************** CHANGED ********************** */
223
      // System.err.println("dragOver" + dsde.getDragSourceContext().getComponent());
224

    
225
                /* ****************** END OF CHANGE ******************** */
226
  }
227

    
228
  /** DragSourceListener interface method */
229
  public void dragOver(DragSourceDragEvent dsde) {
230
                /* ********************** CHANGED ********************** */
231
      // System.err.println("dragOver" + dsde.getDragSourceContext().getComponent());
232
                /* ****************** END OF CHANGE ******************** */
233
  }
234

    
235
  /** DragSourceListener interface method */
236
  public void dropActionChanged(DragSourceDragEvent dsde) {
237
  }
238

    
239
  /** DragSourceListener interface method */
240
  public void dragExit(DragSourceEvent dsde) {
241
  }
242

    
243
  /** DropTargetListener interface method - What we do when drag is released */
244
  public void drop(DropTargetDropEvent e) {
245
    try {
246
      Transferable tr = e.getTransferable();
247
      //flavor not supported, reject drop
248
      if (!tr.isDataFlavorSupported( TocItemBranch.INFO_FLAVOR)) {
249
                e.rejectDrop();
250
        }
251
      //cast into appropriate data type
252
      TocItemBranch childInfo =
253
        (TocItemBranch) tr.getTransferData( TocItemBranch.INFO_FLAVOR );
254
      //get new parent node
255
      Point loc = e.getLocation();
256
      TreePath destinationPath = getPathForLocation(loc.x, loc.y);
257

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

    
290
          DefaultMutableTreeNode nodoTocado =
291
        (DefaultMutableTreeNode) destinationPath.getLastPathComponent();
292
          //        get old parent node
293
      DefaultMutableTreeNode oldParent = (DefaultMutableTreeNode) getSelectedNode().getParent();
294
      if (nodoTocado.getParent().equals(getSelectedNode())){
295
              return;
296
      }
297
      //oldParent.setUserObject(new TocItemBranch(((TocItemBranch)getSelectedNode().getUserObject()).getLayer().getParentLayer()));
298
          if (oldParent==null) {
299
                return;
300
        }
301
      oldPos = oldParent.getIndex(getSelectedNode());
302
          // Para no tener en cuenta los nodos de s?mbolos:
303
      if (!(nodoTocado.getUserObject() instanceof TocItemBranch)){
304
                      nodoTocado = (DefaultMutableTreeNode) nodoTocado.getParent();
305
      }
306

    
307
      ///posActual = oldParent.getIndex(getSelectedNode());
308
      //Destino
309
          DefaultMutableTreeNode destParent=null;
310

    
311
          if (((TocItemBranch)nodoTocado.getUserObject()).getLayer() instanceof FLayers){
312
                  //isContainer=true;
313
                  newPos=0;
314
                  destParent=nodoTocado;
315
      }else{//Si donde se deja la capa seleccionada no es un contenedor de capas.
316
                destParent= (DefaultMutableTreeNode)nodoTocado.getParent();
317
        newPos=destParent.getIndex(nodoTocado);
318
      }
319

    
320

    
321

    
322

    
323
      int action = e.getDropAction();
324
      boolean copyAction = (action == DnDConstants.ACTION_COPY);
325

    
326
      //make new child node
327
      DefaultMutableTreeNode newChild = new DefaultMutableTreeNode(childInfo);
328
          if (getSelectedNode().getAllowsChildren()){
329
                  int childs=getSelectedNode().getChildCount();
330

    
331
                  for (int i=0;i<childs;i++){
332
                          newChild.add((MutableTreeNode)getSelectedNode().getChildAt(0));
333
                  }
334
          }
335

    
336
          try {
337
        if (!copyAction){
338
                oldParent.remove(getSelectedNode());
339
            destParent.insert(newChild,newPos);
340
            // newParent.add(newChild);
341
        }
342
        if (copyAction) {
343
                        e.acceptDrop (DnDConstants.ACTION_COPY);
344
                } else {
345
                        e.acceptDrop (DnDConstants.ACTION_MOVE);
346
                }
347
      }
348
      catch (java.lang.IllegalStateException ils) {
349
        e.rejectDrop();
350
      }
351

    
352
      e.getDropTargetContext().dropComplete(true);
353

    
354
      //expand nodes appropriately - this probably isnt the best way...
355

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

    
364

    
365

    
366
     // ((DefaultTreeModel)model1).reload(oldParent);
367
      DefaultTreeModel model = (DefaultTreeModel) getModel();
368

    
369
          model.reload(getSelectedNode().getRoot());
370
          FLayers lpo=null;
371
          FLayers lpd=null;
372

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

    
387

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

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

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

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

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

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

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

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

    
463

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

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

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

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

    
487
  /** DropTaregetListener interface method */
488
  public void dropActionChanged(DropTargetDragEvent e) {
489
  }
490
  private void setSelectedNode(DefaultMutableTreeNode smtn){
491
          if (smtn!=null) {
492
                SelectedNode=smtn;
493
        }
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

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

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

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

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

    
548
    return null;
549
  }
550

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

    
579
  private void callListeners(FLayers lpo,FLayers lpd,FLayer ls){
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
} //end of DnDJTree