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 @ 44601

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
                return;
251
        }
252
      //cast into appropriate data type
253
      TocItemBranch childInfo =
254
        (TocItemBranch) tr.getTransferData( TocItemBranch.INFO_FLAVOR );
255
      //get new parent node
256
      Point loc = e.getLocation();
257
      TreePath destinationPath = getPathForLocation(loc.x, loc.y);
258

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

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

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

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

    
321

    
322

    
323

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

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

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

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

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

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

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

    
365

    
366

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

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

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

    
388

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

    
396
    catch (IOException io) { e.rejectDrop(); }
397
    catch (UnsupportedFlavorException ufe) {e.rejectDrop();}
398
  } //end of method
399
public void dropRoot(TreeNode tn){
400
        int oldPos,newPos;
401
        DefaultMutableTreeNode nodoTocado =
402
                (DefaultMutableTreeNode) tn;
403
                  //        get old parent node
404
            if (getSelectedNode()==null) {
405
                        return;
406
                }
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
              org.gvsig.andami.ui.mdiManager.IWindow[] views=PluginServices.getMDIManager().getAllWindows();
421
                  for(int i=0;i<views.length;i++){
422
                          if (views[i] instanceof DefaultViewPanel){
423
                                  ((DefaultTreeModel)((DefaultViewPanel)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=((TocItemBranch)getSelectedNode().getUserObject()).getLayer().getParentLayer();
433
                  for(int i=0;i<views.length;i++){
434
                          if (views[i] instanceof DefaultViewPanel){
435
                                  if (((DefaultViewPanel)views[i]).getTOC().getTree().equals(this)){
436
                                          lpd= ((DefaultViewPanel)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

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

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

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

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

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

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

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

    
549
    return null;
550
  }
551

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

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

    
588
} //end of DnDJTree