001/* A parameter with type double with a limited range. 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.actor.parameters; 029 030import ptolemy.data.DoubleToken; 031import ptolemy.data.Token; 032import ptolemy.data.expr.Parameter; 033import ptolemy.data.expr.StringParameter; 034import ptolemy.data.type.BaseType; 035import ptolemy.kernel.util.Attribute; 036import ptolemy.kernel.util.IllegalActionException; 037import ptolemy.kernel.util.NameDuplicationException; 038import ptolemy.kernel.util.NamedObj; 039 040/////////////////////////////////////////////////////////////////// 041//// DoubleRangeParameter 042 043/** 044 This is a parameter with type double with a limited range and 045 limited precision. 046 Its value is an double token that is constrained to lie 047 within the boundaries specified by its two parameters, 048 <i>min</i> and <i>max</i>, inclusive. Moreover, the values 049 are quantized so that there are exactly <i>precision</i> 050 values, uniformly spaced in the range. 051 A user interface will typically use this 052 information to represent the parameter value using a slider 053 which can be decorated by labels indicating the minimum and 054 maximum values. The actual text displayed by the labels can 055 be set using the <i>minLabel</i> and <i>maxLabel</i> parameters 056 which default to showing the actual minimum and maximum double value. 057 The default values for <i>min</i> and <i>max</i> are 0.0 and 1.0, 058 with a default value of 0.5. The default <i>precision</i> is 100. 059 <p> 060 @author Edward A. Lee, Christoph Daniel Schulze 061 @version $Id$ 062 @since Ptolemy II 4.1 063 @Pt.ProposedRating Yellow (eal) 064 @Pt.AcceptedRating Red (cxh) 065 */ 066public class DoubleRangeParameter extends Parameter { 067 /** Construct an attribute with the given name contained by the 068 * specified container. The container argument must not be null, or a 069 * NullPointerException will be thrown. This attribute will use the 070 * workspace of the container for synchronization and version counts. 071 * If the name argument is null, then the name is set to the empty 072 * string. Increment the version of the workspace. 073 * @param container The container. 074 * @param name The name of this attribute. 075 * @exception IllegalActionException If the attribute is not of an 076 * acceptable class for the container, or if the name contains a period. 077 * @exception NameDuplicationException If the name coincides with 078 * an attribute already in the container. 079 */ 080 public DoubleRangeParameter(NamedObj container, String name) 081 throws IllegalActionException, NameDuplicationException { 082 super(container, name); 083 084 min = new Parameter(this, "min"); 085 min.setExpression("0.0"); 086 min.setTypeEquals(BaseType.DOUBLE); 087 088 max = new Parameter(this, "max"); 089 max.setExpression("1.0"); 090 max.setTypeEquals(BaseType.DOUBLE); 091 092 precision = new Parameter(this, "precision"); 093 precision.setExpression("100"); 094 precision.setTypeEquals(BaseType.INT); 095 096 minLabel = new StringParameter(this, "minLabel"); 097 minLabel.setExpression("$min"); 098 099 maxLabel = new StringParameter(this, "maxLabel"); 100 maxLabel.setExpression("$max"); 101 102 // We can't set a default value because then 103 // restore defaults will restore to this value, 104 // but this may be out of range for a particular 105 // application. 106 // setExpression("0.5"); 107 setTypeEquals(BaseType.DOUBLE); 108 109 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-30\" y=\"-2\" " 110 + "width=\"60\" height=\"4\" " + "style=\"fill:white\"/>\n" 111 + "<rect x=\"15\" y=\"-10\" " + "width=\"4\" height=\"20\" " 112 + "style=\"fill:grey\"/>\n" + "</svg>\n"); 113 } 114 115 /////////////////////////////////////////////////////////////////// 116 //// parameters //// 117 118 /** The maximum value. This is has a double value, and defaults to 1.0. */ 119 public Parameter max; 120 121 /** The minimum value. This is has a double value, and defaults to 0.0. */ 122 public Parameter min; 123 124 /** The precision, which is the number of possible values. 125 * This is has an integer value, and defaults to 100. 126 */ 127 public Parameter precision; 128 129 /** The label text displayed for the maximum end of the slider. This is a String, 130 * and defaults to {@code $max}, which is expanded to the value of the {@code max} 131 * parameter in the user interface. 132 */ 133 public StringParameter maxLabel; 134 135 /** The label text displayed for the minimum end of the slider. This is a String, 136 * and defaults to {@code $min}, which is expanded to the value of the {@code min} 137 * parameter in the user interface. 138 */ 139 public StringParameter minLabel; 140 141 /////////////////////////////////////////////////////////////////// 142 //// public methods //// 143 144 /** React to a change in an attribute by ensuring that the current 145 * value remains within the range given by <i>min</i> and <i>max</i>. 146 * @param attribute The attribute that changed. 147 * @exception IllegalActionException If the change is not acceptable 148 * to this container (should not be thrown). 149 */ 150 @Override 151 public void attributeChanged(Attribute attribute) 152 throws IllegalActionException { 153 if (attribute == max && !_inCheck) { 154 try { 155 _inCheck = true; 156 157 double maxValue = ((DoubleToken) max.getToken()).doubleValue(); 158 double value = ((DoubleToken) getToken()).doubleValue(); 159 160 if (value > maxValue) { 161 setToken(max.getToken()); 162 } 163 } finally { 164 _inCheck = false; 165 } 166 } else if (attribute == min && !_inCheck) { 167 try { 168 _inCheck = true; 169 170 double minValue = ((DoubleToken) min.getToken()).doubleValue(); 171 double value = ((DoubleToken) getToken()).doubleValue(); 172 173 if (value < minValue) { 174 setToken(min.getToken()); 175 } 176 } finally { 177 _inCheck = false; 178 } 179 } else { 180 super.attributeChanged(attribute); 181 } 182 } 183 184 /////////////////////////////////////////////////////////////////// 185 //// protected methods //// 186 187 /* Set the token value and type of the variable, and notify the 188 * container that the value (and type, if appropriate) has changed. 189 * Also notify value dependents that they need to be re-evaluated, 190 * and notify any listeners that have been registered with 191 * addValueListener(). 192 * If setTypeEquals() has been called, then attempt to convert 193 * the specified token into one of the appropriate type, if needed, 194 * rather than changing the type. 195 * @param newToken The new value of the variable. 196 * @exception IllegalActionException If the token is not an IntToken 197 * or its value is out of range. 198 */ 199 @Override 200 protected void _setTokenAndNotify(Token newToken) 201 throws IllegalActionException { 202 if (_inCheck) { 203 super._setTokenAndNotify(newToken); 204 return; 205 } 206 207 if (newToken instanceof DoubleToken) { 208 try { 209 _inCheck = true; 210 211 double minValue = ((DoubleToken) min.getToken()).doubleValue(); 212 double maxValue = ((DoubleToken) max.getToken()).doubleValue(); 213 double currentValue = ((DoubleToken) newToken).doubleValue(); 214 215 if (minValue <= currentValue && currentValue <= maxValue) { 216 // All is OK. 217 super._setTokenAndNotify(newToken); 218 return; 219 } 220 221 throw new IllegalActionException(this, 222 "Value is required to lie between " + min + " and " 223 + max + "."); 224 } finally { 225 _inCheck = false; 226 } 227 } 228 229 throw new IllegalActionException(this, 230 "Value is required to be a double token."); 231 } 232 233 /////////////////////////////////////////////////////////////////// 234 //// private variables //// 235 236 /** Indicator that we are in the middle of a check, so skip 237 * circular dependency. 238 */ 239 private boolean _inCheck = false; 240}