001: /*
002: * @(#)PointSpinner.java 4/8/2007
003: *
004: * Copyright 2002 - 2007 JIDE Software Inc. All rights reserved.
005: */
006:
007: package com.jidesoft.spinner;
008:
009: import javax.swing.*;
010: import javax.swing.text.DefaultFormatterFactory;
011: import java.beans.PropertyChangeEvent;
012: import java.beans.PropertyChangeListener;
013:
014: /**
015: * <code>PointSpinner</code> is a spinner that is specialized in displaying x and y value of a point.
016: * <p/>
017: *
018: * @author Nako Ruru
019: */
020: public class PointSpinner extends JSpinner {
021:
022: /**
023: * Constructs a complete spinner with pair of next/previous buttons
024: * and an editor for the <code>SpinnerModel</code>.
025: *
026: * @param model
027: */
028: public PointSpinner(SpinnerPointModel model) {
029: setModel(model);
030: setEditor(createEditor(model));
031: setOpaque(true);
032: updateUI();
033: }
034:
035: /**
036: * Constructs a spinner with an <code>Integer SpinnerNumberModel</code>
037: * with initial value 0 and no minimum or maximum limits.
038: */
039: public PointSpinner() {
040: this (new SpinnerPointModel());
041: }
042:
043: private JComponent createEditor(SpinnerPointModel model) {
044: return new PointEditor(this );
045: }
046:
047: /**
048: *
049: */
050: public static class PointEditor extends DefaultEditor {
051:
052: /**
053: * @param spinner
054: */
055: public PointEditor(JSpinner spinner) {
056: super (spinner);
057: if (!(spinner.getModel() instanceof SpinnerPointModel)) {
058: throw new IllegalArgumentException(
059: "model not a SpinnerPointModel");
060: }
061: final SpinnerPointModel model = (SpinnerPointModel) spinner
062: .getModel();
063:
064: JFormattedTextField.AbstractFormatter formatter = PointFormatter
065: .getInstance();
066: DefaultFormatterFactory factory = new DefaultFormatterFactory(
067: formatter);
068: final JFormattedTextField ftf = getTextField();
069: ftf.setEditable(true);
070: ftf.setFormatterFactory(factory);
071: ftf.setHorizontalAlignment(JTextField.RIGHT);
072:
073: /* TBD - initializing the column width of the text field
074: * is imprecise and doing it here is tricky because
075: * the developer may configure the formatter later.
076: */
077: String min = Integer.toString(Integer.MIN_VALUE);
078: ftf.setColumns(4 + 2 * min.length());
079:
080: ftf.addPropertyChangeListener("value",
081: new PropertyChangeListener() {
082: public void propertyChange(
083: PropertyChangeEvent evt) {
084: String text = ftf.getText();
085: int comma = text.indexOf(',');
086: String digit;
087: int number;
088: if (model.getField() == SpinnerPointModel.FIELD_X) {
089: digit = text.substring(
090: text.indexOf('(') + 1, comma)
091: .trim();
092: number = text.indexOf(digit);
093: } else {
094: digit = text.substring(comma + 1,
095: text.indexOf(')')).trim();
096: number = text.lastIndexOf(digit);
097: }
098: ftf.select(number, number + digit.length());
099: }
100: });
101: }
102: }
103:
104: private void updateField() {
105: JComponent editor = getEditor();
106: if (editor instanceof PointEditor
107: && getModel() instanceof SpinnerPointModel) {
108: JFormattedTextField ftf = ((PointEditor) editor)
109: .getTextField();
110: SpinnerPointModel model = (SpinnerPointModel) getModel();
111: int comma = ftf.getText().indexOf(',');
112: int caret = ftf.getCaretPosition();
113: model.setField(caret <= comma ? SpinnerPointModel.FIELD_X
114: : SpinnerPointModel.FIELD_Y);
115: }
116: }
117:
118: @Override
119: public Object getNextValue() {
120: updateField();
121: return super .getNextValue();
122: }
123:
124: @Override
125: public Object getPreviousValue() {
126: updateField();
127: return super.getPreviousValue();
128: }
129: }
|