Enhanced Spinner List Formatter : Spinner « Swing JFC « Java






Enhanced Spinner List Formatter

   



import java.text.ParseException;
import java.util.Arrays;
import java.util.List;

import javax.swing.JFormattedTextField;
import javax.swing.SpinnerListModel;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
/**
 * Copyright 2007 Brandon Goodin
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * ListFormatter provides completion while text is being input
 * into the JFormattedTextField.Completion is only done if the
 * user is inserting text at the end of the document.Completion
 * is done by way of the SpinnerListModel method findNextMatch.
 * This is largely a copy of the SpinnerListFormatter found in
 * JDK 1.5 sources. A new version was written because the JDK
 * version was not extensible and did not allow for the ability
 * to ehance the stringToValue.
 *
 * The stringToValue was enhanced to iterate through the model
 * list and compare the String values of the list objects and
 * the string value passed to the formatter. The first equal
 * will return. So, if multiple objects have the same toString
 * value, only the first will be returned.
 */
public class EnhancedSpinnerListFormatter extends
    JFormattedTextField.AbstractFormatter {
  private DocumentFilter filter;
  private EnhancedSpinnerListModel model;


  public EnhancedSpinnerListFormatter(EnhancedSpinnerListModel model) {
    this.model = model;
  }

  public String valueToString(Object value) throws ParseException {
    if (value == null) {
      return "";
    }
    return value.toString();
  }

  public Object stringToValue(String string) throws ParseException {

    for (Object item : model.getList()) {
      if (item.toString().equals(string)) return item;
    }
    return null;
  }

  protected DocumentFilter getDocumentFilter() {
    if (filter == null) {
      filter = new Filter();
    }
    return filter;
  }


  private class Filter extends DocumentFilter {
    public void replace(FilterBypass fb, int offset, int length,
              String string, AttributeSet attrs) throws
        BadLocationException {
      if (string != null && (offset + length) ==
          fb.getDocument().getLength()) {
        Object next = model.findNextMatch(
            fb.getDocument().getText(0, offset) +
                string);
        String value = (next != null) ? next.toString() : null;

        if (value != null) {
          fb.remove(0, offset + length);
          fb.insertString(0, value, null);
          getFormattedTextField().select(offset +
              string.length(),
              value.length());
          return;
        }
      }
      super.replace(fb, offset, length, string, attrs);
    }

    public void insertString(FilterBypass fb, int offset,
                 String string, AttributeSet attr)
        throws BadLocationException {
      replace(fb, offset, 0, string, attr);
    }
  }
}




/**
 * Copyright 2007 Brandon Goodin
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * This is a pretty much a direct copy of the SpinnerListModel from JDK 1.5 sources.
 * It was copied out in order to expose methods that needed to be publicly available
 * in order to allow for completion to work properly with a list of complex objects
 * that present their human readable value from a toString(). The findNextMatch
 * method was exposed as public.
 */
class EnhancedSpinnerListModel extends SpinnerListModel {

  private List list;
    private int index;


    /**
     * Constructs a <code>SpinnerModel</code> whose sequence of
     * values is defined by the specified <code>List</code>.
     * The initial value (<i>current element</i>)
     * of the model will be <code>values.get(0)</code>.
     * If <code>values</code> is <code>null</code> or has zero
     * size, an <code>IllegalArugmentException</code> is thrown.
     *
     * @param values the sequence this model represents
     * @throws IllegalArugmentException if <code>values</code> is
     *                                  <code>null</code> or zero size
     */
    @SuppressWarnings({"JavadocReference"})
    public EnhancedSpinnerListModel(List<?> values) {
      if (values == null || values.size() == 0) {
        throw new IllegalArgumentException("SpinnerListModel(List) expects non-null non-empty List");
      }
      this.list = values;
      this.index = 0;
    }


    /**
     * Constructs a <code>SpinnerModel</code> whose sequence of values
     * is defined by the specified array.  The initial value of the model
     * will be <code>values[0]</code>.  If <code>values</code> is
     * <code>null</code> or has zero length, an
     * <code>IllegalArugmentException</code> is thrown.
     *
     * @param values the sequence this model represents
     * @throws IllegalArugmentException if <code>values</code> is
     *                                  <code>null</code> or zero length
     */
    @SuppressWarnings({"JavadocReference"})
    public EnhancedSpinnerListModel(Object[] values) {
      if (values == null || values.length == 0) {
        throw new IllegalArgumentException("SpinnerListModel(Object[]) expects non-null non-empty Object[]");
      }
      this.list = Arrays.asList(values);
      this.index = 0;
    }


    /**
     * Constructs an effectively empty <code>SpinnerListModel</code>.
     * The model's list will contain a single
     * <code>"empty"</code> string element.
     */
    public EnhancedSpinnerListModel() {
      this(new Object[]{"empty"});
    }


