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-2006 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:
042: package org.netbeans.beaninfo.editors;
043:
044: import java.util.StringTokenizer;
045: import java.text.MessageFormat;
046: import org.netbeans.core.UIExceptions;
047: import org.openide.explorer.propertysheet.ExPropertyEditor;
048: import org.openide.explorer.propertysheet.PropertyEnv;
049: import org.openide.explorer.propertysheet.editors.XMLPropertyEditor;
050:
051: /** Support for property editors for several integers.
052: * for example: Point - [2,4], Insets [2,3,4,4],...
053: *
054: * @author Petr Hamernik
055: * @version 0.14, Jul 20, 1998
056: */
057: abstract class ArrayOfIntSupport extends
058: java.beans.PropertyEditorSupport implements XMLPropertyEditor,
059: ExPropertyEditor {
060: private static final String VALUE_FORMAT = org.openide.util.NbBundle
061: .getBundle(ArrayOfIntSupport.class).getString(
062: "EXC_BadFormatValue");
063:
064: /** Length of the array of the integers */
065: private int count;
066:
067: /** Class Name of the edited property. It is used in getJavaInitializationString
068: * method.
069: */
070: private String className;
071:
072: /** associated env, accessible by package private subclasses */
073: PropertyEnv env;
074:
075: /** constructs new property editor.
076: * @param className Name of the class which is this editor for. (e.g. "java.awt.Point")
077: * @param count Length of the array of int
078: */
079: public ArrayOfIntSupport(String className, int count) {
080: this .className = className;
081: this .count = count;
082: }
083:
084: public void attachEnv(PropertyEnv env) {
085: this .env = env;
086: }
087:
088: /** This method is intended for use when generating Java code to set
089: * the value of the property. It should return a fragment of Java code
090: * that can be used to initialize a variable with the current property
091: * value.
092: * <p>
093: * Example results are "2", "new Color(127,127,34)", "Color.orange", etc.
094: *
095: * @return A fragment of Java code representing an initializer for the
096: * current value.
097: */
098: public String getJavaInitializationString() {
099: int[] val = getValues();
100: StringBuffer buf = new StringBuffer("new "); // NOI18N
101:
102: buf.append(className);
103: buf.append("("); // NOI18N
104: addArray(buf, val);
105: buf.append(")"); // NOI18N
106: return buf.toString();
107: }
108:
109: /** Abstract method for translating the value from getValue() method to array of int. */
110: abstract int[] getValues();
111:
112: /** Abstract method for translating the array of int to value
113: * which is set to method setValue(XXX)
114: */
115: abstract void setValues(int[] val);
116:
117: //----------------------------------------------------------------------
118:
119: /**
120: * @return The property value as a human editable string.
121: * <p> Returns null if the value can't be expressed as an editable string.
122: * <p> If a non-null value is returned, then the PropertyEditor should
123: * be prepared to parse that string back in setAsText().
124: */
125: public String getAsText() {
126: if (getValue() == null)
127: return "null"; // NOI18N
128:
129: int[] val = getValues();
130:
131: if (val == null)
132: return null;
133: else {
134: StringBuffer buf = new StringBuffer("["); // NOI18N
135: addArray(buf, val);
136: buf.append("]"); // NOI18N
137: return buf.toString();
138: }
139: }
140:
141: /** Add array of integers to the StringBuffer. Numbers are separated by ", " string */
142: // NOI18N
143: private void addArray(StringBuffer buf, int[] arr) {
144: for (int i = 0; i < count; i++) {
145: if (arr == null)
146: buf.append("0"); // NOI18N
147: else
148: buf.append(arr[i]);
149:
150: if (i < count - 1)
151: buf.append(", "); // NOI18N
152: }
153: }
154:
155: /** Set the property value by parsing a given String. May raise
156: * java.lang.IllegalArgumentException if either the String is
157: * badly formatted or if this kind of property can't be expressed
158: * as text.
159: * @param text The string to be parsed.
160: */
161: public void setAsText(String text) throws IllegalArgumentException {
162: if ("null".equals(text) || "".equals(text)) { // NOI18N
163: setValue(null);
164: return;
165: }
166: int[] newVal = new int[count];
167: int nextNumber = 0;
168:
169: StringTokenizer tuk = new StringTokenizer(text, "[] ,;", false); // NOI18N
170: while (tuk.hasMoreTokens()) {
171: String token = tuk.nextToken();
172: if (nextNumber >= count)
173: badFormat(null);
174:
175: try {
176: newVal[nextNumber] = new Integer(token).intValue();
177: nextNumber++;
178: } catch (NumberFormatException e) {
179: badFormat(e);
180: }
181: }
182:
183: // if less numbers are entered, copy the last entered number into the rest
184: if (nextNumber != count) {
185: if (nextNumber > 0) {
186: int copyValue = newVal[nextNumber - 1];
187: for (int i = nextNumber; i < count; i++)
188: newVal[i] = copyValue;
189: }
190: }
191: setValues(newVal);
192: }
193:
194: /** Always throws the new exception */
195: private void badFormat(Exception e) throws IllegalArgumentException {
196: String msg = new MessageFormat(VALUE_FORMAT)
197: .format(new Object[] { className, getHintFormat() });
198: IllegalArgumentException iae = new IllegalArgumentException(msg);
199: UIExceptions.annotateUser(iae, e == null ? "" : e.getMessage(),
200: msg, e, new java.util.Date()); //NOI18N
201: throw iae;
202: }
203:
204: /** @return the format info for the user. Can be rewritten in subclasses. */
205: String getHintFormat() {
206: StringBuffer buf = new StringBuffer("["); // NOI18N
207: for (int i = 0; i < count; i++) {
208: buf.append("<n"); // NOI18N
209: buf.append(i);
210: buf.append(">"); // NOI18N
211:
212: if (i < count - 1)
213: buf.append(", "); // NOI18N
214: }
215: buf.append("]"); // NOI18N
216:
217: return buf.toString();
218: }
219:
220: //--------------------------------------------------------------------------
221: // XMLPropertyEditor implementation
222:
223: public static final String ATTR_VALUE = "value"; // NOI18N
224:
225: /** Provides name of XML tag to use for XML persistence of the property value */
226: protected abstract String getXMLValueTag();
227:
228: /** Called to load property value from specified XML subtree. If succesfully loaded,
229: * the value should be available via the getValue method.
230: * An IOException should be thrown when the value cannot be restored from the specified XML element
231: * @param element the XML DOM element representing a subtree of XML from which the value should be loaded
232: * @exception IOException thrown when the value cannot be restored from the specified XML element
233: */
234: public void readFromXML(org.w3c.dom.Node element)
235: throws java.io.IOException {
236: if (!getXMLValueTag().equals(element.getNodeName())) {
237: throw new java.io.IOException();
238: }
239: org.w3c.dom.NamedNodeMap attributes = element.getAttributes();
240: try {
241: String value = attributes.getNamedItem(ATTR_VALUE)
242: .getNodeValue();
243: setAsText(value);
244: } catch (Exception e) {
245: throw new java.io.IOException();
246: }
247: }
248:
249: /** Called to store current property value into XML subtree. The property value should be set using the
250: * setValue method prior to calling this method.
251: * @param doc The XML document to store the XML in - should be used for creating nodes only
252: * @return the XML DOM element representing a subtree of XML from which the value should be loaded
253: */
254: public org.w3c.dom.Node storeToXML(org.w3c.dom.Document doc) {
255: org.w3c.dom.Element el = doc.createElement(getXMLValueTag());
256: el.setAttribute(ATTR_VALUE, getAsText());
257: return el;
258: }
259:
260: }
|