001/* An abstract attribute with a reference to a shape. 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.kernel.attributes; 029 030import java.awt.Color; 031import java.awt.Shape; 032import java.awt.geom.Rectangle2D; 033 034import ptolemy.actor.gui.ColorAttribute; 035import ptolemy.data.ArrayToken; 036import ptolemy.data.DoubleToken; 037import ptolemy.data.expr.Parameter; 038import ptolemy.data.expr.Variable; 039import ptolemy.data.type.ArrayType; 040import ptolemy.data.type.BaseType; 041import ptolemy.kernel.util.Attribute; 042import ptolemy.kernel.util.IllegalActionException; 043import ptolemy.kernel.util.Location; 044import ptolemy.kernel.util.NameDuplicationException; 045import ptolemy.kernel.util.NamedObj; 046import ptolemy.kernel.util.Workspace; 047import ptolemy.vergil.icon.ShapeIcon; 048 049/////////////////////////////////////////////////////////////////// 050//// ShapeAttribute 051 052/** 053 This is an abstract attribute that is rendered as a shape. 054 This base class provides support for a line width and a line color. 055 The line color can be "none", in which case no line is drawn. 056 Concrete derived classes provide particular shapes. 057 <p> 058 @author Edward A. Lee 059 @version $Id$ 060 @since Ptolemy II 4.0 061 @Pt.ProposedRating Yellow (eal) 062 @Pt.AcceptedRating Red (cxh) 063 */ 064public abstract class ShapeAttribute extends VisibleAttribute { 065 /** Construct an attribute with the given name contained by the 066 * specified container. The container argument must not be null, or a 067 * NullPointerException will be thrown. This attribute will use the 068 * workspace of the container for synchronization and version counts. 069 * If the name argument is null, then the name is set to the empty 070 * string. Increment the version of the workspace. 071 * @param container The container. 072 * @param name The name of this attribute. 073 * @exception IllegalActionException If the attribute is not of an 074 * acceptable class for the container, or if the name contains a period. 075 * @exception NameDuplicationException If the name coincides with 076 * an attribute already in the container. 077 */ 078 public ShapeAttribute(NamedObj container, String name) 079 throws IllegalActionException, NameDuplicationException { 080 super(container, name); 081 082 _icon = new ShapeIcon(this, "_icon", _getDefaultShape()); 083 _icon.setPersistent(false); 084 085 // Create a location because, for some mysterious reason, 086 // if there isn't one, then the icon is not shown in the 087 // icon editor. 088 new Location(this, "_location"); 089 090 // This must appear before lineColor or cloning could 091 // fail if lineColor references it. 092 _none = new Variable(this, "none"); 093 _none.setExpression("{1.0, 1.0, 1.0, 0.0}"); 094 095 lineWidth = new Parameter(this, "lineWidth"); 096 lineWidth.setTypeEquals(BaseType.DOUBLE); 097 lineWidth.setExpression("1.0"); 098 099 lineColor = new ColorAttribute(this, "lineColor"); 100 lineColor.setExpression("{0.0, 0.0, 0.0, 1.0}"); 101 102 dashArray = new Parameter(this, "dashArray"); 103 dashArray.setTypeEquals(new ArrayType(BaseType.DOUBLE)); 104 105 rotation = new Parameter(this, "rotation"); 106 rotation.setTypeEquals(BaseType.DOUBLE); 107 rotation.setExpression("0.0"); 108 } 109 110 /////////////////////////////////////////////////////////////////// 111 //// parameters //// 112 113 /** Specification of the dash pattern for dashed or dotted lines. 114 * An empty value indicates that the line should not be dashed. 115 * The values specify the length of solid and transparent segments 116 * in an alternating fashion. 117 * This is an array of doubles that by default is empty. 118 */ 119 public Parameter dashArray; 120 121 /** The line color. This is a string representing an array with 122 * four elements, red, green, blue, and alpha, where alpha is 123 * transparency. The default is "{0.0, 0.0, 0.0, 1.0}", which 124 * represents an opaque black. 125 */ 126 public ColorAttribute lineColor; 127 128 /** The line width. This is a double that defaults to 1.0. 129 */ 130 public Parameter lineWidth; 131 132 /** The angle of rotation in radians. This is a double that 133 * defaults to 0.0. 134 */ 135 public Parameter rotation; 136 137 /////////////////////////////////////////////////////////////////// 138 //// public methods //// 139 140 /** React to a changes in the attributes by changing 141 * the icon. 142 * @param attribute The attribute that changed. 143 * @exception IllegalActionException If the change is not acceptable 144 * to this container (should not be thrown). 145 */ 146 @Override 147 public void attributeChanged(Attribute attribute) 148 throws IllegalActionException { 149 if (attribute == lineWidth) { 150 double lineWidthValue = ((DoubleToken) lineWidth.getToken()) 151 .doubleValue(); 152 _icon.setLineWidth((float) lineWidthValue); 153 } else if (attribute == dashArray) { 154 ArrayToken value = (ArrayToken) dashArray.getToken(); 155 156 if (value == null || value.length() == 0) { 157 _icon.setDashArray(null); 158 } else { 159 float[] floatValue = new float[value.length()]; 160 161 for (int i = 0; i < value.length(); i++) { 162 floatValue[i] = (float) ((DoubleToken) value.getElement(i)) 163 .doubleValue(); 164 } 165 166 _icon.setDashArray(floatValue); 167 } 168 } else if (attribute == lineColor) { 169 Color lineColorValue = lineColor.asColor(); 170 171 if (lineColorValue.getAlpha() == 0f) { 172 // Color is fully transparent, so no line is desired. 173 _icon.setLineColor(null); 174 } else { 175 _icon.setLineColor(lineColorValue); 176 } 177 } else if (attribute == rotation) { 178 double angle = ((DoubleToken) rotation.getToken()).doubleValue(); 179 _icon.setRotation(angle); 180 } else { 181 super.attributeChanged(attribute); 182 } 183 } 184 185 /** Clone the object into the specified workspace. The new object is 186 * <i>not</i> added to the directory of that workspace (you must do this 187 * yourself if you want it there). 188 * The result is an object with no container. 189 * @param workspace The workspace for the cloned object. 190 * @exception CloneNotSupportedException Not thrown in this base class 191 * @return The new Attribute. 192 */ 193 @Override 194 public Object clone(Workspace workspace) throws CloneNotSupportedException { 195 ShapeAttribute newObject = (ShapeAttribute) super.clone(workspace); 196 197 // The base class clones the icon, but since this is a protected 198 // member, it doesn't automatically get updated by NamedObj! 199 newObject._icon = (ShapeIcon) newObject.getAttribute("_icon"); 200 newObject._none = (Variable) newObject.getAttribute("_none"); 201 return newObject; 202 } 203 204 /////////////////////////////////////////////////////////////////// 205 //// protected methods //// 206 207 /** Return the default shape to use for this icon. 208 * Note that this is called in the constructor, so if you override 209 * it in derived classed, you cannot access any methods or members 210 * of the derived class because they will not have been constructed. 211 * @return The default shape for this attribute. 212 */ 213 protected Shape _getDefaultShape() { 214 // NOTE: In an ideal world, this would not be necessary, because 215 // setShape() would override the default shape. Unfortunately, 216 // without this, icons are rendered before setShape() has been called, 217 // and consequently, all shape attributes are rendered the same in 218 // the utilities library. 219 return new Rectangle2D.Double(0.0, 0.0, 20.0, 20.0); 220 } 221 222 /////////////////////////////////////////////////////////////////// 223 //// protected members //// 224 225 /** The shape icon. */ 226 protected ShapeIcon _icon; 227 228 /** A color parameter whose value is a fully transparent white 229 * (alpha = 0.0), which is interpreted as no color. 230 */ 231 protected Variable _none; 232}