Source for javax.swing.JFormattedTextField

   1: /* JFormattedTextField.java --
   2:    Copyright (C) 2003, 2004 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing;
  40: 
  41: import java.awt.event.FocusEvent;
  42: import java.io.Serializable;
  43: import java.text.Format;
  44: import java.text.ParseException;
  45: import java.util.Date;
  46: 
  47: import javax.swing.text.DateFormatter;
  48: import javax.swing.text.DefaultFormatter;
  49: import javax.swing.text.Document;
  50: import javax.swing.text.DocumentFilter;
  51: import javax.swing.text.NavigationFilter;
  52: 
  53: /**
  54:  * @author Michael Koch
  55:  * @since 1.4
  56:  */
  57: public class JFormattedTextField extends JTextField
  58: {
  59:   private static final long serialVersionUID = 5464657870110180632L;
  60: 
  61:   public abstract static class AbstractFormatter implements Serializable
  62:   {
  63:     private static final long serialVersionUID = -5193212041738979680L;
  64:     
  65:     private JFormattedTextField textField;
  66:     
  67:     public AbstractFormatter ()
  68:     {
  69:       //Do nothing here.
  70:     }
  71: 
  72:     protected Object clone ()
  73:       throws CloneNotSupportedException
  74:     {
  75:       throw new InternalError ("not implemented");
  76:     }
  77: 
  78:     protected Action[] getActions ()
  79:     {
  80:       return textField.getActions();
  81:     }
  82: 
  83:     protected DocumentFilter getDocumentFilter ()
  84:     {
  85:       throw new InternalError ("not implemented");
  86:     }
  87: 
  88:     protected JFormattedTextField getFormattedTextField ()
  89:     {
  90:       return textField;
  91:     }
  92: 
  93:     protected NavigationFilter getNavigationFilter ()
  94:     {
  95:       return textField.getNavigationFilter();
  96:     }
  97: 
  98:     public void install(JFormattedTextField textField)
  99:     {
 100:       if (this.textField != null)
 101:     uninstall();
 102:       
 103:       this.textField = textField;
 104:     }
 105: 
 106:     public void uninstall ()
 107:     {
 108:       this.textField = null;
 109:     }
 110: 
 111:     protected void invalidEdit ()
 112:     {
 113:       textField.invalidEdit();
 114:     }
 115: 
 116:     protected void setEditValid (boolean valid)
 117:     {
 118:       textField.editValid = valid;
 119:     }
 120: 
 121:     public abstract Object stringToValue (String text)
 122:       throws ParseException;
 123: 
 124:     public abstract String valueToString (Object value)
 125:       throws ParseException;
 126:   }
 127:   
 128:   public abstract static class AbstractFormatterFactory
 129:   {
 130:     public AbstractFormatterFactory ()
 131:     {
 132:       // Do nothing here.
 133:     }
 134: 
 135:     public abstract AbstractFormatter getFormatter (JFormattedTextField tf);
 136:   }
 137: 
 138:   static class FormatterFactoryWrapper extends AbstractFormatterFactory
 139:   {
 140:     AbstractFormatter formatter;
 141: 
 142:     public FormatterFactoryWrapper(AbstractFormatter formatter)
 143:     {
 144:       this.formatter = formatter;
 145:     }
 146: 
 147:     public AbstractFormatter getFormatter(JFormattedTextField tf)
 148:     {
 149:       return formatter;
 150:     }
 151:   }
 152: 
 153:   public static final int COMMIT = 0;
 154:   public static final int COMMIT_OR_REVERT = 1;
 155:   public static final int REVERT = 2;
 156:   public static final int PERSIST = 3;
 157: 
 158:   private Object value;
 159:   private int focusLostBehavior = COMMIT_OR_REVERT;
 160:   private AbstractFormatterFactory formatterFactory;
 161:   // Package-private to avoid an accessor method.
 162:   boolean editValid = true;
 163:   
 164:   public JFormattedTextField ()
 165:   {
 166:     this((AbstractFormatterFactory) null, null);
 167:   }
 168: 
 169:   public JFormattedTextField (Format format)
 170:   {
 171:     throw new InternalError ("not implemented");
 172:   }
 173: 
 174:   public JFormattedTextField (AbstractFormatter formatter)
 175:   {
 176:     this(new FormatterFactoryWrapper(formatter), null);
 177:   }
 178: 
 179:   public JFormattedTextField (AbstractFormatterFactory factory)
 180:   {
 181:     this(factory, null);
 182:   }
 183: 
 184:   public JFormattedTextField (AbstractFormatterFactory factory, Object value)
 185:   {
 186:     this.formatterFactory = factory;
 187:     this.value = value;
 188:   }
 189: 
 190:   public JFormattedTextField (Object value)
 191:   {
 192:     this.value = value;
 193:   }
 194: 
 195:   public void commitEdit ()
 196:     throws ParseException
 197:   {
 198:     throw new InternalError ("not implemented");
 199:   }
 200: 
 201:   public Action[] getActions ()
 202:   {
 203:     // FIXME: Add JFormattedTextField specific actions
 204:     return super.getActions();
 205:   }
 206: 
 207:   public int getFocusLostBehavior()
 208:   {
 209:     return focusLostBehavior;
 210:   }
 211: 
 212:   public AbstractFormatter getFormatter ()
 213:   {
 214:     if (formatterFactory == null)
 215:       return null;
 216:     
 217:     return formatterFactory.getFormatter(this);
 218:   }
 219: 
 220:   public AbstractFormatterFactory getFormatterFactory ()
 221:   {
 222:     return formatterFactory;
 223:   }
 224: 
 225:   public String getUIClassID ()
 226:   {
 227:     return "FormattedTextFieldUI";
 228:   }
 229: 
 230:   public Object getValue ()
 231:   {
 232:     return value;
 233:   }
 234: 
 235:   protected void invalidEdit ()
 236:   {
 237:     UIManager.getLookAndFeel().provideErrorFeedback(this);
 238:   }
 239: 
 240:   public boolean isEditValid ()
 241:   {
 242:     return editValid;
 243:   }
 244: 
 245:   protected void processFocusEvent (FocusEvent evt)
 246:   {
 247:     // it's safe to simply call super for now, until it gets clear
 248:     // what this method is supposed to do
 249:     // throw new InternalError ("not implemented");
 250:     super.processFocusEvent(evt);
 251:   }
 252: 
 253:   public void setDocument(Document newDocument)
 254:   {
 255:     Document oldDocument = getDocument();
 256: 
 257:     if (oldDocument == newDocument)
 258:       return;
 259:     
 260:     super.setDocument(newDocument);
 261:   }
 262: 
 263:   public void setFocusLostBehavior(int behavior)
 264:   {
 265:     if (behavior != COMMIT
 266:     && behavior != COMMIT_OR_REVERT
 267:     && behavior != PERSIST
 268:     && behavior != REVERT)
 269:       throw new IllegalArgumentException("invalid behavior");
 270: 
 271:     this.focusLostBehavior = behavior;
 272:   }
 273: 
 274:   protected void setFormatter (AbstractFormatter formatter)
 275:   {
 276:     AbstractFormatter oldFormatter = null;
 277:     
 278:     if (formatterFactory != null)
 279:       oldFormatter = formatterFactory.getFormatter(this);
 280: 
 281:     if (oldFormatter == formatter)
 282:       return;
 283: 
 284:     setFormatterFactory(new FormatterFactoryWrapper(formatter));
 285:     firePropertyChange("formatter", oldFormatter, formatter);
 286:   }
 287: 
 288:   public void setFormatterFactory (AbstractFormatterFactory factory)
 289:   {
 290:     if (formatterFactory == factory)
 291:       return;
 292:     
 293:     AbstractFormatterFactory oldFactory = formatterFactory;
 294:     formatterFactory = factory;
 295:     firePropertyChange("formatterFactory", oldFactory, factory);
 296:   }
 297: 
 298:   public void setValue (Object newValue)
 299:   {
 300:     if (value == newValue)
 301:       return;
 302: 
 303:     // format value
 304:     AbstractFormatter formatter = createFormatter(newValue);
 305:     try
 306:       {
 307:         setText(formatter.valueToString(newValue));
 308:       }
 309:     catch (ParseException ex)
 310:       {
 311:         // TODO: what should we do with this?
 312:       }
 313: 
 314:     Object oldValue = value;
 315:     value = newValue;
 316:     firePropertyChange("value", oldValue, newValue);
 317:   }
 318: 
 319:   /**
 320:    * A helper method that attempts to create a formatter that is suitable
 321:    * to format objects of the type like <code>value</code>.
 322:    *
 323:    * If <code>formatterFactory</code> is not null and the returned formatter
 324:    * is also not <code>null</code> then this formatter is used. Otherwise we
 325:    * try to create one based on the type of <code>value</code>.
 326:    *
 327:    * @param value an object which should be formatted by the formatter
 328:    *
 329:    * @return a formatter able to format objects of the class of
 330:    *     <code>value</code>
 331:    */
 332:   AbstractFormatter createFormatter(Object value)
 333:   {
 334:     AbstractFormatter formatter = null;
 335:     if (formatterFactory != null
 336:         && formatterFactory.getFormatter(this) != null)
 337:      formatter = formatterFactory.getFormatter(this);
 338:    else
 339:      {
 340:        if (value instanceof Date)
 341:          formatter = new DateFormatter();
 342:        else
 343:          formatter = new DefaultFormatter();
 344:      }
 345:     return formatter;
 346:   }
 347: }