001: // ============================================================================
002: // $Id: GenericCellEditor.java,v 1.13 2005/12/17 04:45:03 davidahall Exp $
003: // Copyright (c) 2003-2005 David A. Hall
004: // ============================================================================
005: // The contents of this file are subject to the Common Development and
006: // Distribution License (CDDL), Version 1.0 (the License); you may not use this
007: // file except in compliance with the License. You should have received a copy
008: // of the the License along with this file: if not, a copy of the License is
009: // available from Sun Microsystems, Inc.
010: //
011: // http://www.sun.com/cddl/cddl.html
012: //
013: // From time to time, the license steward (initially Sun Microsystems, Inc.) may
014: // publish revised and/or new versions of the License. You may not use,
015: // distribute, or otherwise make this file available under subsequent versions
016: // of the License.
017: //
018: // Alternatively, the contents of this file may be used under the terms of the
019: // GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which
020: // case the provisions of the LGPL are applicable instead of those above. If you
021: // wish to allow use of your version of this file only under the terms of the
022: // LGPL, and not to allow others to use your version of this file under the
023: // terms of the CDDL, indicate your decision by deleting the provisions above
024: // and replace them with the notice and other provisions required by the LGPL.
025: // If you do not delete the provisions above, a recipient may use your version
026: // of this file under the terms of either the CDDL or the LGPL.
027: //
028: // This library is distributed in the hope that it will be useful,
029: // but WITHOUT ANY WARRANTY; without even the implied warranty of
030: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
031: // ============================================================================
032:
033: package net.sf.jga.swing;
034:
035: import java.awt.Color;
036: import java.text.Format;
037: import java.text.NumberFormat;
038: import javax.swing.DefaultCellEditor;
039: import javax.swing.JComponent;
040: import javax.swing.JLabel;
041: import javax.swing.JTextField;
042: import javax.swing.border.LineBorder;
043: import net.sf.jga.fn.UnaryFunctor;
044: import net.sf.jga.fn.arithmetic.Arithmetic;
045: import net.sf.jga.fn.arithmetic.ArithmeticFactory;
046: import net.sf.jga.fn.property.ConstructUnary;
047: import net.sf.jga.fn.string.DefaultFormat;
048: import net.sf.jga.fn.string.FormatValue;
049: import net.sf.jga.fn.string.ParseFormat;
050: import net.sf.jga.fn.EvaluationException;
051:
052: /**
053: * CellEditor that uses a pair of functors to parse/format a value. Empty
054: * strings, or strings containing only whitespace will correspond to null
055: * values of type T.
056: * <p>
057: * Copyright © 2003-2005 David A. Hall
058: *
059: * @author <a href="mailto:davidahall@users.sf.net">David A. Hall</a>
060: */
061:
062: public class GenericCellEditor<T> extends DefaultCellEditor {
063:
064: static final long serialVersionUID = -6265710748312156901L;
065:
066: // correctly typed reference to the editor component, saving excess casts
067: protected JTextField _component;
068:
069: // default value returned when the string is empty.
070: private T _defaultValue;
071:
072: /**
073: * Builds a GenericCellEdior using default format for the given class. The
074: * resulting editor can support any class that defines toString() and also
075: * has a one argument constructor that takes a String.
076: */
077: public GenericCellEditor(Class<T> type) {
078: this (new DefaultFormat<T>(), new ConstructUnary<String, T>(
079: String.class, type));
080: }
081:
082: /**
083: * Builds the GenericCellEditor using the given functor pair.
084: */
085: public GenericCellEditor(UnaryFunctor<T, String> formatter,
086: UnaryFunctor<String, T> parser) {
087: this (formatter, parser, null);
088: }
089:
090: /**
091: * Builds the GenericCellEditor using the given functor pair and default
092: * value for empty strings.
093: */
094: public GenericCellEditor(UnaryFunctor<T, String> formatter,
095: UnaryFunctor<String, T> parser, T defaultValue) {
096: super (new JTextField());
097: if (formatter == null) {
098: String msg = "Formatter (functor) is required";
099: throw new IllegalArgumentException(msg);
100: }
101:
102: if (parser == null) {
103: String msg = "Parser (functor) is required";
104: throw new IllegalArgumentException(msg);
105: }
106:
107: _component = (JTextField) editorComponent;
108: _defaultValue = defaultValue;
109:
110: // overrides the protected delegate
111: delegate = new FormattedDelegate(formatter, parser);
112: }
113:
114: /**
115: * Retrieves the value from the editor component, giving a visual clue when
116: * the value is invalid
117: */
118:
119: public boolean stopCellEditing() {
120: try {
121: // @SuppressException
122: // The FormattedDelegate class provides the implementation of
123: // getCellEditorValue, and it is known to always return a T
124: T value = (T) getCellEditorValue();
125: } catch (Exception e) {
126: _component.setBorder(new LineBorder(Color.red));
127: return false;
128: }
129:
130: return super .stopCellEditing();
131: }
132:
133: /**
134: * Returns the horizontal alignment: one of the values defined by JTextField.
135: */
136: public int getHorizontalAlignment() {
137: return _component.getHorizontalAlignment();
138: }
139:
140: /**
141: * Sets the horizontal alignment to one of the values defined by JTextField.
142: */
143: public void setHorizontalAlignment(int alignment) {
144: _component.setHorizontalAlignment(alignment);
145: }
146:
147: public String toString() {
148: return "GenericTableCellEditor[" + delegate + "]";
149: }
150:
151: //
152: // Overrides the base class nested EditorDelegate class, using the given
153: // functor pair to fill in and interpret the value of the component.
154: //
155:
156: protected class FormattedDelegate extends EditorDelegate {
157:
158: static final long serialVersionUID = -3670848351305705031L;
159:
160: private UnaryFunctor<T, String> _formatter;
161: private UnaryFunctor<String, T> _parser;
162:
163: public FormattedDelegate(UnaryFunctor<T, String> formatter,
164: UnaryFunctor<String, T> parser) {
165: _formatter = formatter;
166: _parser = parser;
167: }
168:
169: /**
170: * Sets the text in the editor component by formatting the given value.
171: * Will use the default value if one is available when given a null,
172: * otherwise will use an empty string.
173: */
174: public void setValue(Object value) {
175: if (value != null) {
176: // @SuppressWarnings
177: // ClassCastException is explicitely caught and sort-of dealt with
178: try {
179: _component.setText(_formatter.fn((T) value));
180: return;
181: } catch (ClassCastException x) {
182: // The value we're passed is not of the correct type, so
183: // fall through to one of the defaults.
184: }
185: }
186:
187: if (_defaultValue != null) {
188: _component.setText(_formatter.fn(_defaultValue));
189: return;
190: }
191:
192: _component.setText("");
193: }
194:
195: /**
196: * Retrieves the value in the component. If the component contains an
197: * empty string (or one with only whitespace), or if an exception
198: * occurs, then returns the default value (which may be null).
199: */
200: public Object getCellEditorValue() {
201: String txt = _component.getText();
202: if (txt == null || txt.trim().length() == 0) {
203: return _defaultValue;
204: }
205:
206: try {
207: Object val = _parser.fn(txt);
208: return val;
209: } catch (EvaluationException x) {
210: return _defaultValue;
211: }
212: }
213:
214: public String toString() {
215: return "FormattedDelegate[" + _formatter + "," + _parser
216: + "]";
217: }
218: }
219: }
|