001    package org.springframework.richclient.components;
002    
003    import org.apache.commons.logging.Log;
004    import org.apache.commons.logging.LogFactory;
005    import org.springframework.richclient.form.binding.swing.text.TimeFormatter;
006    
007    import javax.swing.*;
008    import javax.swing.text.BadLocationException;
009    import javax.swing.text.PlainDocument;
010    import javax.swing.text.AttributeSet;
011    import java.awt.event.FocusEvent;
012    import java.awt.event.FocusListener;
013    
014    public class TimeTextField extends JFormattedTextField
015    {
016    
017        Log log = LogFactory.getLog(TimeTextField.class);
018    
019        private static final String INPUT_SEPARATORS = "[hHuU\\s\\.,+*-/]";
020    
021        public TimeTextField()
022        {
023            super(new TimeFormatter());
024            this.setDocument(new TimeDocument());
025            setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT);
026            addFocusListener(new UpdateFocusListener());
027        }
028    
029        private void updateText(String txt)
030        {
031            try
032            {
033                getDocument().remove(0, getText().length());
034                getDocument().insertString(0, txt, null);
035            }
036            catch (BadLocationException e)
037            {
038                log.error("Text out of boundaries. ", e);
039            }
040        }
041    
042        protected void processFocusEvent(FocusEvent e)
043        {
044            super.processFocusEvent(e);
045            if (e.getID() == FocusEvent.FOCUS_GAINED)
046            {
047                setCaretPosition(0);
048                moveCaretPosition(getDocument().getLength());
049            }
050        }
051    
052        class UpdateFocusListener implements FocusListener
053        {
054    
055            public void focusGained(FocusEvent e)
056            {
057            }
058    
059            public void focusLost(FocusEvent e)
060            {
061                try
062                {
063                    commitEdit();
064                    String valueToString = getFormatter().valueToString(getValue());
065                    updateText(valueToString);
066                }
067                catch (Exception e1)
068                {
069                    log.error("Invalid date format. ", e1);
070                }
071            }
072        }
073    
074        class TimeDocument extends PlainDocument
075        {
076    
077            public void replace(int offset, int length, String text, AttributeSet attrs)
078                    throws BadLocationException
079            {
080                remove(offset, length);
081                insertString(offset, text, attrs);
082            }
083    
084            public void remove(int offs, int len) throws BadLocationException
085            {
086                super.remove(offs, len);
087            }
088    
089            public void insertString(int offset, String str, AttributeSet a) throws BadLocationException
090            {
091                if ((str = isValidString(offset, str)) != null)
092                    super.insertString(offset, str, a);
093            }
094    
095            private String isValidString(int offset, String str) throws BadLocationException
096            {
097                if (str == null)
098                    return null;
099                str = str.replaceAll(INPUT_SEPARATORS, TimeFormatter.SEPARATOR_STRING); // set
100                // correct
101                // Separator
102    
103                String s = getText(0, offset) + str;
104                if (offset < getLength())
105                    s += getText(offset, getLength() - offset);
106    
107                char[] strArray = s.toCharArray();
108                int sepPos = -1;
109                for (int i = 0; i < strArray.length; ++i) // check on only
110                // digits/one separator
111                {
112                    if (!Character.isDigit(strArray[i]))
113                    {
114                        if (!(TimeFormatter.SEPARATOR == strArray[i]) || (sepPos != -1))
115                            return null;
116    
117                        sepPos = i;
118                        if ((sepPos > 2) || ((getLength() - sepPos) > 2)) // separator
119                            // on a
120                            // correct
121                            // position
122                            return null;
123                    }
124                }
125    
126                int length = sepPos == -1 ? s.length() : s.length() - 1;
127                if (length > 4) // correct number of digits
128                    return null;
129    
130                return str;
131            }
132        }
133    }