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.modules.form.editors;
043:
044: import java.awt.Component;
045: import java.beans.PropertyEditorSupport;
046: import java.io.IOException;
047: import java.util.logging.Level;
048: import java.util.logging.Logger;
049: import javax.swing.*;
050: import org.netbeans.modules.form.*;
051: import org.netbeans.modules.form.codestructure.CodeVariable;
052: import org.netbeans.modules.form.editors2.SpinnerModelEditor;
053: import org.openide.explorer.propertysheet.editors.XMLPropertyEditor;
054: import org.openide.util.NbBundle;
055: import org.w3c.dom.Document;
056: import org.w3c.dom.NamedNodeMap;
057: import org.w3c.dom.Node;
058:
059: /**
060: * Property editor for <code>editor</code> property of <code>JSpinner</code>.
061: *
062: * @author Jan Stola
063: */
064: public class SpinnerEditorEditor extends PropertyEditorSupport
065: implements XMLPropertyEditor, NamedPropertyEditor,
066: FormAwareEditor {
067:
068: /** Determines whether the components of custom editor have been created. */
069: private boolean initialized;
070: /** Determines whether custom property editor should fire value changes. */
071: private boolean fireChanges;
072: /** Property being edited. */
073: private FormProperty property;
074:
075: /**
076: * Initializes components of custom editor.
077: */
078: private void initGUI() {
079: initialized = true;
080: initComponents();
081: DefaultComboBoxModel comboModel = new DefaultComboBoxModel();
082: comboModel
083: .addElement(typeToString(FormSpinnerEditor.TYPE_DEFAULT));
084: comboModel
085: .addElement(typeToString(FormSpinnerEditor.TYPE_DATE));
086: comboModel
087: .addElement(typeToString(FormSpinnerEditor.TYPE_LIST));
088: comboModel
089: .addElement(typeToString(FormSpinnerEditor.TYPE_NUMBER));
090: typeCombo.setModel(comboModel);
091: }
092:
093: /**
094: * Converts textual representation of spinner editor type to integer constant.
095: *
096: * @param string textual representation of spinner editor type.
097: * @return integer constant that correspond to the textual representation
098: * of the spinner editor type. Returns <code>-1</code> if the text cannot
099: * be parsed.
100: */
101: private int stringToType(String string) {
102: int type = -1;
103: if (NbBundle.getMessage(getClass(),
104: "LBL_SpinnerEditorEditor_Default").equals(string)) { // NOI18N
105: type = FormSpinnerEditor.TYPE_DEFAULT;
106: } else if (NbBundle.getMessage(getClass(),
107: "LBL_SpinnerEditorEditor_Date").equals(string)) { // NOI18N
108: type = FormSpinnerEditor.TYPE_DATE;
109: } else if (NbBundle.getMessage(getClass(),
110: "LBL_SpinnerEditorEditor_List").equals(string)) { // NOI18N
111: type = FormSpinnerEditor.TYPE_LIST;
112: } else if (NbBundle.getMessage(getClass(),
113: "LBL_SpinnerEditorEditor_Number").equals(string)) { // NOI18N
114: type = FormSpinnerEditor.TYPE_NUMBER;
115: }
116: return type;
117: }
118:
119: /**
120: * Converts spinner editor type into human readable text.
121: *
122: * @param type spinner editor type.
123: * @return human readable textual representation of spinner editor type.
124: */
125: private String typeToString(int type) {
126: String string = null;
127: switch (type) {
128: case FormSpinnerEditor.TYPE_DEFAULT:
129: string = NbBundle.getMessage(getClass(),
130: "LBL_SpinnerEditorEditor_Default"); // NOI18N
131: break;
132: case FormSpinnerEditor.TYPE_DATE:
133: string = NbBundle.getMessage(getClass(),
134: "LBL_SpinnerEditorEditor_Date"); // NOI18N
135: break;
136: case FormSpinnerEditor.TYPE_LIST:
137: string = NbBundle.getMessage(getClass(),
138: "LBL_SpinnerEditorEditor_List"); // NOI18N
139: break;
140: case FormSpinnerEditor.TYPE_NUMBER:
141: string = NbBundle.getMessage(getClass(),
142: "LBL_SpinnerEditorEditor_Number"); // NOI18N
143: break;
144: default:
145: assert false;
146: }
147: return string;
148: }
149:
150: @Override
151: public String getAsText() {
152: String text = null;
153: Object value = getValue();
154: if (value instanceof FormSpinnerEditor) {
155: FormSpinnerEditor editor = (FormSpinnerEditor) value;
156: text = typeToString(editor.getType());
157: String format = editor.getFormat();
158: if (format != null) {
159: text += " " + format; // NOI18N
160: }
161: } else {
162: text = typeToString(FormSpinnerEditor.TYPE_DEFAULT);
163: }
164: return text;
165: }
166:
167: @Override
168: public void setAsText(String text) {
169: if (text == null)
170: throw new IllegalArgumentException();
171: int index = text.indexOf(' ');
172: String typeText;
173: String format;
174: if (index == -1) {
175: typeText = text;
176: format = null;
177: } else {
178: typeText = text.substring(0, index);
179: format = text.substring(index + 1);
180: }
181: int type = stringToType(typeText);
182: if (type == -1)
183: throw new IllegalArgumentException();
184: if (type != FormSpinnerEditor.TYPE_DEFAULT) {
185: FormSpinnerEditor editor = new FormSpinnerEditor(property,
186: type, format);
187: setValue(editor);
188: }
189: }
190:
191: /**
192: * Determines whether this property editor supports custom editing.
193: *
194: * @return <code>true</code>.
195: */
196: @Override
197: public boolean supportsCustomEditor() {
198: return true;
199: }
200:
201: /**
202: * Returns custom editor.
203: *
204: * @return custom editor.
205: */
206: @Override
207: public Component getCustomEditor() {
208: fireChanges = false;
209: if (!initialized) {
210: initGUI();
211: }
212: Object value = getValue();
213: if (value instanceof FormSpinnerEditor) {
214: FormSpinnerEditor editor = (FormSpinnerEditor) value;
215: typeCombo.setSelectedIndex(editor.getType());
216: String format = editor.getFormat();
217: if (format != null) {
218: formatField.setText(format);
219: }
220: } else {
221: // default value
222: typeCombo.setSelectedIndex(0);
223: }
224: fireChanges = true;
225: return customizerPanel;
226: }
227:
228: /** This method is called from within the constructor to
229: * initialize the form.
230: * WARNING: Do NOT modify this code. The content of this method is
231: * always regenerated by the Form Editor.
232: */
233: // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
234: private void initComponents() {
235:
236: customizerPanel = new javax.swing.JPanel();
237: typeLabel = new javax.swing.JLabel();
238: typeCombo = new javax.swing.JComboBox();
239: formatLabel = new javax.swing.JLabel();
240: formatField = new javax.swing.JTextField();
241:
242: typeLabel.setText(org.openide.util.NbBundle.getMessage(
243: SpinnerEditorEditor.class,
244: "LBL_SpinnerEditorEditor_Type")); // NOI18N
245:
246: typeCombo
247: .addActionListener(new java.awt.event.ActionListener() {
248: public void actionPerformed(
249: java.awt.event.ActionEvent evt) {
250: typeComboActionPerformed(evt);
251: }
252: });
253:
254: formatLabel.setText(org.openide.util.NbBundle.getMessage(
255: SpinnerEditorEditor.class,
256: "LBL_SpinnerEditorEditor_Format")); // NOI18N
257:
258: formatField.setColumns(15);
259: formatField.addFocusListener(new java.awt.event.FocusAdapter() {
260: public void focusLost(java.awt.event.FocusEvent evt) {
261: formatFieldFocusLost(evt);
262: }
263: });
264:
265: org.jdesktop.layout.GroupLayout customizerPanelLayout = new org.jdesktop.layout.GroupLayout(
266: customizerPanel);
267: customizerPanel.setLayout(customizerPanelLayout);
268: customizerPanelLayout
269: .setHorizontalGroup(customizerPanelLayout
270: .createParallelGroup(
271: org.jdesktop.layout.GroupLayout.LEADING)
272: .add(
273: customizerPanelLayout
274: .createSequentialGroup()
275: .addContainerGap()
276: .add(
277: customizerPanelLayout
278: .createParallelGroup(
279: org.jdesktop.layout.GroupLayout.LEADING)
280: .add(typeLabel)
281: .add(
282: formatLabel))
283: .addPreferredGap(
284: org.jdesktop.layout.LayoutStyle.RELATED)
285: .add(
286: customizerPanelLayout
287: .createParallelGroup(
288: org.jdesktop.layout.GroupLayout.LEADING)
289: .add(
290: typeCombo,
291: 0,
292: 126,
293: Short.MAX_VALUE)
294: .add(
295: formatField))
296: .addContainerGap()));
297: customizerPanelLayout
298: .setVerticalGroup(customizerPanelLayout
299: .createParallelGroup(
300: org.jdesktop.layout.GroupLayout.LEADING)
301: .add(
302: customizerPanelLayout
303: .createSequentialGroup()
304: .addContainerGap()
305: .add(
306: customizerPanelLayout
307: .createParallelGroup(
308: org.jdesktop.layout.GroupLayout.BASELINE)
309: .add(typeLabel)
310: .add(
311: typeCombo,
312: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
313: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
314: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
315: .addPreferredGap(
316: org.jdesktop.layout.LayoutStyle.RELATED)
317: .add(
318: customizerPanelLayout
319: .createParallelGroup(
320: org.jdesktop.layout.GroupLayout.BASELINE)
321: .add(
322: formatLabel)
323: .add(
324: formatField,
325: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
326: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
327: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
328: .addContainerGap(
329: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
330: Short.MAX_VALUE)));
331: }// </editor-fold>//GEN-END:initComponents
332:
333: private void formatFieldFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_formatFieldFocusLost
334: updateValueFromUI();
335: }//GEN-LAST:event_formatFieldFocusLost
336:
337: private void typeComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_typeComboActionPerformed
338: int index = typeCombo.getSelectedIndex();
339: boolean editable = (index % 2 == 1);
340: if (editable != formatField.isEditable()) {
341: formatField.setText(""); // NOI18N
342: formatField.setEditable(editable);
343: }
344: updateValueFromUI();
345: }//GEN-LAST:event_typeComboActionPerformed
346:
347: /**
348: * Updates property editor according value represented by UI components
349: * of the custom property editor.
350: */
351: private void updateValueFromUI() {
352: if (!fireChanges)
353: return;
354: Object value = valueFromUI();
355: if (value == null) {
356: value = property.getDefaultValue();
357: }
358: updateModelProperty(value);
359: setValue(value);
360: }
361:
362: private void updateModelProperty(Object value) {
363: if ((value instanceof FormSpinnerEditor)
364: && (property instanceof RADProperty)) {
365: RADProperty editorProperty = (RADProperty) property;
366: RADProperty modelProperty = (RADProperty) editorProperty
367: .getRADComponent().getPropertyByName("model"); // NOI18N
368: if (modelProperty != null) {
369: try {
370: Object spinnerModel = modelProperty.getRealValue();
371: FormSpinnerEditor editor = (FormSpinnerEditor) value;
372: int type = editor.getType();
373: if ((type == FormSpinnerEditor.TYPE_DATE)
374: && !(spinnerModel instanceof SpinnerDateModel)) {
375: SpinnerDateModel newModel = new SpinnerDateModel();
376: modelProperty
377: .setValue(new SpinnerModelEditor.FormSpinnerModel(
378: newModel, newModel.getValue(),
379: true, false, false));
380: } else if ((type == FormSpinnerEditor.TYPE_NUMBER)
381: && !(spinnerModel instanceof SpinnerNumberModel)) {
382: SpinnerNumberModel newModel = new SpinnerNumberModel();
383: modelProperty
384: .setValue(new SpinnerModelEditor.FormSpinnerModel(
385: newModel, newModel.getValue()));
386: } else if ((type == FormSpinnerEditor.TYPE_LIST)
387: && !(spinnerModel instanceof SpinnerListModel)) {
388: SpinnerListModel newModel = new SpinnerListModel();
389: modelProperty
390: .setValue(new SpinnerModelEditor.FormSpinnerModel(
391: newModel, newModel.getValue()));
392: }
393: } catch (Exception ex) {
394: Logger.getLogger(getClass().getName()).log(
395: Level.INFO, ex.getMessage(), ex);
396: }
397: }
398: }
399: }
400:
401: /**
402: * Obtains value from the custom property editor.
403: *
404: * @return value represented by UI components of the custom property editor.
405: */
406: private FormSpinnerEditor valueFromUI() {
407: int index = typeCombo.getSelectedIndex();
408: FormSpinnerEditor value;
409: if (index == 0) {
410: value = null;
411: } else {
412: String format = formatField.getText();
413: if (index % 2 == 0) {
414: format = null;
415: }
416: value = new FormSpinnerEditor(property, index, format);
417: }
418: return value;
419: }
420:
421: // Variables declaration - do not modify//GEN-BEGIN:variables
422: private javax.swing.JPanel customizerPanel;
423: private javax.swing.JTextField formatField;
424: private javax.swing.JLabel formatLabel;
425: private javax.swing.JComboBox typeCombo;
426: private javax.swing.JLabel typeLabel;
427: // End of variables declaration//GEN-END:variables
428:
429: /** Name of the root tag of the spinner editor XML property editor. */
430: private static final String XML_SPINNER_EDITOR = "SpinnerEditor"; // NOI18N
431: /** Name of the type attribute. */
432: private static final String ATTR_TYPE = "type"; // NOI18N
433: /** Name of the format attribute. */
434: private static final String ATTR_FORMAT = "format"; // NOI18N
435:
436: public void readFromXML(Node element) throws IOException {
437: NamedNodeMap attributes = element.getAttributes();
438: String typeTxt = attributes.getNamedItem(ATTR_TYPE)
439: .getNodeValue();
440: int type = Integer.parseInt(typeTxt);
441: Node node = attributes.getNamedItem(ATTR_FORMAT);
442: String format = null;
443: if (node != null) {
444: format = node.getNodeValue();
445: }
446: setValue(new FormSpinnerEditor(property, type, format));
447: }
448:
449: public Node storeToXML(Document doc) {
450: org.w3c.dom.Element el = doc.createElement(XML_SPINNER_EDITOR);
451: Object value = getValue();
452: if (!(value instanceof FormSpinnerEditor)) {
453: el.setAttribute(ATTR_TYPE, ""
454: + FormSpinnerEditor.TYPE_DEFAULT); // NOI18N
455: } else {
456: FormSpinnerEditor editor = (FormSpinnerEditor) value;
457: el.setAttribute(ATTR_TYPE, "" + editor.getType()); // NOI18N
458: String format = editor.getFormat();
459: if (format != null) {
460: el.setAttribute(ATTR_FORMAT, editor.getFormat());
461: }
462: }
463: return el;
464: }
465:
466: /**
467: * Returns display name of the editor.
468: *
469: * @return display name of the editor.
470: */
471: public String getDisplayName() {
472: return NbBundle.getMessage(getClass(),
473: "CTL_SpinnerEditorEditor_DisplayName"); // NOI18N
474: }
475:
476: /**
477: * Sets context of this property editor.
478: *
479: * @param formModel form model.
480: * @param property
481: */
482: public void setContext(FormModel formModel, FormProperty property) {
483: this .property = property;
484: }
485:
486: /**
487: * Raise form version to 6.0 - this editor is available since NB 6.0.
488: */
489: public void updateFormVersionLevel() {
490: property.getPropertyContext().getFormModel().raiseVersionLevel(
491: FormModel.FormVersion.NB60, FormModel.FormVersion.NB60);
492: }
493:
494: /**
495: * Returns initialization string for the value represented by this property editor.
496: *
497: * @return initialization string.
498: */
499: @Override
500: public String getJavaInitializationString() {
501: Object value = getValue();
502: if (!(value instanceof FormSpinnerEditor)) {
503: // should not happen
504: return super .getJavaInitializationString();
505: }
506: FormSpinnerEditor editor = (FormSpinnerEditor) value;
507: CodeVariable var = editor.getProperty().getRADComponent()
508: .getCodeExpression().getVariable();
509: int type = editor.getType();
510: String code = null;
511: switch (type) {
512: case FormSpinnerEditor.TYPE_DATE:
513: String format = editor.getFormat().replace("\"", "\\\""); // NOI18N
514: code = "new javax.swing.JSpinner.DateEditor("
515: + var.getName() + ", \"" + format + "\")"; // NOI18N
516: break;
517: case FormSpinnerEditor.TYPE_LIST:
518: code = "new javax.swing.JSpinner.ListEditor("
519: + var.getName() + ")"; // NOI18N
520: break;
521: case FormSpinnerEditor.TYPE_NUMBER:
522: format = editor.getFormat().replace("\"", "\\\""); // NOI18N
523: code = "new javax.swing.JSpinner.NumberEditor("
524: + var.getName() + ", \"" + format + "\")"; // NOI18N
525: break;
526: default:
527: assert false;
528: }
529: return code;
530: }
531:
532: /**
533: * Wrapper for an editor of <code>JSpinner</code>.
534: */
535: static class FormSpinnerEditor extends FormDesignValueAdapter {
536: /** Constant for the type of the spinner editor - default editor. */
537: public static final int TYPE_DEFAULT = 0;
538: /** Constant for the type of the spinner editor - date editor. */
539: public static final int TYPE_DATE = 1;
540: /** Constant for the type of the spinner editor - list editor. */
541: public static final int TYPE_LIST = 2;
542: /** Constant for the type of the spinner editor - number editor. */
543: public static final int TYPE_NUMBER = 3;
544: /** Type of the spinner editor. */
545: private int type;
546: /** Format of the spinner editor. */
547: private String format;
548: /** Property this editor belongs to. */
549: private RADProperty property;
550:
551: /**
552: * Creates new <code>FormSpinnerEditor</code>.
553: *
554: * @param property property this editor belongs to.
555: * @param type type of the spinner editor.
556: * @param format format of the spinner editor.
557: */
558: FormSpinnerEditor(FormProperty property, int type, String format) {
559: this .property = (RADProperty) property;
560: this .type = type;
561: this .format = format;
562: }
563:
564: /**
565: * Returns type of the spinner editor.
566: *
567: * @return type of the spinner editor.
568: */
569: public int getType() {
570: return type;
571: }
572:
573: /**
574: * Returns format of the spinner editor.
575: *
576: * @return format of the spinner editor.
577: */
578: public String getFormat() {
579: return format;
580: }
581:
582: RADProperty getProperty() {
583: return property;
584: }
585:
586: /**
587: * Returns design value.
588: *
589: * @return design value.
590: */
591: public Object getDesignValue() {
592: Object value = null;
593: switch (type) {
594: case TYPE_DEFAULT:
595: value = property.getDefaultValue();
596: break;
597: case TYPE_DATE:
598: value = new JSpinner.DateEditor((JSpinner) property
599: .getRADComponent().getBeanInstance(), format);
600: break;
601: case TYPE_LIST:
602: value = new JSpinner.ListEditor((JSpinner) property
603: .getRADComponent().getBeanInstance());
604: break;
605: case TYPE_NUMBER:
606: value = new JSpinner.NumberEditor((JSpinner) property
607: .getRADComponent().getBeanInstance(), format);
608: break;
609: default:
610: assert false;
611: }
612: return value;
613: }
614:
615: /**
616: * Returns copy of the current value.
617: *
618: * @param targetFormProperty property where this value should be copied to.
619: * @return copy of the current value.
620: */
621: @Override
622: public Object copy(FormProperty targetFormProperty) {
623: return new FormSpinnerEditor(targetFormProperty, type,
624: format);
625: }
626:
627: }
628:
629: }
|