001/* A parameter with type integer with a limited range. 002 003 Copyright (c) 2001-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.IntToken; 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//// IntRangeParameter 042 043/** 044 <p>This is a parameter with type integer with a limited range. 045 Its value is an integer token that is constrained to lie 046 within the boundaries specified by its two parameters, 047 <i>min</i> and <i>max</i>. These specify the minimum and maximum values. 048 A user interface will typically use this 049 information to represent the parameter value using a slider 050 which can be decorated by labels indicating the minimum and 051 maximum values. The actual text displayed by the labels can 052 be set using the <i>minLabel</i> and <i>maxLabel</i> parameters 053 which default to showing the actual minimum and maximum int value. 054 The default values for <i>min</i> and <i>max</i> are 0 and 100, 055 respectively, and the default value for this parameter is 50. 056 </p> 057 058 @author Edward A. Lee, Christoph Daniel Schulze 059 @version $Id$ 060 @since Ptolemy II 3.0 061 @Pt.ProposedRating Yellow (eal) 062 @Pt.AcceptedRating Red (cxh) 063 */ 064public class IntRangeParameter extends Parameter { 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 IntRangeParameter(NamedObj container, String name) 079 throws IllegalActionException, NameDuplicationException { 080 super(container, name); 081 082 min = new Parameter(this, "min"); 083 min.setExpression("0"); 084 min.setTypeEquals(BaseType.INT); 085 086 max = new Parameter(this, "max"); 087 max.setExpression("100"); 088 max.setTypeEquals(BaseType.INT); 089 090 minLabel = new StringParameter(this, "minLabel"); 091 minLabel.setExpression("$min"); 092 093 maxLabel = new StringParameter(this, "maxLabel"); 094 maxLabel.setExpression("$max"); 095 096 setExpression("50"); 097 setTypeEquals(BaseType.INT); 098 099 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-30\" y=\"-2\" " 100 + "width=\"60\" height=\"4\" " + "style=\"fill:white\"/>\n" 101 + "<rect x=\"15\" y=\"-10\" " + "width=\"4\" height=\"20\" " 102 + "style=\"fill:grey\"/>\n" + "</svg>\n"); 103 } 104 105 /////////////////////////////////////////////////////////////////// 106 //// parameters //// 107 108 /** The maximum value. This is has an integer value, and defaults to 100. */ 109 public Parameter max; 110 111 /** The minimum value. This is has an integer value, and defaults to 0. */ 112 public Parameter min; 113 114 /** The label text displayed for the maximum end of the slider. This is a String, 115 * and defaults to {@code $max}, which is expanded to the value of the {@code max} 116 * parameter in the user interface. 117 */ 118 public StringParameter maxLabel; 119 120 /** The label text displayed for the minimum end of the slider. This is a String, 121 * and defaults to {@code $min}, which is expanded to the value of the {@code min} 122 * parameter in the user interface. 123 */ 124 public StringParameter minLabel; 125 126 /////////////////////////////////////////////////////////////////// 127 //// public methods //// 128 129 /** React to a change in an attribute by ensuring that the current 130 * value remains within the range given by <i>min</i> and <i>max</i>. 131 * @param attribute The attribute that changed. 132 * @exception IllegalActionException If the change is not acceptable 133 * to this container (should not be thrown). 134 */ 135 @Override 136 public void attributeChanged(Attribute attribute) 137 throws IllegalActionException { 138 if (attribute == max && !_inCheck) { 139 try { 140 _inCheck = true; 141 142 int maxValue = ((IntToken) max.getToken()).intValue(); 143 144 if (getCurrentValue() > maxValue) { 145 setToken(max.getToken()); 146 } 147 } finally { 148 _inCheck = false; 149 } 150 } else if (attribute == min && !_inCheck) { 151 try { 152 _inCheck = true; 153 154 int minValue = ((IntToken) min.getToken()).intValue(); 155 156 if (getCurrentValue() < minValue) { 157 setToken(min.getToken()); 158 } 159 } finally { 160 _inCheck = false; 161 } 162 } else { 163 super.attributeChanged(attribute); 164 } 165 } 166 167 /** Return the current value of this parameter as an integer. 168 * @return The current value. 169 * @exception IllegalActionException If the expression cannot 170 * be parsed or cannot be evaluated, or if the result of evaluation 171 * violates type constraints, or if the result of evaluation is null 172 * and there are variables that depend on this one. 173 */ 174 public int getCurrentValue() throws IllegalActionException { 175 return ((IntToken) getToken()).intValue(); 176 } 177 178 /** Return the maximum value of this parameter as an integer. 179 * @return The maximum value. 180 * @exception IllegalActionException If the expression cannot 181 * be parsed or cannot be evaluated, or if the result of evaluation 182 * violates type constraints, or if the result of evaluation is null 183 * and there are variables that depend on this one. 184 */ 185 public int getMaxValue() throws IllegalActionException { 186 return ((IntToken) max.getToken()).intValue(); 187 } 188 189 /** Return the minimum value of this parameter. 190 * @return The minimum value. 191 * @exception IllegalActionException If the expression cannot 192 * be parsed or cannot be evaluated, or if the result of evaluation 193 * violates type constraints, or if the result of evaluation is null 194 * and there are variables that depend on this one. 195 */ 196 public int getMinValue() throws IllegalActionException { 197 return ((IntToken) min.getToken()).intValue(); 198 } 199 200 /////////////////////////////////////////////////////////////////// 201 //// protected methods //// 202 203 /* Set the token value and type of the variable, and notify the 204 * container that the value (and type, if appropriate) has changed. 205 * Also notify value dependents that they need to be re-evaluated, 206 * and notify any listeners that have been registered with 207 * addValueListener(). 208 * If setTypeEquals() has been called, then attempt to convert 209 * the specified token into one of the appropriate type, if needed, 210 * rather than changing the type. 211 * @param newToken The new value of the variable. 212 * @exception IllegalActionException If the token is not an IntToken 213 * or its value is out of range. 214 */ 215 @Override 216 protected void _setTokenAndNotify(Token newToken) 217 throws IllegalActionException { 218 if (_inCheck) { 219 super._setTokenAndNotify(newToken); 220 return; 221 } 222 223 if (newToken instanceof IntToken) { 224 try { 225 _inCheck = true; 226 227 int minValue = ((IntToken) min.getToken()).intValue(); 228 int maxValue = ((IntToken) max.getToken()).intValue(); 229 int currentValue = ((IntToken) newToken).intValue(); 230 231 if (minValue <= currentValue && currentValue <= maxValue) { 232 // All is OK. 233 super._setTokenAndNotify(newToken); 234 return; 235 } 236 237 throw new IllegalActionException(this, 238 "Value is required to lie between " + min + " and " 239 + max + "."); 240 } finally { 241 _inCheck = false; 242 } 243 } 244 245 throw new IllegalActionException(this, 246 "Value is required to be an integer token."); 247 } 248 249 /////////////////////////////////////////////////////////////////// 250 //// private variables //// 251 252 /** Indicator that we are in the middle of a check, so skip 253 * circular dependency. 254 */ 255 private boolean _inCheck = false; 256}