001/* A tree cell renderer for ptolemy objects. 002 003 Copyright (c) 2000-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.util.List; 032 033import javax.swing.JTree; 034import javax.swing.tree.DefaultTreeCellRenderer; 035 036import ptolemy.kernel.util.Attribute; 037import ptolemy.kernel.util.InternalErrorException; 038import ptolemy.kernel.util.KernelException; 039import ptolemy.kernel.util.NamedObj; 040import ptolemy.kernel.util.Settable; 041import ptolemy.moml.Documentation; 042import ptolemy.moml.EntityLibrary; 043import ptolemy.vergil.icon.EditorIcon; 044import ptolemy.vergil.icon.XMLIcon; 045 046/** 047 A tree cell renderer for Ptolemy objects. This renderer renders 048 the icon of an object, if it has one. 049 050 @author Steve Neuendorffer and Edward A. Lee 051 @version $Revision$ 052 @since Ptolemy II 1.0 053 @Pt.ProposedRating Red (eal) 054 @Pt.AcceptedRating Red (johnr) 055 */ 056@SuppressWarnings("serial") 057public class PtolemyTreeCellRenderer extends DefaultTreeCellRenderer { 058 059 /** Construct a tree cell renderer that shows the expression value 060 * of any object that implements {@link Settable}. 061 */ 062 public PtolemyTreeCellRenderer() { 063 this(true); 064 } 065 066 /** Construct a tree cell renderer that shows the expression value 067 * of any object that implements {@link Settable}. 068 * @param showSettableValues If true, show the expression value 069 * for any object that implements {@link Settable}. 070 */ 071 public PtolemyTreeCellRenderer(boolean showSettableValues) { 072 _showSettableValues = showSettableValues; 073 } 074 075 /////////////////////////////////////////////////////////////////// 076 //// public method //// 077 078 /** Create a new rendition for the given object. The rendition is 079 * the default provided by the base class with the text set to 080 * the name of the node (if it is an object implementing Nameable). 081 * If the object is an instance of NamedObj and it has attributes 082 * of type Documentation, then construct a tooltip as follows. 083 * If there is a Documentation attribute named "tooltip", then 084 * use that. Otherwise, consolidate all the Documentation 085 * attributes and use those. 086 */ 087 @Override 088 public Component getTreeCellRendererComponent(JTree tree, Object value, 089 boolean selected, boolean expanded, boolean leaf, int row, 090 boolean hasFocus) { 091 DefaultTreeCellRenderer component = (DefaultTreeCellRenderer) super.getTreeCellRendererComponent( 092 tree, value, selected, expanded, leaf, row, hasFocus); 093 094 if (value instanceof NamedObj) { 095 NamedObj object = (NamedObj) value; 096 097 // Fix the background colors because transparent 098 // labels don't work quite right. 099 if (!selected) { 100 component.setBackground(tree.getBackground()); 101 component.setOpaque(true); 102 } else { 103 component.setOpaque(false); 104 } 105 106 if (object instanceof Settable) { 107 StringBuffer buffer = new StringBuffer(); 108 buffer.append(object.getDisplayName()); 109 if (_showSettableValues) { 110 buffer.append("="); 111 buffer.append(((Settable) object).getExpression() 112 .replace('\n', ' ')); 113 } 114 component.setText(buffer.toString()); 115 } else { 116 // Use the display name not the name so that what is 117 // shown to the user in the tree view matches what is 118 // shown in the regular canvas. 119 component.setText(object.getDisplayName()); 120 } 121 122 // Render an icon, if one has been defined. 123 // NOTE: Avoid asking for attributes if the entity is a library 124 // because this will trigger evaluation, defeating deferred 125 // evaluation. 126 if (!(object instanceof EntityLibrary)) { 127 // Only if an object has an icon, an icon description, or 128 // a small icon description is it rendered in the tree. 129 List iconList = object.attributeList(EditorIcon.class); 130 131 // jkillian removed the first condition (iconList.size() > 0), saying: 132 // Removed iconList.size() > 0 condition from the if-clause because 133 // it cached a blank image when an icon wasn't defined and then always 134 // entered the block in subsequent repaints. This caused the icon 135 // to disappear in Homer when dragging attributes onto the canvas. 136 // Doing so didn't seem to affect the tree display in Vergil. 137 // 138 // The last statement is wrong. The result is that icons do not 139 // display in the library. Hence, I've reversed the change. EAL 12/15/11. 140 if (iconList.size() > 0 141 || object.getAttribute("_iconDescription") != null 142 || object.getAttribute( 143 "_smallIconDescription") != null) { 144 // NOTE: this code is similar to that in IconController. 145 EditorIcon icon = null; 146 147 try { 148 if (iconList.size() == 0) { 149 icon = XMLIcon.getXMLIcon(object, "_icon"); 150 icon.setPersistent(false); 151 } else { 152 icon = (EditorIcon) iconList 153 .get(iconList.size() - 1); 154 } 155 } catch (KernelException ex) { 156 throw new InternalErrorException( 157 "could not create icon in " + object 158 + " even though one did not previously exist."); 159 } 160 161 // Wow.. this is a confusing line of code.. :) 162 try { 163 component.setIcon(icon.createIcon()); 164 } catch (Throwable throwable) { 165 // Ignore this, but print a message 166 System.err.println( 167 "Warning: Failed to create or " + "set icon " 168 + icon + " for component " + component); 169 throwable.printStackTrace(); 170 } 171 } 172 173 // NOTE: The following is not called on EntityLibrary, 174 // which means no tooltip for those. Calling it would 175 // force expansion of the library. No good solution here. 176 Attribute tooltipAttribute = object.getAttribute("tooltip"); 177 178 if (tooltipAttribute != null 179 && tooltipAttribute instanceof Documentation) { 180 // FIXME: This doesn't work with calling this 181 // on either this or component. 182 this.setToolTipText(((Documentation) tooltipAttribute) 183 .getValueAsString()); 184 } else { 185 String tip = Documentation.consolidate(object); 186 187 if (tip != null) { 188 // FIXME: This doesn't work with calling this 189 // on either this or component. 190 this.setToolTipText(tip); 191 } 192 } 193 } 194 } 195 196 return component; 197 } 198 199 /////////////////////////////////////////////////////////////////// 200 //// private variable //// 201 202 /** Indicator of whether to show expression values of Settables. */ 203 private boolean _showSettableValues; 204}