001/* An attribute that displays the value of an attribute of the container. 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.math.RoundingMode; 031import java.text.NumberFormat; 032import java.util.Collection; 033 034import ptolemy.data.BooleanToken; 035import ptolemy.data.DoubleToken; 036import ptolemy.data.IntToken; 037import ptolemy.data.Token; 038import ptolemy.data.expr.ModelScope; 039import ptolemy.data.expr.Parameter; 040import ptolemy.data.expr.Variable; 041import ptolemy.data.type.BaseType; 042import ptolemy.kernel.util.Attribute; 043import ptolemy.kernel.util.ChangeRequest; 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.kernel.util.ValueListener; 050 051/////////////////////////////////////////////////////////////////// 052//// AttributeValueAttribute 053 054/** 055 This is a text attribute whose text string shows the 056 value of a parameter. <p> 057 058 @author Steve Neuendorffer 059 @version $Id$ 060 @since Ptolemy II 4.1 061 @Pt.ProposedRating Yellow (eal) 062 @Pt.AcceptedRating Red (cxh) 063 */ 064public class AttributeValueAttribute extends AbstractTextAttribute 065 implements ValueListener, Settable { 066 // NOTE: This attribute only implements settable as a workaround 067 // to ensure that it gets notified of the start of execution. 068 // Unfortunately, most of the code in the Variable class is 069 // written to be specific to Variables, making it difficult for 070 // this class to properly listen to a variable by name. 071 072 /** Construct an attribute with the given name contained by the 073 * specified container. The container argument must not be null, or a 074 * NullPointerException will be thrown. This attribute will use the 075 * workspace of the container for synchronization and version counts. 076 * If the name argument is null, then the name is set to the empty 077 * string. Increment the version of the workspace. 078 * @param container The container. 079 * @param name The name of this attribute. 080 * @exception IllegalActionException If the attribute is not of an 081 * acceptable class for the container, or if the name contains a period. 082 * @exception NameDuplicationException If the name coincides with 083 * an attribute already in the container. 084 */ 085 public AttributeValueAttribute(NamedObj container, String name) 086 throws IllegalActionException, NameDuplicationException { 087 super(container, name); 088 089 attributeName = new StringAttribute(this, "attributeName"); 090 displayWidth = new Parameter(this, "displayWidth"); 091 displayWidth.setExpression("6"); 092 displayWidth.setTypeEquals(BaseType.INT); 093 094 useExpression = new Parameter(this, "useExpression"); 095 useExpression.setExpression("false"); 096 useExpression.setTypeEquals(BaseType.BOOLEAN); 097 098 } 099 100 /////////////////////////////////////////////////////////////////// 101 //// parameters //// 102 103 /** The name of the attribute of the container whose value to display. */ 104 public StringAttribute attributeName; 105 106 /** The number of characters to display. This is an integer, with 107 * default value 6. 108 */ 109 public Parameter displayWidth; 110 111 /** If true, display the expression rather than the value. 112 * This is a boolean that defaults to false. 113 */ 114 public Parameter useExpression; 115 116 /////////////////////////////////////////////////////////////////// 117 //// public methods //// 118 119 /** React to a changes in the attributes by changing the icon. 120 * @param attribute The attribute that changed. 121 * @exception IllegalActionException If the change is not acceptable 122 * to this container (should not be thrown). 123 */ 124 @Override 125 public void attributeChanged(Attribute attribute) 126 throws IllegalActionException { 127 if (attribute == attributeName) { 128 _setAttributeName(attributeName.getExpression()); 129 } else if (attribute == displayWidth) { 130 _displayWidth = ((IntToken) displayWidth.getToken()).intValue(); 131 _icon.setText(_getText()); 132 } else { 133 super.attributeChanged(attribute); 134 } 135 } 136 137 /** React to a change in the value of the associated attribute. 138 */ 139 @Override 140 public void valueChanged(Settable settable) { 141 _setAttributeName(attributeName.getExpression()); 142 } 143 144 /** Add a listener to be notified when the value of this settable 145 * object changes. This implementation ignores the argument, so 146 * listeners to this object are not notified of changes in value. 147 * @param listener The listener to add. 148 * @see #removeValueListener(ValueListener) 149 */ 150 @Override 151 public void addValueListener(ValueListener listener) { 152 } 153 154 /** Return the default value of this attribute, if there is 155 * one, or null if there is none. 156 * @return The default value of this attribute, or null 157 * if there is none. 158 */ 159 @Override 160 public String getDefaultExpression() { 161 return ""; 162 } 163 164 /** Return a name to present to the user, which 165 * is the same as the name returned by getName(). 166 * @return A name to present to the user. 167 */ 168 @Override 169 public String getDisplayName() { 170 return getName(); 171 } 172 173 /** Get the value of the attribute that has been set by setExpression(), 174 * or null if there is none. 175 * @return The expression. This base class always returns 176 * the empty string "". 177 * @see #setExpression(String) 178 */ 179 @Override 180 public String getExpression() { 181 return ""; 182 } 183 184 /** Get the value of the attribute, which is the evaluated expression. 185 * @return The same as getExpression(). 186 * @see #getExpression() 187 */ 188 @Override 189 public String getValueAsString() { 190 return getExpression(); 191 } 192 193 /** Get the visibility of this Settable, as set by setVisibility(). 194 * If setVisibility() has not been called, then implementations of 195 * this interface should return some default, not null, indicating 196 * user-level visibility. The returned value is one of the static 197 * instances of the Visibility inner class. 198 * @return The visibility of this Settable. 199 * @see #setVisibility(Settable.Visibility) 200 */ 201 @Override 202 public Settable.Visibility getVisibility() { 203 return Settable.NONE; 204 } 205 206 /** Remove a listener from the list of listeners that are 207 * notified when the value of this variable changes. This 208 * implementation ignores the argument. 209 * @param listener The listener to remove. 210 * @see #addValueListener(ValueListener) 211 */ 212 @Override 213 public void removeValueListener(ValueListener listener) { 214 } 215 216 /** Set the value of the attribute by giving some expression. 217 * In this implementation, the specified value is ignored. 218 * @param expression The value of the attribute, which is ignored. 219 * @exception IllegalActionException If the expression is invalid. 220 * @see #getExpression() 221 */ 222 @Override 223 public void setExpression(String expression) throws IllegalActionException { 224 } 225 226 /** Set the visibility of this Settable. This call does nothing. 227 * @param visibility The visibility of this Settable. 228 * @see #getVisibility() 229 */ 230 @Override 231 public void setVisibility(Settable.Visibility visibility) { 232 } 233 234 /** Set the attribute name to match the current expression. 235 * @return Null, indicating that no other instances of Settable 236 * are validated. 237 * @exception IllegalActionException If the expression is not valid, or 238 * its value is not acceptable to the container or the listeners. 239 */ 240 @Override 241 public Collection validate() throws IllegalActionException { 242 _setAttributeName(attributeName.getExpression()); 243 return null; 244 } 245 246 /////////////////////////////////////////////////////////////////// 247 //// protected methods //// 248 249 /** Set the attribute name. 250 * @param attributeName The attribute name. 251 */ 252 protected void _setAttributeName(final String attributeName) { 253 NamedObj container = getContainer(); 254 255 if (container != null) { 256 Attribute newAttribute = ModelScope.getScopedVariable(null, 257 container, attributeName); 258 if (newAttribute == null) { 259 // Either the specified attribute name is invalid, 260 // or this is getting invoked in the constructor, and the 261 // attribute being referenced has not yet been constructed. 262 // To support the latter situation, we try again (just one 263 // more time) in a ChangeRequest. 264 if (!_deferred) { 265 ChangeRequest request = new ChangeRequest(this, 266 "AttributeValueAttribute") { 267 @Override 268 protected void _execute() { 269 _setAttributeName(attributeName); 270 _deferred = false; 271 } 272 }; 273 _deferred = true; 274 container.requestChange(request); 275 } 276 _attribute = null; 277 } else if (_attribute != newAttribute) { 278 if (_attribute != null) { 279 _attribute.removeValueListener(this); 280 } 281 282 // newAttribute will always be a Settable. 283 _attribute = (Settable) newAttribute; 284 _attribute.addValueListener(this); 285 } 286 } 287 288 _icon.setText(_getText()); 289 } 290 291 /** Return a new string that contains the expression of the 292 * referred to attribute. 293 * @return A new shape. 294 */ 295 protected String _getText() { 296 NamedObj container = getContainer(); 297 298 try { 299 if (container != null) { 300 if (_attribute instanceof Variable) { 301 String value; 302 if (!((BooleanToken) useExpression.getToken()) 303 .booleanValue()) { 304 Token token = ((Variable) _attribute).getToken(); 305 value = "absent"; 306 if (token != null) { 307 value = token.toString(); 308 // Suppress scientific notation if it's a double. 309 if (token instanceof DoubleToken) { 310 double doubleValue = ((DoubleToken) token) 311 .doubleValue(); 312 NumberFormat format = NumberFormat 313 .getInstance(); 314 format.setGroupingUsed(false); 315 format.setMinimumFractionDigits(1); 316 format.setRoundingMode( 317 RoundingMode.UNNECESSARY); 318 value = format.format(doubleValue); 319 // If the value shown is 0.0, make sure it's actually zero. 320 if (value.equals("0.0") && doubleValue != 0.0) { 321 value = "0.00000..."; 322 } 323 } 324 } 325 } else { 326 value = _attribute.getExpression(); 327 } 328 String truncated = value; 329 int width = _displayWidth; 330 331 if (value.length() > width) { 332 truncated = value.substring(0, width) + "..."; 333 } 334 335 if (truncated.length() == 0) { 336 truncated = " "; 337 } 338 339 return truncated; 340 } else { 341 String value = _attribute.getExpression(); 342 String truncated = value; 343 int width = _displayWidth; 344 345 if (value.length() > width) { 346 truncated = value.substring(0, width) + "..."; 347 } 348 349 if (truncated.length() == 0) { 350 truncated = " "; 351 } 352 353 return truncated; 354 } 355 } 356 } catch (Throwable throwable) { 357 return "???"; 358 } 359 360 return "???"; 361 } 362 363 /////////////////////////////////////////////////////////////////// 364 //// protected members //// 365 366 /** Most recent value of the rounding parameter. */ 367 protected int _displayWidth = 0; 368 369 /** The associated attribute. */ 370 protected Settable _attribute = null; 371 372 /////////////////////////////////////////////////////////////////// 373 //// private members //// 374 375 /** Flag indicating that we have already tried deferring evaluation. */ 376 private boolean _deferred = false; 377}