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: package org.netbeans.modules.vmd.midp.propertyeditors;
042:
043: import java.awt.BorderLayout;
044: import java.awt.event.FocusEvent;
045: import java.awt.event.FocusListener;
046: import java.util.Collections;
047: import java.util.regex.Pattern;
048: import javax.swing.JComponent;
049: import javax.swing.JPanel;
050: import javax.swing.JRadioButton;
051: import javax.swing.JSpinner;
052: import javax.swing.JTextField;
053: import javax.swing.event.ChangeEvent;
054: import javax.swing.event.ChangeListener;
055: import javax.swing.event.DocumentEvent;
056: import javax.swing.event.DocumentListener;
057: import org.netbeans.modules.vmd.api.model.PropertyValue;
058: import org.netbeans.modules.vmd.midp.components.MidpTypes;
059: import org.netbeans.modules.vmd.midp.propertyeditors.api.usercode.PropertyEditorUserCode;
060: import org.netbeans.modules.vmd.midp.propertyeditors.api.usercode.PropertyEditorElement;
061: import org.openide.awt.Mnemonics;
062: import org.openide.util.NbBundle;
063:
064: /**
065: *
066: * @author Anton Chechel
067: */
068: public class PropertyEditorNumber extends PropertyEditorUserCode
069: implements PropertyEditorElement {
070:
071: /**
072: * The text to be shown as a warning if user inputs incorrect characters
073: */
074: public static final String NON_DIGITS_TEXT = NbBundle.getMessage(
075: PropertyEditorGaugeMaxValue.class, "MSG_NON_DIGIT_CHARS"); // NOI18N
076: private CustomEditor customEditor;
077: private JRadioButton radioButton;
078: private String label;
079:
080: private PropertyEditorNumber(boolean useSpinner, String label,
081: String userCodeLabel) {
082: super (userCodeLabel);
083: this .label = label;
084: initComponents(useSpinner);
085:
086: initElements(Collections
087: .<PropertyEditorElement> singleton(this ));
088: }
089:
090: /**
091: * Creates instance of property editor for integer type
092: *
093: * @param label localized label with mnemonics for radio button
094: * @return propertyEditor
095: */
096: public static final PropertyEditorNumber createIntegerInstance(
097: boolean useSpinner, String label) {
098: return new PropertyEditorNumber(useSpinner, label, NbBundle
099: .getMessage(PropertyEditorNumber.class,
100: "LBL_INTEGER_UCLABEL")); // NOI18N
101: }
102:
103: /**
104: * Creates instance of property editor for long type
105: *
106: * @param label localized label with mnemonics for radio button
107: * @return propertyEditor
108: */
109: public static final PropertyEditorNumber createLongInstance(
110: boolean useSpinner, String label) {
111: return new PropertyEditorNumber(useSpinner, label, NbBundle
112: .getMessage(PropertyEditorNumber.class,
113: "LBL_LONG_UCLABEL")) { // NOI18N
114:
115: @Override
116: protected void saveValue(String text) {
117: if (text.length() > 0) {
118: long longValue = 0;
119: try {
120: text = prepareText(text);
121: longValue = Long.parseLong(text);
122: } catch (NumberFormatException e) {
123: }
124: super
125: .setValue(MidpTypes
126: .createLongValue(longValue));
127: }
128: }
129: };
130: }
131:
132: /**
133: * Creates instance of property editor for byte type
134: *
135: * @param label localized label with mnemonics for radio button
136: * @return propertyEditor
137: */
138: public static final PropertyEditorNumber createByteInstance(
139: boolean useSpinner, String label) {
140: return new PropertyEditorNumber(useSpinner, label, NbBundle
141: .getMessage(PropertyEditorNumber.class,
142: "LBL_BYTE_UCLABEL")) { // NOI18N
143:
144: @Override
145: protected void saveValue(String text) {
146: if (text.length() > 0) {
147: byte byteValue = 0;
148: try {
149: text = prepareText(text);
150: byteValue = Byte.parseByte(text);
151: } catch (NumberFormatException e) {
152: }
153: super
154: .setValue(MidpTypes
155: .createByteValue(byteValue));
156: }
157: }
158: };
159: }
160:
161: /**
162: * Creates instance of property editor for short type
163: *
164: * @param label localized label with mnemonics for radio button
165: * @return propertyEditor
166: */
167: public static final PropertyEditorNumber createShortInstance(
168: boolean useSpinner, String label) {
169: return new PropertyEditorNumber(useSpinner, label, NbBundle
170: .getMessage(PropertyEditorNumber.class,
171: "LBL_SHORT_UCLABEL")) { // NOI18N
172:
173: @Override
174: protected void saveValue(String text) {
175: if (text.length() > 0) {
176: short shortValue = 0;
177: try {
178: text = prepareText(text);
179: shortValue = Short.parseShort(text);
180: } catch (NumberFormatException e) {
181: }
182: super .setValue(MidpTypes
183: .createShortValue(shortValue));
184: }
185: }
186: };
187: }
188:
189: /**
190: * Creates instance of property editor for float type
191: *
192: * @param label localized label with mnemonics for radio button
193: * @return propertyEditor
194: */
195: public static final PropertyEditorNumber createFloatInstance(
196: String label) {
197: return new PropertyEditorNumber(false, label, NbBundle
198: .getMessage(PropertyEditorNumber.class,
199: "LBL_FLOAT_UCLABEL")) { // NOI18N
200:
201: @Override
202: protected boolean isTextCorrect(String text) {
203: return Pattern.matches("[\\d\\-\\.]+", text); // NOI18N
204: }
205:
206: @Override
207: protected String prepareText(String text) {
208: return text.replaceAll("[^0-9\\-\\.]+", ""); // NOI18N
209: }
210:
211: @Override
212: protected void saveValue(String text) {
213: if (text.length() > 0) {
214: float floatValue = 0;
215: try {
216: text = prepareText(text);
217: floatValue = Float.parseFloat(text);
218: } catch (NumberFormatException e) {
219: }
220: super .setValue(MidpTypes
221: .createFloatValue(floatValue));
222: }
223: }
224: };
225: }
226:
227: /**
228: * Creates instance of property editor for double type
229: *
230: * @param label localized label with mnemonics for radio button
231: * @return propertyEditor
232: */
233: public static final PropertyEditorNumber createDoubleInstance(
234: String label) {
235: return new PropertyEditorNumber(false, label, NbBundle
236: .getMessage(PropertyEditorNumber.class,
237: "LBL_DOUBLE_UCLABEL")) { // NOI18N
238:
239: @Override
240: protected boolean isTextCorrect(String text) {
241: return Pattern.matches("[\\d\\-\\.]+", text); // NOI18N
242: }
243:
244: @Override
245: protected String prepareText(String text) {
246: return text.replaceAll("[^0-9\\-\\.]+", ""); // NOI18N
247: }
248:
249: @Override
250: protected void saveValue(String text) {
251: if (text.length() > 0) {
252: double doubleValue = 0;
253: try {
254: text = prepareText(text);
255: doubleValue = Double.parseDouble(text);
256: } catch (NumberFormatException e) {
257: }
258: super .setValue(MidpTypes
259: .createDoubleValue(doubleValue));
260: }
261: }
262: };
263: }
264:
265: /**
266: * Creates instance of property editor for char type
267: *
268: * @param label localized label with mnemonics for radio button
269: * @return propertyEditor
270: */
271: public static final PropertyEditorNumber createCharInstance(
272: boolean useSpinner, String label) {
273: return new PropertyEditorNumber(useSpinner, label, NbBundle
274: .getMessage(PropertyEditorNumber.class,
275: "LBL_CHAR_UCLABEL")) { // NOI18N
276:
277: @Override
278: protected boolean isTextCorrect(String text) {
279: return Pattern.matches("[\\d\\-]+", text); // NOI18N
280: }
281:
282: @Override
283: protected String prepareText(String text) {
284: return text.replaceAll("[^0-9\\-]+", ""); // NOI18N
285: }
286:
287: @Override
288: protected void saveValue(String text) {
289: if (text.length() > 0) {
290: char charValue = 0;
291: try {
292: text = prepareText(text);
293: charValue = text.charAt(0);
294: } catch (NumberFormatException e) {
295: }
296: super
297: .setValue(MidpTypes
298: .createCharValue(charValue));
299: }
300: }
301: };
302: }
303:
304: private void initComponents(boolean useSpinner) {
305: radioButton = new JRadioButton();
306: Mnemonics.setLocalizedText(radioButton, label);
307: customEditor = new CustomEditor(useSpinner);
308: }
309:
310: /**
311: * Checks whether text is in correct format for given property editor.
312: * For example for integer property editor text must match [\d\-]+ regex
313: *
314: * @param text to be checked
315: * @return result
316: */
317: protected boolean isTextCorrect(String text) {
318: return Pattern.matches("[\\d\\-]+", text) || // NOI18N
319: // hexadecimal support
320: isHexFormat(text);
321: }
322:
323: /**
324: * Removes all incorrect characters for for given property editor.
325: * For example for integer property editor removes all chars except [\d\-]+ regex
326: *
327: * @param text to be checked
328: * @return result text
329: */
330: protected String prepareText(String text) {
331: if (text == null) {
332: return text;
333: }
334:
335: // hex
336: if (isHexFormat(text)) {
337: text = text.replaceAll("[^0-9\\-0xabcdefABCDEF]+", ""); // NOI18N
338: return text.replace("0x", ""); // NOI18N
339: }
340: return text.replaceAll("[^0-9\\-]+", ""); // NOI18N
341: }
342:
343: /**
344: * Saves text as a proper property value
345: *
346: * @param text to be parsed and saved
347: */
348: protected void saveValue(String text) {
349: if (text.length() > 0) {
350: int intValue = 0;
351: try {
352: if (isHexFormat(text)) {
353: text = prepareText(text);
354: intValue = Integer.parseInt(text, 16);
355: } else {
356: text = prepareText(text);
357: intValue = Integer.parseInt(text);
358: }
359: } catch (NumberFormatException e) {
360: }
361: super .setValue(MidpTypes.createIntegerValue(intValue));
362: }
363: }
364:
365: private boolean isHexFormat(String text) {
366: return text != null && text.matches("-?0x[\\d\\abcdefABCDEF]+"); //NOI18N
367: }
368:
369: /**
370: * Returns component to represent custom editor in propertyEditorUserCode
371: *
372: * @return component
373: */
374: public JComponent getCustomEditorComponent() {
375: return customEditor;
376: }
377:
378: /**
379: * Returns radio button for propertyEditorUserCode
380: *
381: * @return radioButton
382: */
383: public JRadioButton getRadioButton() {
384: return radioButton;
385: }
386:
387: /**
388: * Determines whether radioButton should be selected by default in the propertyEditorUserCode
389: *
390: * @return isSelected
391: */
392: public boolean isInitiallySelected() {
393: return true;
394: }
395:
396: /**
397: * Determines whether custom component resizable vertically in the propertyEditorUserCode
398: *
399: * @return isResizable
400: */
401: public boolean isVerticallyResizable() {
402: return false;
403: }
404:
405: @Override
406: public String getAsText() {
407: String super Text = super .getAsText();
408: if (super Text != null) {
409: return super Text;
410: }
411:
412: PropertyValue value = (PropertyValue) super .getValue();
413: return String.valueOf(value.getPrimitiveValue());
414: }
415:
416: /**
417: * Sets propertyValue from text
418: *
419: * @param text
420: * @see java.beans.PropertyEditor#setAsText
421: */
422: public void setTextForPropertyValue(String text) {
423: saveValue(text);
424: }
425:
426: /**
427: * Returns text for additional operations with propertyValue, not used here
428: *
429: * @return null
430: */
431: public String getTextForPropertyValue() {
432: return null;
433: }
434:
435: /**
436: * Sets initial propertyValue before displaying customPropertyEditor
437: *
438: * @param value
439: */
440: public void updateState(PropertyValue value) {
441: if (isCurrentValueANull() || value == null) {
442: customEditor.setText(null);
443: } else {
444: customEditor.setText(String.valueOf(value
445: .getPrimitiveValue()));
446: }
447: radioButton.setSelected(!isCurrentValueAUserCodeType());
448: }
449:
450: @Override
451: public void customEditorOKButtonPressed() {
452: super .customEditorOKButtonPressed();
453: if (radioButton.isSelected()) {
454: saveValue(customEditor.getText());
455: }
456: }
457:
458: private class CustomEditor extends JPanel implements
459: DocumentListener, ChangeListener, FocusListener {
460:
461: private JTextField textField;
462: private JSpinner spinner;
463: private boolean useSpinner;
464:
465: public CustomEditor(boolean useSpinner) {
466: this .useSpinner = useSpinner;
467: radioButton.addFocusListener(this );
468: initComponents();
469: }
470:
471: private void initComponents() {
472: setLayout(new BorderLayout());
473: if (useSpinner) {
474: spinner = new JSpinner();
475: spinner.getModel().addChangeListener(this );
476: spinner.addFocusListener(this );
477: add(spinner, BorderLayout.CENTER);
478: } else {
479: textField = new JTextField();
480: textField.getDocument().addDocumentListener(this );
481: textField.addFocusListener(this );
482: add(textField, BorderLayout.CENTER);
483: }
484: }
485:
486: public void setText(String text) {
487: if (useSpinner) {
488: Integer intValue = 0;
489: try {
490: if (isHexFormat(text)) {
491: text = prepareText(text);
492: intValue = Integer.parseInt(text, 16);
493: } else {
494: text = prepareText(text);
495: intValue = Integer.parseInt(text);
496: }
497: } catch (NumberFormatException e) {
498: }
499:
500: spinner.setValue(intValue);
501: } else {
502: textField.setText(text);
503: }
504: }
505:
506: public String getText() {
507: return useSpinner ? spinner.getValue().toString()
508: : textField.getText();
509: }
510:
511: private void checkNumberStatus() {
512: if (!isTextCorrect(getText())) {
513: displayWarning(NON_DIGITS_TEXT);
514: } else {
515: clearErrorStatus();
516: }
517: }
518:
519: public void focusGained(FocusEvent e) {
520: if (e.getSource() == radioButton
521: || e.getSource() == textField
522: || e.getSource() == spinner) {
523: checkNumberStatus();
524: }
525: }
526:
527: public void focusLost(FocusEvent e) {
528: clearErrorStatus();
529: }
530:
531: public void stateChanged(ChangeEvent e) {
532: if (spinner.hasFocus()) {
533: radioButton.setSelected(true);
534: checkNumberStatus();
535: }
536: }
537:
538: public void insertUpdate(DocumentEvent e) {
539: if (textField.hasFocus()) {
540: radioButton.setSelected(true);
541: checkNumberStatus();
542: }
543: }
544:
545: public void removeUpdate(DocumentEvent e) {
546: if (textField.hasFocus()) {
547: radioButton.setSelected(true);
548: checkNumberStatus();
549: }
550: }
551:
552: public void changedUpdate(DocumentEvent e) {
553: }
554: }
555: }
|