001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visualweb.propertyeditors;
042:
043: import com.sun.rave.designtime.DesignProperty;
044: import java.beans.PropertyDescriptor;
045: import java.text.MessageFormat;
046: import java.util.ResourceBundle;
047:
048: /**
049: * An abstract property editor base class for editors that deal with numbers.
050: * Values submitted must be valid numbers, and must fall within the default
051: * range for the type of number, of the range specified by the user, whichever
052: * is most restrictive. Range values may be supplied as the property descriptor
053: * attributes <code>MIN_VALUE</code> and <code>MAX_VALUE</code>.
054: *
055: * <p>This editor class may be used with properties of type string, or of any
056: * type that inherits from {@link java.lang.Number} or an atomic number type. If
057: * used with a property of type string, numbers will be converted to strings
058: * before being returned by getValue().
059: *
060: * <p>This editor class supports the notion of an "unset" or "null" value.
061: * Normally, a number editor's value is what it displays. If a non-numeric string
062: * is submitted as a candidate text value, the <code>setAsText(String)</code>
063: * method will throw an illegal argument exception, causing the previous,
064: * correct value to be restored. However, if the editor is configured to
065: * accept an "unset" vaue (using the property descriptor attribute
066: * <code>UNSET_VALUE</code>), submitting an empty string will cause the editor
067: * to return the specified unset value as its new value. When thus configured,
068: * the editor maintains a map between one numeric value and the empty text
069: * string. Note that the caller of the editor's <code>getValue()</code> method
070: * cannot distinguish between the case where the value, if equal to the "unset"
071: * value, is being returned because the user entered the empty string, or
072: * because the user explicitly typed it in. For the purposes of triggering an
073: * "unset" value, a string consisting of only blank characters is considered
074: * empty.
075: *
076: * @author gjmurphy
077: */
078: public abstract class NumberPropertyEditor extends PropertyEditorBase {
079:
080: static ResourceBundle bundle = ResourceBundle
081: .getBundle(NumberPropertyEditor.class.getPackage()
082: .getName()
083: + ".Bundle"); //NOI18N
084:
085: /** Name of property descriptor attribute used to specify a minimum value.
086: * Values may be specified as strings, or as instances of {@link java.lang.Number}
087: * or any of its subclasses.
088: */
089: public static final String MIN_VALUE = "com.sun.rave.propertyeditors.MIN_VALUE"; // NOI18N
090:
091: /** Name of property descriptor attribute used to specify a maximum value.
092: * Values may be specified as strings, or as instances of {@link java.lang.Number}
093: * or any of its subclasses.
094: */
095: public static final String MAX_VALUE = "com.sun.rave.propertyeditors.MAX_VALUE"; // NOI18N
096:
097: String unsetText;
098: Object value;
099: Class propertyType;
100: Number minValue;
101: Number maxValue;
102:
103: private Number defaultMinValue;
104: private Number defaultMaxValue;
105:
106: NumberPropertyEditor(Number defaultMinValue, Number defaultMaxValue) {
107: this .minValue = defaultMinValue;
108: this .maxValue = defaultMaxValue;
109: this .defaultMinValue = defaultMinValue;
110: this .defaultMaxValue = defaultMaxValue;
111: this .value = null;
112: }
113:
114: /**
115: * Convert a string to a number. Implementing classes should return a
116: * subclass of {@link java.lang.Number} appropriate to the type of number
117: * that they support.
118: */
119: protected abstract Number parseString(String string)
120: throws IllegalTextArgumentException;
121:
122: public void setDesignProperty(DesignProperty designProperty) {
123:
124: super .setDesignProperty(designProperty);
125: PropertyDescriptor descriptor = designProperty
126: .getPropertyDescriptor();
127:
128: // Initialize min value
129: Number number = null;
130: Object value = descriptor.getValue(MIN_VALUE);
131: if (value instanceof String)
132: try {
133: number = parseString((String) value);
134: } catch (NumberFormatException e) {
135: number = null;
136: // Report error
137: }
138: else if (value instanceof Number)
139: number = (Number) value;
140: if (number != null
141: && ((Comparable) number).compareTo(defaultMinValue) >= 0)
142: minValue = number;
143:
144: // Initialize max value
145: number = null;
146: value = descriptor.getValue(MAX_VALUE);
147: if (value instanceof String)
148: try {
149: number = parseString((String) value);
150: } catch (NumberFormatException e) {
151: number = null;
152: // Report error
153: }
154: else if (value instanceof Number)
155: number = (Number) value;
156: if (number != null
157: && ((Comparable) number).compareTo(defaultMaxValue) <= 0)
158: maxValue = number;
159:
160: propertyType = designProperty.getPropertyDescriptor()
161: .getPropertyType();
162:
163: }
164:
165: public void setValue(Object value) {
166: if (value == null) {
167: this .value = null;
168: } else {
169: if (String.class.isAssignableFrom(value.getClass())) {
170: this .setAsText((String) value);
171: } else if (Number.class.isAssignableFrom(value.getClass())) {
172: this .value = (Number) value;
173: } else {
174: throw new IllegalArgumentException();
175: }
176: }
177: }
178:
179: public Object getValue() {
180: if (this .value == null)
181: return null;
182: if (String.class.isAssignableFrom(this .propertyType))
183: return this .value.toString();
184: return this .value;
185: }
186:
187: public String getAsText() {
188: if (this .value == null) {
189: return "";
190: }
191: if (this .value.equals(super .unsetValue)
192: && value instanceof Comparable) {
193: Comparable c = (Comparable) value;
194: if (c.compareTo(this .minValue) <= 0
195: || c.compareTo(this .maxValue) >= 0)
196: return "";
197: }
198: return this .value.toString();
199: }
200:
201: public void setAsText(String str) throws IllegalArgumentException {
202: str = str == null ? "" : str.trim();
203: if (str.length() == 0) {
204: this .value = super .unsetValue;
205: } else {
206: Number n = parseString(str);
207: if (((Comparable) n).compareTo(minValue) >= 0
208: && ((Comparable) n).compareTo(maxValue) <= 0) {
209: this .value = n;
210: } else {
211: String rangeErrorMessage = null;
212: int maxCompare = ((Comparable) maxValue)
213: .compareTo(defaultMaxValue);
214: int minCompare = ((Comparable) minValue)
215: .compareTo(defaultMinValue);
216: if (maxCompare > 0 && minCompare < 0)
217: rangeErrorMessage = MessageFormat
218: .format(
219: bundle
220: .getString("NumberPropertyEditor.rangeErrorMessage"),
221: new Number[] { minValue, maxValue });
222: else if (maxCompare < 0)
223: rangeErrorMessage = MessageFormat
224: .format(
225: bundle
226: .getString("NumberPropertyEditor.rangeMaxErrorMessage"),
227: new Number[] { maxValue });
228: else if (minCompare > 0)
229: rangeErrorMessage = MessageFormat
230: .format(
231: bundle
232: .getString("NumberPropertyEditor.rangeMinErrorMessage"),
233: new Number[] { minValue });
234: throw new IllegalTextArgumentException(
235: rangeErrorMessage);
236: }
237: }
238: }
239:
240: }
|