001/* An attribute that has a string value. 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 */ 027package ptolemy.kernel.util; 028 029import java.io.IOException; 030import java.io.Writer; 031import java.util.Collection; 032import java.util.Iterator; 033import java.util.LinkedList; 034import java.util.List; 035 036import ptolemy.util.StringUtilities; 037 038/////////////////////////////////////////////////////////////////// 039//// StringAttribute 040 041/** 042 An attribute that has a string value. 043 Use setExpression() to define the value, as in for example 044 <pre> 045 attribute.setExpression("xxx"); 046 </pre> 047 <p>The default value of the string contained by this attribute is the empty 048 string. 049 050 <p>By default, an instance of this class is fully visible in 051 a user interface. The visibility is indicated to the user 052 interface when the user interface calls the getVisibility() method 053 of this class and the value Settable.FULL is returned to the userInterface. 054 055 <p>Note that the string value within StringAttribute cannot reference 056 other StringAttributes or Parameters, so if an actor has a public 057 StringAttribute, then one cannot make the value of that attribute 058 dependent on a value higher in the hierarchy. Usually, actors have 059 public ptolemy.data.expr.Parameters instead of public StringAttributes 060 so that the value can reference other parameters. The primary reason 061 to use StringAttribute is if you want a string that will not be parsed 062 and you do not want to type a leading a trailing double quote. 063 064 @see Settable#FULL 065 @author Edward A. Lee 066 @version $Id$ 067 @since Ptolemy II 1.0 068 @Pt.ProposedRating Green (eal) 069 @Pt.AcceptedRating Green (cxh) 070 */ 071public class StringAttribute extends AbstractSettableAttribute { 072 /** Construct an attribute in the default workspace with an empty string 073 * as its name. 074 * The object is added to the directory of the workspace. 075 * Increment the version number of the workspace. 076 */ 077 public StringAttribute() { 078 super(); 079 _value = ""; 080 } 081 082 /** Construct an attribute in the specified workspace with an empty 083 * string as a name. 084 * The object is added to the directory of the workspace. 085 * Increment the version number of the workspace. 086 * @param workspace The workspace that will list the attribute. 087 */ 088 public StringAttribute(Workspace workspace) { 089 super(workspace); 090 _value = ""; 091 } 092 093 /** Construct an attribute with the given name contained by the specified 094 * container. The container argument must not be null, or a 095 * NullPointerException will be thrown. This attribute will use the 096 * workspace of the container for synchronization and version counts. 097 * If the name argument is null, then the name is set to the empty 098 * string. The object is added to the directory of the workspace 099 * if the container is null. 100 * Increment the version of the workspace. 101 * @param container The container. 102 * @param name The name of this attribute. 103 * @exception IllegalActionException If the attribute is not of an 104 * acceptable class for the container, or if the name contains a period. 105 * @exception NameDuplicationException If the name coincides with 106 * an attribute already in the container. 107 */ 108 public StringAttribute(NamedObj container, String name) 109 throws IllegalActionException, NameDuplicationException { 110 super(container, name); 111 _value = ""; 112 } 113 114 /////////////////////////////////////////////////////////////////// 115 //// public methods //// 116 117 /** Add a listener to be notified when the value of this attribute changes. 118 * If the listener is already on the list of listeners, then do nothing. 119 * @param listener The listener to add. 120 * @see #removeValueListener(ValueListener) 121 */ 122 @Override 123 public void addValueListener(ValueListener listener) { 124 if (_valueListeners == null) { 125 _valueListeners = new LinkedList(); 126 } 127 128 if (!_valueListeners.contains(listener)) { 129 _valueListeners.add(listener); 130 } 131 } 132 133 /** Clone the object into the specified workspace. 134 * @param workspace The workspace for the new object. 135 * @return A new NamedObj. 136 * @exception CloneNotSupportedException If any of the attributes 137 * cannot be cloned. 138 */ 139 @Override 140 public Object clone(Workspace workspace) throws CloneNotSupportedException { 141 StringAttribute newObject = (StringAttribute) super.clone(workspace); 142 newObject._valueListeners = null; 143 return newObject; 144 } 145 146 /** Write a MoML description of this object, unless it is non-persistent. 147 * MoML is an XML modeling markup language. 148 * In this class, the object is identified by the "property" 149 * element, with "name", "class", and "value" (XML) attributes. 150 * The body of the element, between the "<property>" 151 * and "</property>", is written using 152 * the _exportMoMLContents() protected method, so that derived classes 153 * can override that method alone to alter only how the contents 154 * of this object are described. 155 * The text that is written is indented according to the specified 156 * depth, with each line (including the last one) 157 * terminated with a newline. 158 * @param output The output stream to write to. 159 * @param depth The depth in the hierarchy, to determine indenting. 160 * @param name The name to use instead of the current name. 161 * @exception IOException If an I/O error occurs. 162 * @see #isPersistent() 163 */ 164 @Override 165 public void exportMoML(Writer output, int depth, String name) 166 throws IOException { 167 if (_isMoMLSuppressed(depth)) { 168 return; 169 } 170 171 String value = getExpression(); 172 String valueTerm = ""; 173 174 if (value != null && !value.equals("")) { 175 valueTerm = " value=\"" + StringUtilities.escapeForXML(value) 176 + "\""; 177 } 178 179 // Escape any < character in name. unescapeForXML occurs in 180 // NamedObj.setName(String). 181 name = StringUtilities.escapeForXML(name); 182 183 output.write(_getIndentPrefix(depth) + "<" + _elementName + " name=\"" 184 + name + "\" class=\"" + getClassName() + "\"" + valueTerm 185 + ">\n"); 186 _exportMoMLContents(output, depth + 1); 187 output.write(_getIndentPrefix(depth) + "</" + _elementName + ">\n"); 188 } 189 190 /** Get the value that has been set by setExpression(), 191 * or null if there is none. 192 * @return The string value. 193 * @see #setExpression(String) 194 */ 195 @Override 196 public String getExpression() { 197 return _value; 198 } 199 200 /** Get the visibility of this attribute, as set by setVisibility(). 201 * The visibility is set by default to FULL. 202 * @return The visibility of this attribute. 203 * @see #setVisibility(Settable.Visibility) 204 */ 205 @Override 206 public Settable.Visibility getVisibility() { 207 return _visibility; 208 } 209 210 /** Remove a listener from the list of listeners that is 211 * notified when the value of this attribute changes. If no such listener 212 * exists, do nothing. 213 * @param listener The listener to remove. 214 * @see #addValueListener(ValueListener) 215 */ 216 @Override 217 public void removeValueListener(ValueListener listener) { 218 if (_valueListeners != null) { 219 _valueListeners.remove(listener); 220 } 221 } 222 223 /** Set the value of the string attribute and notify the container 224 * of the value of this attribute by calling attributeChanged(). 225 * Notify any value listeners of this attribute. 226 * @param expression The value of the string attribute. 227 * @exception IllegalActionException If the change is not acceptable 228 * to the container. 229 * @see #getExpression() 230 */ 231 @Override 232 public void setExpression(String expression) throws IllegalActionException { 233 super.setExpression(expression); 234 _value = expression; 235 236 // Notify the container and any value listeners immediately, 237 // rather than deferring to validate(). 238 NamedObj container = getContainer(); 239 240 if (container != null) { 241 container.attributeChanged(this); 242 } 243 244 if (_valueListeners != null) { 245 Iterator listeners = _valueListeners.iterator(); 246 247 while (listeners.hasNext()) { 248 ValueListener listener = (ValueListener) listeners.next(); 249 listener.valueChanged(this); 250 } 251 } 252 } 253 254 /** Set the visibility of this attribute. The argument should be one 255 * of the public static instances in Settable. 256 * @param visibility The visibility of this attribute. 257 * @see #getVisibility() 258 */ 259 @Override 260 public void setVisibility(Settable.Visibility visibility) { 261 _visibility = visibility; 262 } 263 264 /** Do nothing. 265 * There is no need to notify the container or listeners of this 266 * attribute because they have presumably already been notified 267 * in setExpression(). 268 * @return Null, indicating that no other instances of Settable are 269 * validated. 270 * @exception IllegalActionException If the change is not acceptable 271 * to the container. 272 */ 273 @Override 274 public Collection validate() throws IllegalActionException { 275 return null; 276 } 277 278 /////////////////////////////////////////////////////////////////// 279 //// protected methods //// 280 281 /** Propagate the value of this object to the 282 * specified object. The specified object is required 283 * to be an instance of the same class as this one, or 284 * a ClassCastException will be thrown. 285 * @param destination Object to which to propagate the 286 * value. 287 * @exception IllegalActionException If the value cannot 288 * be propagated. 289 */ 290 @Override 291 protected void _propagateValue(NamedObj destination) 292 throws IllegalActionException { 293 ((Settable) destination).setExpression(getExpression()); 294 } 295 296 /////////////////////////////////////////////////////////////////// 297 //// private variables //// 298 // The value. 299 private String _value; 300 301 // Listeners for changes in value. 302 private List _valueListeners; 303 304 // The visibility of this attribute, which defaults to FULL. 305 private Settable.Visibility _visibility = Settable.FULL; 306}