001/* An abstract attribute for a visible text annotation.
002
003 Copyright (c) 2004-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.kernel.attributes;
029
030import java.awt.Color;
031import java.awt.Font;
032import java.awt.GraphicsEnvironment;
033
034import javax.swing.SwingConstants;
035
036import ptolemy.actor.gui.ColorAttribute;
037import ptolemy.data.BooleanToken;
038import ptolemy.data.IntToken;
039import ptolemy.data.expr.Parameter;
040import ptolemy.data.expr.StringParameter;
041import ptolemy.data.type.BaseType;
042import ptolemy.kernel.util.Attribute;
043import ptolemy.kernel.util.IllegalActionException;
044import ptolemy.kernel.util.NameDuplicationException;
045import ptolemy.kernel.util.NamedObj;
046import ptolemy.kernel.util.Workspace;
047import ptolemy.vergil.icon.TextIcon;
048
049///////////////////////////////////////////////////////////////////
050//// AbstractTextAttribute
051
052/**
053 An abstract base class for text annotations.
054 <p>
055 @author Edward A. Lee, Steve Neuendorffer
056 @version $Id$
057 @since Ptolemy II 4.1
058 @Pt.ProposedRating Yellow (eal)
059 @Pt.AcceptedRating Red (cxh)
060 */
061public class AbstractTextAttribute extends VisibleAttribute {
062    /** Construct an attribute with the given name contained by the
063     *  specified container. The container argument must not be null, or a
064     *  NullPointerException will be thrown.  This attribute will use the
065     *  workspace of the container for synchronization and version counts.
066     *  If the name argument is null, then the name is set to the empty
067     *  string. Increment the version of the workspace.
068     *  @param container The container.
069     *  @param name The name of this attribute.
070     *  @exception IllegalActionException If the attribute is not of an
071     *   acceptable class for the container, or if the name contains a period.
072     *  @exception NameDuplicationException If the name coincides with
073     *   an attribute already in the container.
074     */
075    public AbstractTextAttribute(NamedObj container, String name)
076            throws IllegalActionException, NameDuplicationException {
077        super(container, name);
078
079        _icon = new TextIcon(this, "_icon");
080        _icon.setPersistent(false);
081
082        textSize = new Parameter(this, "textSize");
083        textSize.setExpression("14");
084        textSize.setTypeEquals(BaseType.INT);
085        textSize.addChoice("9");
086        textSize.addChoice("10");
087        textSize.addChoice("11");
088        textSize.addChoice("12");
089        textSize.addChoice("14");
090        textSize.addChoice("18");
091        textSize.addChoice("24");
092        textSize.addChoice("32");
093
094        textColor = new ColorAttribute(this, "textColor");
095        textColor.setExpression("{0.0, 0.0, 1.0, 1.0}");
096
097        // Get font family names from the Font class in Java.
098        // This includes logical font names, per Font class in Java:
099        // Dialog, DialogInput, Monospaced, Serif, SansSerif, or Symbol.
100        fontFamily = new StringParameter(this, "fontFamily");
101        fontFamily.setExpression("SansSerif");
102
103        String[] families = GraphicsEnvironment.getLocalGraphicsEnvironment()
104                .getAvailableFontFamilyNames();
105
106        for (String familie : families) {
107            fontFamily.addChoice(familie);
108        }
109
110        bold = new Parameter(this, "bold");
111        bold.setExpression("false");
112        bold.setTypeEquals(BaseType.BOOLEAN);
113
114        italic = new Parameter(this, "italic");
115        italic.setExpression("false");
116        italic.setTypeEquals(BaseType.BOOLEAN);
117
118        anchor = new StringParameter(this, "anchor");
119        anchor.setExpression("northwest");
120        anchor.addChoice("center");
121        anchor.addChoice("east");
122        anchor.addChoice("north");
123        anchor.addChoice("northeast");
124        anchor.addChoice("northwest");
125        anchor.addChoice("south");
126        anchor.addChoice("southeast");
127        anchor.addChoice("southwest");
128        anchor.addChoice("west");
129    }
130
131    ///////////////////////////////////////////////////////////////////
132    ////                         parameters                        ////
133
134    /** Indication of which point of the text should be aligned to the
135     *  grid. The possible values are "center", "east", "north",
136     *  "northeast", "northwest" (the default), "south", "sountheast",
137     *  "southwest", or "west".
138     */
139    public StringParameter anchor;
140
141    /** A boolean indicating whether the font should be bold.
142     *  This defaults to false.
143     */
144    public Parameter bold;
145
146    /** The font family. This is a string that defaults to "SansSerif".
147     */
148    public StringParameter fontFamily;
149
150    /** A boolean indicating whether the font should be italic.
151     *  This defaults to false.
152     */
153    public Parameter italic;
154
155    /** The text color.  This is a string representing an array with
156     *  four elements, red, green, blue, and alpha, where alpha is
157     *  transparency. The default is "{0.0, 0.0, 0.0, 1.0}", which
158     *  represents an opaque black.
159     */
160    public ColorAttribute textColor;
161
162    /** The text size.  This is an int that defaults to 14.
163     */
164    public Parameter textSize;
165
166    ///////////////////////////////////////////////////////////////////
167    ////                         public methods                    ////
168
169    /** React to a changes in the attributes by changing the icon.
170     *  @param attribute The attribute that changed.
171     *  @exception IllegalActionException If the change is not acceptable
172     *   to this container (should not be thrown).
173     */
174    @Override
175    public void attributeChanged(Attribute attribute)
176            throws IllegalActionException {
177        if (attribute == anchor) {
178            String anchorValue = anchor.stringValue();
179            if (anchorValue.equals("center")) {
180                _icon.setAnchor(SwingConstants.CENTER);
181            } else if (anchorValue.equals("east")) {
182                _icon.setAnchor(SwingConstants.EAST);
183            } else if (anchorValue.equals("north")) {
184                _icon.setAnchor(SwingConstants.NORTH);
185            } else if (anchorValue.equals("northeast")) {
186                _icon.setAnchor(SwingConstants.NORTH_EAST);
187            } else if (anchorValue.equals("south")) {
188                _icon.setAnchor(SwingConstants.SOUTH);
189            } else if (anchorValue.equals("southeast")) {
190                _icon.setAnchor(SwingConstants.SOUTH_EAST);
191            } else if (anchorValue.equals("southwest")) {
192                _icon.setAnchor(SwingConstants.SOUTH_WEST);
193            } else if (anchorValue.equals("west")) {
194                _icon.setAnchor(SwingConstants.WEST);
195            } else {
196                _icon.setAnchor(SwingConstants.NORTH_WEST);
197            }
198        } else if ((attribute == fontFamily || attribute == textSize
199                || attribute == bold || attribute == italic)
200                && !_inAttributeChanged) {
201            try {
202                // Prevent redundant actions here... When we evaluate the
203                // _other_ attribute here (whichever one did _not_ trigger
204                // this call, it will likely trigger another call to
205                // attributeChanged(), which will result in this action
206                // being performed twice.
207                _inAttributeChanged = true;
208
209                int sizeValue = ((IntToken) textSize.getToken()).intValue();
210                String familyValue = fontFamily.stringValue();
211                int styleValue = Font.PLAIN;
212
213                if (((BooleanToken) bold.getToken()).booleanValue()) {
214                    styleValue = styleValue | Font.BOLD;
215                }
216
217                if (((BooleanToken) italic.getToken()).booleanValue()) {
218                    styleValue = styleValue | Font.ITALIC;
219                }
220
221                Font fontValue = new Font(familyValue, styleValue, sizeValue);
222                _icon.setFont(fontValue);
223            } finally {
224                _inAttributeChanged = false;
225            }
226        } else if (attribute == textColor) {
227            Color colorValue = textColor.asColor();
228            _icon.setTextColor(colorValue);
229        } else {
230            super.attributeChanged(attribute);
231        }
232    }
233
234    /** Clone the object into the specified workspace.
235     *  @param workspace The workspace for the new object.
236     *  @return A new AbstractTextAttribute.
237     *  @exception CloneNotSupportedException If any of the attributes
238     *   cannot be cloned.
239     */
240    @Override
241    public Object clone(Workspace workspace) throws CloneNotSupportedException {
242        AbstractTextAttribute result = (AbstractTextAttribute) super.clone(
243                workspace);
244        result._icon = (TextIcon) result.getAttribute("_icon");
245        return result;
246    }
247
248    ///////////////////////////////////////////////////////////////////
249    ////                       protected members                   ////
250
251    /** The text icon. */
252    protected TextIcon _icon;
253
254    ///////////////////////////////////////////////////////////////////
255    ////                         private variables                 ////
256    private boolean _inAttributeChanged = false;
257}