001/* An icon that renders the value of an attribute of the container.
002
003 Copyright (c) 1999-2016 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.icon;
029
030import java.awt.Font;
031import java.awt.geom.Rectangle2D;
032
033import javax.swing.SwingConstants;
034
035import diva.canvas.CompositeFigure;
036import diva.canvas.Figure;
037import diva.canvas.toolbox.LabelFigure;
038import ptolemy.data.IntToken;
039import ptolemy.data.expr.Parameter;
040import ptolemy.data.expr.StringParameter;
041import ptolemy.data.type.BaseType;
042import ptolemy.kernel.CompositeEntity;
043import ptolemy.kernel.util.Attribute;
044import ptolemy.kernel.util.IllegalActionException;
045import ptolemy.kernel.util.NameDuplicationException;
046import ptolemy.kernel.util.NamedObj;
047import ptolemy.kernel.util.Settable;
048import ptolemy.kernel.util.StringAttribute;
049import ptolemy.util.StringUtilities;
050
051///////////////////////////////////////////////////////////////////
052//// AttributeValueIcon
053
054/**
055 An icon that displays the value of an attribute of the container
056 or of some other entity contained by the container.
057 The attribute is assumed to be an instance of Settable, and its name
058 is given by the parameter <i>attributeName</i>.  The display is not
059 automatically updated when the attribute value is updated.
060
061 @author Edward A. Lee
062 @version $Id$
063 @since Ptolemy II 2.0
064 @Pt.ProposedRating Yellow (eal)
065 @Pt.AcceptedRating Red (johnr)
066 */
067public class AttributeValueIcon extends XMLIcon {
068    /** Create a new icon with the given name in the given container.
069     *  The container is required to implement Settable, or an exception
070     *  will be thrown.
071     *  @param container The container for this attribute.
072     *  @param name The name of this attribute.
073     *  @exception IllegalActionException If thrown by the parent
074     *  class or while setting an attribute
075     *  @exception NameDuplicationException If the name coincides with
076     *   an attribute already in the container.
077     */
078    public AttributeValueIcon(NamedObj container, String name)
079            throws NameDuplicationException, IllegalActionException {
080        super(container, name);
081
082        attributeName = new StringAttribute(this, "attributeName");
083
084        displayWidth = new Parameter(this, "displayWidth");
085        displayWidth.setExpression("6");
086        displayWidth.setTypeEquals(BaseType.INT);
087
088        displayHeight = new Parameter(this, "displayHeight");
089        displayHeight.setExpression("1");
090        displayHeight.setTypeEquals(BaseType.INT);
091
092        entityName = new StringParameter(this, "entityName");
093        entityName.setExpression("");
094    }
095
096    ///////////////////////////////////////////////////////////////////
097    ////                         parameters                        ////
098
099    /** The name of the attribute of the container whose value to display.
100     *  This is a string that by default is empty. An empty string means
101     *  that the attribute whose value to display is the container itself,
102     *  rather than an attribute contained by the container.
103     */
104    public StringAttribute attributeName;
105
106    /** The maximum number of lines to display. This is an integer, with
107     *  default value 1.
108     */
109    public Parameter displayHeight;
110
111    /** The number of characters to display. This is an integer, with
112     *  default value 6.
113     */
114    public Parameter displayWidth;
115
116    /** Name of the entity contained by the container whose attribute
117     *  this icon will display. This is a string that defaults to the
118     *  empty string, which means that the attribute is contained
119     *  by the container of this attribute.
120     */
121    public StringParameter entityName;
122
123    ///////////////////////////////////////////////////////////////////
124    ////                         public methods                    ////
125
126    /** Create a new Diva figure that visually represents this icon.
127     *  The figure will be an instance of LabelFigure that renders the
128     *  value of the specified attribute of the container.
129     *  @return A new CompositeFigure consisting of the label.
130     */
131    @Override
132    public Figure createFigure() {
133        CompositeFigure result = (CompositeFigure) super.createFigure();
134        String truncated = _displayString();
135
136        LabelFigure label = new LabelFigure(truncated, _labelFont, 1.0,
137                SwingConstants.CENTER);
138        Rectangle2D backBounds = result.getBackgroundFigure().getBounds();
139        label.translateTo(backBounds.getCenterX(), backBounds.getCenterY());
140        result.add(label);
141
142        _addLiveFigure(label);
143        return result;
144    }
145
146    ///////////////////////////////////////////////////////////////////
147    ////                         protected methods                 ////
148
149    /** Return the associated attribute. If an {@link #entityName} is given,
150     *  then the associated attribute is attribute with name given by
151     *  {@link #attributeName} contained by the specified entity.
152     *  If no entityName is given, then the associated attribute is
153     *  the one contained by the container of this object with the
154     *  specified name.  If no attributeName is given either, and the
155     *  the container of this object is an Attribute, then the associated
156     *  attribute is that container. Otherwise, throw an exception.
157     *  @return The associated attribute.
158     *  @exception IllegalActionException If no Settable associated attribute
159     *   can be found.
160     */
161    protected Settable _associatedAttribute() throws IllegalActionException {
162        NamedObj container = getContainer();
163        if (entityName.stringValue().trim().equals("")) {
164            String name = attributeName.getExpression();
165            if (!name.trim().equals("") && container != null) {
166                Attribute candidate = container.getAttribute(name);
167                if (candidate instanceof Settable) {
168                    return (Settable) candidate;
169                }
170            } else {
171                // No attributeName is given.
172                // If the container is an Attribute, use it.
173                if (container instanceof Settable) {
174                    return (Settable) container;
175                }
176            }
177        } else if (container instanceof CompositeEntity) {
178            NamedObj entity = ((CompositeEntity) container)
179                    .getEntity(entityName.stringValue());
180            if (entity != null) {
181                Attribute candidate = entity
182                        .getAttribute(attributeName.getExpression());
183                if (candidate instanceof Settable) {
184                    return (Settable) candidate;
185                }
186            }
187        }
188        throw new IllegalActionException(this, "No associated attribute.");
189    }
190
191    /** Get the string value of the attribute to render in the icon.
192     *  This string is the expression giving the value of the attribute of the
193     *  container having the name <i>attributeName</i>. If the string is empty,
194     *  then return a string with one space (diva fails on empty strings). This
195     *  method will always return the full string value of the attribute and will
196     *  not be truncated.
197     *  @return The string value of the attribute to display, or a string with
198     *   one space if none is found.
199     */
200    protected String _attributeValueString() {
201        try {
202            String value = _associatedAttribute().getExpression();
203            if (value == null || value.equals("")) {
204                value = " ";
205            }
206            return value;
207        } catch (IllegalActionException e) {
208            // Ignore and produce a default icon.
209            return " ";
210        }
211    }
212
213    /** Get the string to render in the icon.  This string is the
214     *  expression giving the value of the attribute of the container
215     *  having the name <i>attributeName</i>, truncated so that it is
216     *  no longer than <i>displayWidth</i> characters.  If it is truncated,
217     *  then the string has a trailing "...".  If the string is empty,
218     *  then return a string with one space (diva fails on empty strings).
219     *  @return The string to display, or a string with one space if none is found.
220     */
221    protected String _displayString() {
222        String truncated = _attributeValueString();
223
224        try {
225            int width = ((IntToken) displayWidth.getToken()).intValue();
226            int height = ((IntToken) displayHeight.getToken()).intValue();
227            truncated = StringUtilities.truncateString(truncated, width,
228                    height);
229        } catch (IllegalActionException ex) {
230            // Ignore... use whole string.
231        }
232
233        if (truncated.length() == 0) {
234            truncated = " ";
235        }
236
237        return truncated;
238    }
239
240    ///////////////////////////////////////////////////////////////////
241    ////                         protected members                 ////
242
243    /** The font used. */
244    protected static final Font _labelFont = new Font("SansSerif", Font.PLAIN,
245            12);
246}