001/*
002 *  jDTAUS Banking Utilities
003 *  Copyright (C) 2005 Christian Schulte
004 *  <cs@schulte.it>
005 *
006 *  This library is free software; you can redistribute it and/or
007 *  modify it under the terms of the GNU Lesser General Public
008 *  License as published by the Free Software Foundation; either
009 *  version 2.1 of the License, or any later version.
010 *
011 *  This library is distributed in the hope that it will be useful,
012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 *  Lesser General Public License for more details.
015 *
016 *  You should have received a copy of the GNU Lesser General Public
017 *  License along with this library; if not, write to the Free Software
018 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
019 *
020 */
021package org.jdtaus.banking.util.swing;
022
023import java.text.ParseException;
024import javax.swing.JFormattedTextField;
025import javax.swing.JFormattedTextField.AbstractFormatter;
026import javax.swing.text.AttributeSet;
027import javax.swing.text.BadLocationException;
028import javax.swing.text.DocumentFilter;
029import javax.swing.text.DocumentFilter.FilterBypass;
030import org.jdtaus.banking.Kontonummer;
031import org.jdtaus.core.container.ContainerFactory;
032import org.jdtaus.core.container.PropertyException;
033
034/**
035 * {@code JFormattedTextField} supporting the {@code Kontonummer} type.
036 * <p>This textfield uses the {@link Kontonummer} type for parsing and formatting. An empty string value is treated as
037 * {@code null}. Property {@code format} controls formatting and takes one of the format constants defined in class
038 * {@code Kontonummer}. By default the {@code ELECTRONIC_FORMAT} is used. The {@code validating} flag controls
039 * validation of values entered into the textfield. If {@code true} (default), a {@code DocumentFilter} is registered
040 * with the textfield disallowing invalid values, that is, values which are not {@code null} and not empty strings and
041 * for which the {@link Kontonummer#parse(String)} method throws a {@code ParseException}.</p>
042 *
043 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
044 * @version $JDTAUS: KontonummerTextField.java 8864 2014-01-10 17:13:30Z schulte $
045 */
046public final class KontonummerTextField extends JFormattedTextField
047{
048
049    /** Serial version UID for backwards compatibility with 1.1.x classes. */
050    private static final long serialVersionUID = -959284086262750493L;
051
052    /**
053     * Format used to format Kontonummer instances.
054     * @serial
055     */
056    private Integer format;
057
058    /**
059     * Flag indicating if validation is performed.
060     * @serial
061     */
062    private Boolean validating;
063
064    /** Creates a new default {@code KontonummerTextField} instance. */
065    public KontonummerTextField()
066    {
067        super();
068        this.assertValidProperties();
069        this.setColumns( Kontonummer.MAX_CHARACTERS );
070        this.setFormatterFactory( new AbstractFormatterFactory()
071        {
072
073            public AbstractFormatter getFormatter( final JFormattedTextField ftf )
074            {
075                return new AbstractFormatter()
076                {
077
078                    public Object stringToValue( final String text ) throws ParseException
079                    {
080                        Object value = null;
081
082                        if ( text != null && text.trim().length() > 0 )
083                        {
084                            value = Kontonummer.parse( text );
085                        }
086
087                        return value;
088                    }
089
090                    public String valueToString( final Object value ) throws ParseException
091                    {
092                        String ret = null;
093
094                        if ( value instanceof Kontonummer )
095                        {
096                            final Kontonummer kto = (Kontonummer) value;
097                            ret = kto.format( getFormat() );
098                        }
099
100                        return ret;
101                    }
102
103                    protected DocumentFilter getDocumentFilter()
104                    {
105                        return new DocumentFilter()
106                        {
107
108                            public void insertString( final FilterBypass fb, final int o, String s,
109                                                      final AttributeSet a ) throws BadLocationException
110                            {
111                                if ( isValidating() )
112                                {
113                                    final StringBuffer b = new StringBuffer( fb.getDocument().getLength() + s.length() );
114                                    b.append( fb.getDocument().getText( 0, fb.getDocument().getLength() ) );
115                                    b.insert( o, s );
116
117                                    try
118                                    {
119                                        Kontonummer.parse( b.toString() );
120                                    }
121                                    catch ( ParseException e )
122                                    {
123                                        invalidEdit();
124                                        return;
125                                    }
126                                }
127
128                                super.insertString( fb, o, s, a );
129                            }
130
131                            public void replace( final FilterBypass fb, final int o, final int l, String s,
132                                                 final AttributeSet a ) throws BadLocationException
133                            {
134                                if ( isValidating() )
135                                {
136                                    final StringBuffer b = new StringBuffer(
137                                        fb.getDocument().getText( 0, fb.getDocument().getLength() ) );
138
139                                    b.delete( o, o + l );
140
141                                    if ( s != null )
142                                    {
143                                        b.insert( o, s );
144                                    }
145
146                                    try
147                                    {
148                                        Kontonummer.parse( b.toString() );
149                                    }
150                                    catch ( ParseException e )
151                                    {
152                                        invalidEdit();
153                                        return;
154                                    }
155                                }
156
157                                super.replace( fb, o, l, s, a );
158                            }
159
160                        };
161                    }
162
163                };
164            }
165
166        } );
167    }
168
169    /**
170     * Gets the last valid {@code Kontonummer}.
171     *
172     * @return the last valid {@code Kontonummer} or {@code null}.
173     */
174    public Kontonummer getKontonummer()
175    {
176        return (Kontonummer) this.getValue();
177    }
178
179    /**
180     * Gets the constant of the format used when formatting Kontonummer instances.
181     *
182     * @return the constant of the format used when formatting Kontonummer instances.
183     *
184     * @see Kontonummer#ELECTRONIC_FORMAT
185     * @see Kontonummer#LETTER_FORMAT
186     */
187    public int getFormat()
188    {
189        if ( this.format == null )
190        {
191            this.format = this.getDefaultFormat();
192        }
193
194        return this.format.intValue();
195    }
196
197    /**
198     * Sets the constant of the format to use when formatting Kontonummer instances.
199     *
200     * @param value the constant of the format to use when formatting Kontonummer instances.
201     *
202     * @throws IllegalArgumentException if {@code format} is neither {@code ELECTRONIC_FORMAT} nor
203     * {@code LETTER_FORMAT}.
204     *
205     * @see Kontonummer#ELECTRONIC_FORMAT
206     * @see Kontonummer#LETTER_FORMAT
207     */
208    public void setFormat( final int value )
209    {
210        if ( value != Kontonummer.ELECTRONIC_FORMAT && value != Kontonummer.LETTER_FORMAT )
211        {
212            throw new IllegalArgumentException( Integer.toString( value ) );
213        }
214
215        this.format = new Integer( value );
216    }
217
218    /**
219     * Gets the flag indicating if validation is performed.
220     *
221     * @return {@code true} if the field's value is validated; {@code false} if no validation of the field's value is
222     * performed.
223     */
224    public boolean isValidating()
225    {
226        if ( this.validating == null )
227        {
228            this.validating = this.isDefaultValidating();
229        }
230
231        return this.validating.booleanValue();
232    }
233
234    /**
235     * Sets the flag indicating if validation should be performed.
236     *
237     * @param value {@code true} to validate the field's value; {@code false} to not validate the field's value.
238     */
239    public void setValidating( boolean value )
240    {
241        this.validating = Boolean.valueOf( value );
242    }
243
244    /**
245     * Checks configured properties.
246     *
247     * @throws PropertyException for invalid property values.
248     */
249    private void assertValidProperties()
250    {
251        if ( this.getFormat() != Kontonummer.ELECTRONIC_FORMAT && this.getFormat() != Kontonummer.LETTER_FORMAT )
252        {
253            throw new PropertyException( "format", Integer.toString( this.getFormat() ) );
254        }
255    }
256
257    //--Properties--------------------------------------------------------------
258
259// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausProperties
260    // This section is managed by jdtaus-container-mojo.
261
262    /**
263     * Gets the value of property <code>defaultValidating</code>.
264     *
265     * @return Default value of the flag indicating if validation should be performed.
266     */
267    private java.lang.Boolean isDefaultValidating()
268    {
269        return (java.lang.Boolean) ContainerFactory.getContainer().
270            getProperty( this, "defaultValidating" );
271
272    }
273
274    /**
275     * Gets the value of property <code>defaultFormat</code>.
276     *
277     * @return Default value of the format to use when formatting Kontonummer instances (4001 = electronic format, 4002 letter format).
278     */
279    private java.lang.Integer getDefaultFormat()
280    {
281        return (java.lang.Integer) ContainerFactory.getContainer().
282            getProperty( this, "defaultFormat" );
283
284    }
285
286// </editor-fold>//GEN-END:jdtausProperties
287
288    //--------------------------------------------------------------Properties--
289}