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.form.editors;
042:
043: import java.awt.Component;
044: import java.beans.PropertyChangeEvent;
045: import java.beans.PropertyChangeListener;
046: import java.beans.PropertyEditorSupport;
047: import java.io.IOException;
048: import java.text.DateFormat;
049: import java.text.DecimalFormat;
050: import java.text.NumberFormat;
051: import java.text.ParseException;
052: import java.text.SimpleDateFormat;
053: import java.util.logging.Level;
054: import java.util.logging.Logger;
055: import javax.swing.JFormattedTextField;
056: import javax.swing.text.DateFormatter;
057: import javax.swing.text.DefaultFormatterFactory;
058: import javax.swing.text.MaskFormatter;
059: import javax.swing.text.NumberFormatter;
060: import org.netbeans.modules.form.FormAwareEditor;
061: import org.netbeans.modules.form.FormDesignValueAdapter;
062: import org.netbeans.modules.form.FormModel;
063: import org.netbeans.modules.form.FormProperty;
064: import org.netbeans.modules.form.NamedPropertyEditor;
065: import org.openide.explorer.propertysheet.editors.XMLPropertyEditor;
066: import org.openide.util.NbBundle;
067: import org.w3c.dom.Document;
068: import org.w3c.dom.NamedNodeMap;
069: import org.w3c.dom.Node;
070:
071: /**
072: * Property editor for JFormattedTextField's format (formatter factory).
073: *
074: * @author Jan Stola
075: */
076: public class AbstractFormatterFactoryEditor extends
077: PropertyEditorSupport implements XMLPropertyEditor,
078: NamedPropertyEditor, PropertyChangeListener, FormAwareEditor {
079: /** Format selector used by the editor. */
080: private FormatSelector selector;
081: /** Property being edited. */
082: private FormProperty property;
083:
084: /**
085: * Returns custom property editor (form selector).
086: *
087: * @return custom property editor.
088: */
089: @Override
090: public Component getCustomEditor() {
091: if (selector == null) {
092: selector = new FormatSelector();
093: selector.addPropertyChangeListener(this );
094: }
095: Object value = getValue();
096: if (value instanceof FormFormatter) {
097: FormFormatter formatter = (FormFormatter) value;
098: selector.setFormat(formatter.getFormat());
099: } else {
100: selector.setFormat(new FormatSelector.FormatInfo(
101: FormatSelector.FormatInfo.NUMBER,
102: FormatSelector.FormatInfo.DEFAULT, null));
103: propertyChange(null);
104: }
105: return selector.getSelectorPanel();
106: }
107:
108: /**
109: * Returns Java code that corresponds to the selected formatter factory.
110: *
111: * @return Java code that corresponds to the selected formatter factory.
112: */
113: @Override
114: public String getJavaInitializationString() {
115: Object value = getValue();
116: if (!(value instanceof FormFormatter)) {
117: return super .getJavaInitializationString();
118: }
119: FormFormatter formatter = (FormFormatter) value;
120: FormatSelector.FormatInfo formatInfo = formatter.getFormat();
121: int type = formatInfo.getType();
122: int subtype = formatInfo.getSubtype();
123: String format = formatInfo.getFormat();
124: if (format != null) {
125: format = "\"" + format.replace("\"", "\\\"") + "\""; // NOI18N
126: }
127: String code = null;
128: if (type == FormatSelector.FormatInfo.MASK) {
129: code = "new javax.swing.text.MaskFormatter(" + format + ")"; // NOI18N
130: } else if (type == FormatSelector.FormatInfo.DATE) {
131: switch (subtype) {
132: case FormatSelector.FormatInfo.NONE:
133: code = "new java.text.SimpleDateFormat(" + format + ")"; // NOI18N
134: break;
135: case FormatSelector.FormatInfo.DEFAULT:
136: code = ""; // NOI18N
137: break;
138: case FormatSelector.FormatInfo.SHORT:
139: code = "java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT)"; // NOI18N
140: break;
141: case FormatSelector.FormatInfo.MEDIUM:
142: code = "java.text.DateFormat.getDateInstance(java.text.DateFormat.MEDIUM)"; // NOI18N
143: break;
144: case FormatSelector.FormatInfo.LONG:
145: code = "java.text.DateFormat.getDateInstance(java.text.DateFormat.LONG)"; // NOI18N
146: break;
147: case FormatSelector.FormatInfo.FULL:
148: code = "java.text.DateFormat.getDateInstance(java.text.DateFormat.FULL)"; // NOI18N
149: break;
150: default:
151: assert false;
152: break;
153: }
154: code = "new javax.swing.text.DateFormatter(" + code + ")"; // NOI18N
155: } else if (type == FormatSelector.FormatInfo.TIME) {
156: switch (subtype) {
157: case FormatSelector.FormatInfo.NONE:
158: code = "new java.text.SimpleDateFormat(" + format + ")"; // NOI18N
159: break;
160: case FormatSelector.FormatInfo.DEFAULT:
161: code = "java.text.DateFormat.getTimeInstance()"; // NOI18N
162: break;
163: case FormatSelector.FormatInfo.SHORT:
164: code = "java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT)"; // NOI18N
165: break;
166: case FormatSelector.FormatInfo.MEDIUM:
167: code = "java.text.DateFormat.getTimeInstance(java.text.DateFormat.MEDIUM)"; // NOI18N
168: break;
169: case FormatSelector.FormatInfo.LONG:
170: code = "java.text.DateFormat.getTimeInstance(java.text.DateFormat.LONG)"; // NOI18N
171: break;
172: case FormatSelector.FormatInfo.FULL:
173: code = "java.text.DateFormat.getTimeInstance(java.text.DateFormat.FULL)"; // NOI18N
174: break;
175: default:
176: assert false;
177: break;
178: }
179: code = "new javax.swing.text.DateFormatter(" + code + ")"; // NOI18N
180: } else if (type == FormatSelector.FormatInfo.NUMBER) {
181: switch (subtype) {
182: case FormatSelector.FormatInfo.NONE:
183: code = "new java.text.DecimalFormat(" + format + ")"; // NOI18N
184: break;
185: case FormatSelector.FormatInfo.DEFAULT:
186: code = ""; // NOI18N
187: break;
188: case FormatSelector.FormatInfo.INTEGER:
189: code = "java.text.NumberFormat.getIntegerInstance()"; // NOI18N
190: break;
191: default:
192: assert false;
193: break;
194: }
195: code = "new javax.swing.text.NumberFormatter(" + code + ")"; // NOI18N
196: } else if (type == FormatSelector.FormatInfo.PERCENT) {
197: if (subtype == FormatSelector.FormatInfo.DEFAULT) {
198: code = "java.text.NumberFormat.getPercentInstance()"; // NOI18N
199: } else {
200: code = "new java.text.DecimalFormat(" + format + ")"; // NOI18N
201: }
202: code = "new javax.swing.text.NumberFormatter(" + code + ")"; // NOI18N
203: } else if (type == FormatSelector.FormatInfo.CURRENCY) {
204: if (subtype == FormatSelector.FormatInfo.DEFAULT) {
205: code = "java.text.NumberFormat.getCurrencyInstance()"; // NOI18N
206: } else {
207: code = "new java.text.DecimalFormat(" + format + ")"; // NOI18N
208: }
209: code = "new javax.swing.text.NumberFormatter(" + code + ")"; // NOI18N
210: }
211: return "new javax.swing.text.DefaultFormatterFactory(" + code
212: + ")"; // NOI18N
213: }
214:
215: /** Pre-code for mask format. */
216: private static final String PRE_MASK_CODE = "try {"; // NOI18N
217: /** Post-code for mask format. */
218: private static final String POST_MASK_CODE = "} catch (java.text.ParseException ex) {\nex.printStackTrace();\n}"; // NOI18N
219:
220: /**
221: * Implementation of property change listener that listens on changes
222: * in selected format.
223: *
224: * @param evt property change event.
225: */
226: public void propertyChange(PropertyChangeEvent evt) {
227: setValue(new FormFormatter(selector.getFormat()));
228: }
229:
230: @Override
231: public void setValue(Object value) {
232: updatePrePostCode(value, getValue());
233: super .setValue(value);
234: }
235:
236: /**
237: * Updates pre/post code of the edited property.
238: *
239: * @param newValue new value of the property.
240: * @param oldValue old value of the property.
241: */
242: private void updatePrePostCode(Object newValue, Object oldValue) {
243: if ((newValue instanceof FormFormatter)
244: && (((FormFormatter) newValue).getFormat().getType() == FormatSelector.FormatInfo.MASK)) {
245: property.setPreCode(PRE_MASK_CODE);
246: property.setPostCode(POST_MASK_CODE);
247: } else {
248: // simple heuristic to avoid modification of real user code
249: if (((oldValue instanceof FormFormatter) && (((FormFormatter) oldValue)
250: .getFormat().getType() == FormatSelector.FormatInfo.MASK))
251: // Make sure restoreDefaultValue works on mask format before changing this
252: || ((property.getPostCode() != null) && (property
253: .getPreCode().trim().equals(PRE_MASK_CODE)))) {
254: property.setPreCode(null);
255: property.setPostCode(null);
256: }
257: }
258: }
259:
260: /**
261: * Determines whether custom property editor is supported.
262: *
263: * @return <code>true</code>.
264: */
265: @Override
266: public boolean supportsCustomEditor() {
267: return true;
268: }
269:
270: // Implementation of XMLPropertyEditor
271:
272: /** Tag representing the format. */
273: private static final String XML_FORMAT = "Format"; // NOI18N
274: /** Attribute describing type of format. */
275: private static final String ATTR_TYPE = "type"; // NOI18N
276: /** Attribute describing subtype of format. */
277: private static final String ATTR_SUBTYPE = "subtype"; // NOI18N
278: /** Attribute describing format's pattern. */
279: private static final String ATTR_FORMAT = "format"; // NOI18N
280:
281: public void readFromXML(Node element) throws IOException {
282: NamedNodeMap attributes = element.getAttributes();
283: String typeTxt = attributes.getNamedItem(ATTR_TYPE)
284: .getNodeValue();
285: String subtypeTxt = attributes.getNamedItem(ATTR_SUBTYPE)
286: .getNodeValue();
287: String format = null;
288: Node node = attributes.getNamedItem(ATTR_FORMAT);
289: if (node != null) {
290: format = node.getNodeValue();
291: }
292: int type = Integer.parseInt(typeTxt);
293: int subtype = Integer.parseInt(subtypeTxt);
294: setValue(new FormFormatter(new FormatSelector.FormatInfo(type,
295: subtype, format)));
296: }
297:
298: public Node storeToXML(Document doc) {
299: org.w3c.dom.Element el = doc.createElement(XML_FORMAT);
300: Object value = getValue();
301: FormFormatter formatter = (FormFormatter) value;
302: FormatSelector.FormatInfo format = formatter.getFormat();
303: el.setAttribute(ATTR_TYPE, "" + format.getType()); // NOI18N
304: el.setAttribute(ATTR_SUBTYPE, "" + format.getSubtype()); // NOI18N
305: if (format.isCustomizable()) {
306: el.setAttribute(ATTR_FORMAT, format.getFormat());
307: }
308: return el;
309: }
310:
311: /**
312: * Returns display name of the property editor.
313: *
314: * @return display name of the property editor.
315: */
316: public String getDisplayName() {
317: return NbBundle.getMessage(getClass(),
318: "CTL_AbstractFormatterFactoryEditor_DisplayName"); // NOI18N
319: }
320:
321: public void setContext(FormModel formModel, FormProperty property) {
322: this .property = property;
323: try {
324: updatePrePostCode(null, property.getValue());
325: } catch (Exception ex) {
326: Logger.getLogger(getClass().getName()).log(Level.INFO,
327: ex.getMessage(), ex);
328: }
329: }
330:
331: /**
332: * Raise form version to 6.0 - this editor is available since NB 6.0.
333: */
334: public void updateFormVersionLevel() {
335: property.getPropertyContext().getFormModel().raiseVersionLevel(
336: FormModel.FormVersion.NB60, FormModel.FormVersion.NB60);
337: }
338:
339: /**
340: * Form wrapper around formatter.
341: */
342: static class FormFormatter extends FormDesignValueAdapter {
343: /** Information about wrapped format. */
344: private FormatSelector.FormatInfo format;
345:
346: /**
347: * Creates new <code>FormFormatter</code>.
348: *
349: * @param format information about wrapped format.
350: */
351: FormFormatter(FormatSelector.FormatInfo format) {
352: this .format = format;
353: }
354:
355: /**
356: * Returns information about wrapped format.
357: *
358: * @return information about wrapped format.
359: */
360: public FormatSelector.FormatInfo getFormat() {
361: return format;
362: }
363:
364: /**
365: * Returns design value corresponding to this formatter.
366: *
367: * @return design value corresponding to this formatter.
368: */
369: public Object getDesignValue() {
370: JFormattedTextField.AbstractFormatter value = null;
371: int type = format.getType();
372: if (type == FormatSelector.FormatInfo.MASK) {
373: try {
374: value = new MaskFormatter(format.getFormat());
375: } catch (ParseException pex) {
376: Logger.getLogger(getClass().getName()).log(
377: Level.INFO, pex.getMessage(), pex);
378: value = new MaskFormatter();
379: }
380: } else if (type == FormatSelector.FormatInfo.DATE) {
381: DateFormat dateFormat = null;
382: switch (format.getSubtype()) {
383: case FormatSelector.FormatInfo.NONE:
384: dateFormat = new SimpleDateFormat(format
385: .getFormat());
386: break;
387: case FormatSelector.FormatInfo.DEFAULT:
388: dateFormat = DateFormat.getDateInstance();
389: break;
390: case FormatSelector.FormatInfo.SHORT:
391: dateFormat = DateFormat
392: .getDateInstance(DateFormat.SHORT);
393: break;
394: case FormatSelector.FormatInfo.MEDIUM:
395: dateFormat = DateFormat
396: .getDateInstance(DateFormat.MEDIUM);
397: break;
398: case FormatSelector.FormatInfo.LONG:
399: dateFormat = DateFormat
400: .getDateInstance(DateFormat.LONG);
401: break;
402: case FormatSelector.FormatInfo.FULL:
403: dateFormat = DateFormat
404: .getDateInstance(DateFormat.FULL);
405: break;
406: default:
407: assert false;
408: break;
409: }
410: value = new DateFormatter(dateFormat);
411: } else if (type == FormatSelector.FormatInfo.TIME) {
412: DateFormat timeFormat = null;
413: switch (format.getSubtype()) {
414: case FormatSelector.FormatInfo.NONE:
415: timeFormat = new SimpleDateFormat(format
416: .getFormat());
417: break;
418: case FormatSelector.FormatInfo.DEFAULT:
419: timeFormat = DateFormat.getTimeInstance();
420: break;
421: case FormatSelector.FormatInfo.SHORT:
422: timeFormat = DateFormat
423: .getTimeInstance(DateFormat.SHORT);
424: break;
425: case FormatSelector.FormatInfo.MEDIUM:
426: timeFormat = DateFormat
427: .getTimeInstance(DateFormat.MEDIUM);
428: break;
429: case FormatSelector.FormatInfo.LONG:
430: timeFormat = DateFormat
431: .getTimeInstance(DateFormat.LONG);
432: break;
433: case FormatSelector.FormatInfo.FULL:
434: timeFormat = DateFormat
435: .getTimeInstance(DateFormat.FULL);
436: break;
437: default:
438: assert false;
439: break;
440: }
441: value = new DateFormatter(timeFormat);
442: } else if (type == FormatSelector.FormatInfo.NUMBER) {
443: NumberFormat numberFormat = null;
444: switch (format.getSubtype()) {
445: case FormatSelector.FormatInfo.NONE:
446: numberFormat = new DecimalFormat(format.getFormat());
447: break;
448: case FormatSelector.FormatInfo.DEFAULT:
449: numberFormat = NumberFormat.getInstance();
450: break;
451: case FormatSelector.FormatInfo.INTEGER:
452: numberFormat = NumberFormat.getIntegerInstance();
453: break;
454: default:
455: assert false;
456: break;
457: }
458: value = new NumberFormatter(numberFormat);
459: } else if (type == FormatSelector.FormatInfo.PERCENT) {
460: NumberFormat percentFormat;
461: if (format.getSubtype() == FormatSelector.FormatInfo.DEFAULT) {
462: percentFormat = NumberFormat.getPercentInstance();
463: } else {
464: percentFormat = new DecimalFormat(format
465: .getFormat());
466: }
467: value = new NumberFormatter(percentFormat);
468: } else if (type == FormatSelector.FormatInfo.CURRENCY) {
469: NumberFormat currencyFormat;
470: if (format.getSubtype() == FormatSelector.FormatInfo.DEFAULT) {
471: currencyFormat = NumberFormat.getCurrencyInstance();
472: } else {
473: currencyFormat = new DecimalFormat(format
474: .getFormat());
475: }
476: value = new NumberFormatter(currencyFormat);
477: } else {
478: assert false;
479: }
480: return new DefaultFormatterFactory(value);
481: }
482:
483: }
484:
485: }
|