001/* A tree of ptolemy objects.
002
003 Copyright (c) 1999-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.vergil.tree;
029
030import java.awt.Component;
031import java.awt.Point;
032import java.awt.dnd.DnDConstants;
033import java.awt.dnd.DragGestureEvent;
034import java.awt.dnd.DragGestureListener;
035import java.awt.dnd.DragSource;
036import java.awt.dnd.DragSourceContext;
037import java.awt.dnd.DragSourceDragEvent;
038import java.awt.dnd.DragSourceDropEvent;
039import java.awt.dnd.DragSourceEvent;
040import java.awt.dnd.DragSourceListener;
041
042import javax.swing.JTree;
043import javax.swing.tree.TreeModel;
044import javax.swing.tree.TreePath;
045
046import ptolemy.data.BooleanToken;
047import ptolemy.data.Token;
048import ptolemy.data.expr.Parameter;
049import ptolemy.kernel.util.Attribute;
050import ptolemy.kernel.util.IllegalActionException;
051import ptolemy.kernel.util.Nameable;
052import ptolemy.kernel.util.NamedObj;
053import ptolemy.moml.EntityLibrary;
054import ptolemy.vergil.toolbox.PtolemyTransferable;
055
056/**
057 This class provides a tree view of a ptolemy model.
058 The class supports drag-and-drop.
059
060 @author Steve Neuendorffer and Edward A. Lee, contributor: Sean Riddle
061 @version $Id$
062 @since Ptolemy II 1.0
063 @Pt.ProposedRating Red (eal)
064 @Pt.AcceptedRating Red (johnr)
065 */
066@SuppressWarnings("serial")
067public class PTree extends JTree {
068    /** Create a new tree that is rooted at the given entity.
069     *  This constructor creates a tree that shows the expression
070     *  value for any object that implements {@link ptolemy.kernel.util.Settable}.
071     *  @param model The model that is the root of the tree.
072     */
073    public PTree(TreeModel model) {
074        this(model, true);
075    }
076
077    /** Create a new tree that is rooted at the given entity.
078     *  @param model The model that is the root of the tree.
079     *  @param showSettableValues If true, show the expression value
080     *   for any object that implements {@link ptolemy.kernel.util.Settable}.
081     */
082    public PTree(TreeModel model, boolean showSettableValues) {
083        // The use of EntityTreeModel here is what restricts the
084        // tree to displaying only entities.
085        super(model);
086        setCellRenderer(new PtolemyTreeCellRenderer(showSettableValues));
087        DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(
088                this, DnDConstants.ACTION_COPY_OR_MOVE,
089                new PTreeDragGestureListener());
090    }
091
092    ///////////////////////////////////////////////////////////////////
093    ////                         public methods                    ////
094
095    /** Give a string representation of the node value.
096     *  If the value is a Nameable, this returns its name.
097     *  Otherwise, it returns value.toString();
098     */
099    @Override
100    public String convertValueToText(Object value, boolean selected,
101            boolean expanded, boolean leaf, int row, boolean hasFocus) {
102        String result;
103        if (value instanceof Nameable) {
104            result = ((Nameable) value).getName();
105        } else {
106            result = value.toString();
107        }
108        return result;
109    }
110
111    ///////////////////////////////////////////////////////////////////
112    ////                         inner classes                     ////
113    // A Drag Gesture listener for the tree.
114    private static class PTreeDragGestureListener
115            implements DragGestureListener {
116        // FindBugs suggests making this class static so as to decrease
117        // the size of instances and avoid dangling references.
118        @Override
119        public void dragGestureRecognized(DragGestureEvent e) {
120            final DragSourceListener dsl = new DragSourceListener() {
121                @Override
122                public void dragDropEnd(DragSourceDropEvent dsde) {
123                }
124
125                @Override
126                public void dragEnter(DragSourceDragEvent dsde) {
127                    DragSourceContext context = dsde.getDragSourceContext();
128
129                    // Intersection of the users selected action,
130                    // and the source and target actions
131                    int myaction = dsde.getDropAction();
132
133                    if ((myaction & DnDConstants.ACTION_COPY_OR_MOVE) != 0) {
134                        context.setCursor(DragSource.DefaultCopyDrop);
135                    } else {
136                        context.setCursor(DragSource.DefaultCopyNoDrop);
137                    }
138                }
139
140                @Override
141                public void dragExit(DragSourceEvent dse) {
142                }
143
144                @Override
145                public void dragOver(DragSourceDragEvent dsde) {
146                }
147
148                @Override
149                public void dropActionChanged(DragSourceDragEvent dsde) {
150                }
151            };
152
153            Component source = e.getComponent();
154
155            if (source instanceof JTree) {
156                JTree tree = (JTree) source;
157                Point sourcePoint = e.getDragOrigin();
158                TreePath path = tree.getPathForLocation(sourcePoint.x,
159                        sourcePoint.y);
160
161                // If we didn't select anything.. then don't drag.
162                if (path == null) {
163                    return;
164                }
165
166                if (path.getLastPathComponent() instanceof EntityLibrary) {
167                    //this prevents a user from dragging a folder.
168                    return;
169                }
170
171                Object object = path.getLastPathComponent();
172
173                if (object == null) {
174                    return;
175                }
176
177                if (object instanceof NamedObj
178                        && !_isPropertySet((NamedObj) object,
179                                "_notDraggable")) {
180                    PtolemyTransferable transferable = new PtolemyTransferable();
181                    transferable.addObject((NamedObj) object);
182
183                    //initial cursor, transferable, dsource listener
184                    e.startDrag(DragSource.DefaultCopyNoDrop, transferable,
185                            dsl);
186                }
187            }
188        }
189    }
190
191    private static boolean _isPropertySet(NamedObj object, String name) {
192        Attribute attribute = object.getAttribute(name);
193
194        if (attribute == null) {
195            return false;
196        }
197
198        if (attribute instanceof Parameter) {
199            try {
200                Token token = ((Parameter) attribute).getToken();
201
202                if (token instanceof BooleanToken) {
203                    if (!((BooleanToken) token).booleanValue()) {
204                        return false;
205                    }
206                }
207            } catch (IllegalActionException e) {
208                // Ignore, using default of true.
209            }
210        }
211
212        return true;
213    }
214
215}