    /**
     * Returns the <code>List</code> that defines the sequence for this model.
     *
     * @return the value of the <code>list</code> property
     * @see #setList
     */
    public List<?> getList() {
      return list;
    }


    /**
     * Changes the list that defines this sequence and resets the index
     * of the models <code>value</code> to zero.  Note that <code>list</code>
     * is not copied, the model just stores a reference to it.
     * <p/>
     * This method fires a <code>ChangeEvent</code> if <code>list</code> is
     * not equal to the current list.
     *
     * @param list the sequence that this model represents
     * @throws IllegalArgumentException if <code>list</code> is
     *                                  <code>null</code> or zero length
     * @see #getList
     */
    public void setList(List<?> list) {
      if ((list == null) || (list.size() == 0)) {
        throw new IllegalArgumentException("invalid list");
      }
      if (!list.equals(this.list)) {
        this.list = list;
        index = 0;
        fireStateChanged();
      }
    }


    /**
     * Returns the current element of the sequence.
     *
     * @return the <code>value</code> property
     * @see javax.swing.SpinnerModel#getValue
     * @see #setValue
     */
    public Object getValue() {
      return list.get(index);
    }


    /**
     * Changes the current element of the sequence and notifies
     * <code>ChangeListeners</code>.  If the specified
     * value is not equal to an element of the underlying sequence
     * then an <code>IllegalArgumentException</code> is thrown.
     * In the following example the <code>setValue</code> call
     * would cause an exception to be thrown:
     * <pre>
     * String[] values = {"one", "two", "free", "four"};
     * SpinnerModel model = new SpinnerListModel(values);
     * model.setValue("TWO");
     * </pre>
     *
     * @param elt the sequence element that will be model's current value
     * @throws IllegalArgumentException if the specified value isn't allowed
     * @see javax.swing.SpinnerModel#setValue
     * @see #getValue
     */
    public void setValue(Object elt) {
      int index = list.indexOf(elt);
      if (index == -1) {
        throw new IllegalArgumentException("invalid sequence element");
      } else if (index != this.index) {
        this.index = index;
        fireStateChanged();
      }
    }


    /**
     * Returns the next legal value of the underlying sequence or
     * <code>null</code> if value is already the last element.
     *
     * @return the next legal value of the underlying sequence or
     *         <code>null</code> if value is already the last element
     * @see javax.swing.SpinnerModel#getNextValue
     * @see #getPreviousValue
     */
    public Object getNextValue() {
      return (index >= (list.size() - 1)) ? null : list.get(index + 1);
    }


    /**
     * Returns the previous element of the underlying sequence or
     * <code>null</code> if value is already the first element.
     *
     * @return the previous element of the underlying sequence or
     *         <code>null</code> if value is already the first element
     * @see javax.swing.SpinnerModel#getPreviousValue
     * @see #getNextValue
     */
    public Object getPreviousValue() {
      return (index <= 0) ? null : list.get(index - 1);
    }


    /**
     * Returns the next object that starts with <code>substring</code>.
     *
     * @param substring the string to be matched
     * @return the match
     */
    public Object findNextMatch(String substring) {
      int max = list.size();

      if (max == 0) {
        return null;
      }
      int counter = index;

      do {
        Object value = list.get(counter);
        String string = value.toString();

        if (string != null && string.startsWith(substring)) {
          return value;
        }
        counter = (counter + 1) % max;
      } while (counter != index);
      return null;
    }

}

   
    
    
  








Related examples in the same category

1.A program to test spinners.A program to test spinners.
2.An implementation of JSpinner with customized content--iconsAn implementation of JSpinner with customized content--icons
3.A quick test of various spinnersA quick test of various spinners
4.An example of JSpinner with a custom editorAn example of JSpinner with a custom editor
5.Create a spinnerCreate a spinner
6.Demonstrating the JSpinner ComponentDemonstrating the JSpinner Component
7.Demonstrate the Swing Spinner control
8.Spinner 2Spinner 2
9.Listening for Changes to the Value in a JSpinner Component
10.Creating a SpinnerListModel That Loops Through Its Values
11.Customizing the Editor in a JSpinner Component: Create a color spinner
12.Setting the Margin Space on a JSpinner Component
13.Limiting the Values in a Number JSpinner Component
14.Disabling Keyboard Editing in a JSpinner Component
15.Creating an Hour JSpinner Component
16.Creating a JSpinner Component: A number spinner:
17.A list spinner
18.A date spinner
19.A spinner of dates
20.Use an Icon Editor for use with the JSpinner component
21.Use images in tooltips
22.Number spinner
23.Date spinner
24.List based spinner
25.Java Spinner ComponentJava Spinner Component
26.Enhanced Spinner List Model