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}