001/* An icon that renders the value of all attributes of the container.
002
003 Copyright (c) 2003-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.Color;
031import java.awt.Font;
032import java.awt.geom.Rectangle2D;
033import java.util.Iterator;
034
035import javax.swing.SwingConstants;
036
037import diva.canvas.CompositeFigure;
038import diva.canvas.Figure;
039import diva.canvas.toolbox.BasicRectangle;
040import diva.canvas.toolbox.LabelFigure;
041import ptolemy.data.IntToken;
042import ptolemy.data.expr.Parameter;
043import ptolemy.data.type.BaseType;
044import ptolemy.kernel.util.IllegalActionException;
045import ptolemy.kernel.util.NameDuplicationException;
046import ptolemy.kernel.util.NamedObj;
047import ptolemy.kernel.util.Settable;
048
049///////////////////////////////////////////////////////////////////
050//// BoxedValuesIcon
051
052/**
053 This icon displays the value of all visible attributes of class Settable
054 contained by the container of this icon. Visible attributes are those
055 whose visibility is Settable.FULL. The names and values of the attributes
056 are displayed in a box that resizes as necessary. If any line is longer
057 than <i>displayWidth</i> (in characters), then it is truncated.
058
059 @author Edward A. Lee
060 @version $Id$
061 @since Ptolemy II 4.0
062 @Pt.ProposedRating Yellow (eal)
063 @Pt.AcceptedRating Red (johnr)
064 */
065public class BoxedValuesIcon extends XMLIcon {
066    /** Create a new icon with the given name in the given container.
067     *  The container is required to implement Settable, or an exception
068     *  will be thrown.
069     *  @param container The container for this attribute.
070     *  @param name The name of this attribute.
071     *  @exception IllegalActionException If thrown by the parent
072     *  class or while setting an attribute.
073     *  @exception NameDuplicationException If the name coincides with
074     *   an attribute already in the container.
075     */
076    public BoxedValuesIcon(NamedObj container, String name)
077            throws NameDuplicationException, IllegalActionException {
078        super(container, name);
079
080        displayWidth = new Parameter(this, "displayWidth");
081        displayWidth.setExpression("80");
082        displayWidth.setTypeEquals(BaseType.INT);
083
084        setPersistent(false);
085    }
086
087    ///////////////////////////////////////////////////////////////////
088    ////                         parameters                        ////
089
090    /** The number of characters to display. This is an integer, with
091     *  default value 80.
092     */
093    public Parameter displayWidth;
094
095    ///////////////////////////////////////////////////////////////////
096    ////                         public methods                    ////
097
098    /** Create a new background figure.  This overrides the base class
099     *  to draw a box around the value display, where the width of the
100     *  box depends on the value.
101     *  @return A new figure.
102     */
103    @Override
104    public Figure createBackgroundFigure() {
105        String displayString = _displayString();
106        double width = 60;
107        double heigth = 30;
108
109        if (displayString != null) {
110            // Measure width of the text.  Unfortunately, this
111            // requires generating a label figure that we will not use.
112            LabelFigure label = new LabelFigure(displayString, _labelFont, 1.0,
113                    SwingConstants.CENTER);
114            Rectangle2D stringBounds = label.getBounds();
115
116            // NOTE: Padding of 20.
117            width = stringBounds.getWidth() + 20;
118            heigth = stringBounds.getHeight() + 10;
119        }
120
121        BasicRectangle result = new BasicRectangle(0, 0, width, heigth,
122                Color.white, 1);
123
124        // FIXME: Doesn't do the right thing.
125        // result.setCentered(false);
126        return result;
127    }
128
129    /** Create a new Diva figure that visually represents this icon.
130     *  The figure will be an instance of LabelFigure that renders the
131     *  values of the attributes of the container.
132     *  @return A new CompositeFigure consisting of the label.
133     */
134    @Override
135    public Figure createFigure() {
136        CompositeFigure result = (CompositeFigure) super.createFigure();
137        String truncated = _displayString();
138
139        // If there is no string to display now, then create a string
140        // with a single blank.
141        if (truncated == null) {
142            truncated = " ";
143        }
144
145        // NOTE: This violates the Diva MVC architecture!
146        // This attribute is part of the model, and should not have
147        // a reference to this figure.  By doing so, it precludes the
148        // possibility of having multiple views on this model.
149        LabelFigure label = new LabelFigure(truncated, _labelFont, 1.0,
150                SwingConstants.CENTER);
151        Rectangle2D backBounds = result.getBackgroundFigure().getBounds();
152        label.translateTo(backBounds.getCenterX(), backBounds.getCenterY());
153        result.add(label);
154
155        _addLiveFigure(label);
156        return result;
157    }
158
159    ///////////////////////////////////////////////////////////////////
160    ////                         protected methods                 ////
161
162    /** Get the string to render in the icon.  This string is the
163     *  expression giving the value of the attribute of the container
164     *  having the name <i>attributeName</i>, truncated so that it is
165     *  no longer than <i>displayWidth</i> characters.  If it is truncated,
166     *  then the string has a trailing "...".  If the string is empty,
167     *  then return a string with one space (diva fails on empty strings).
168     *  @return The string to display, or null if none is found.
169     */
170    protected String _displayString() {
171        NamedObj container = getContainer();
172
173        if (container != null) {
174            StringBuffer buffer = new StringBuffer();
175            Iterator settables = container.attributeList(Settable.class)
176                    .iterator();
177
178            while (settables.hasNext()) {
179                Settable settable = (Settable) settables.next();
180
181                if (settable.getVisibility() != Settable.FULL
182                        && settable.getVisibility() != Settable.NOT_EDITABLE) {
183                    continue;
184                }
185
186                String name = settable.getDisplayName();
187                String value = settable.getExpression();
188                String line = name + ": " + value;
189                String truncated = line;
190
191                try {
192                    int width = ((IntToken) displayWidth.getToken()).intValue();
193
194                    if (line.length() > width) {
195                        truncated = line.substring(0, width) + "...";
196                    }
197                } catch (IllegalActionException ex) {
198                    // Ignore... use whole string.
199                }
200
201                buffer.append(truncated);
202
203                if (settables.hasNext()) {
204                    buffer.append("\n");
205                }
206            }
207
208            return buffer.toString();
209        }
210
211        return null;
212    }
213
214    ///////////////////////////////////////////////////////////////////
215    ////                         protected members                 ////
216
217    /** The font used. */
218    protected static final Font _labelFont = new Font("Dialog", Font.PLAIN, 12);
219}