001 /* 002 * Copyright 2002-2004 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016 package org.springframework.binding.value.swing; 017 018 import java.awt.event.FocusEvent; 019 import java.awt.event.FocusListener; 020 import java.beans.PropertyChangeEvent; 021 import java.beans.PropertyChangeListener; 022 import java.text.ParseException; 023 024 import javax.swing.JFormattedTextField; 025 import javax.swing.event.DocumentEvent; 026 import javax.swing.event.DocumentListener; 027 028 import org.springframework.binding.value.ValueModel; 029 import org.springframework.binding.value.support.AbstractValueModelAdapter; 030 031 /** 032 * Sets the value of the value model associated with a formatted text field when the text field changes according to the 033 * value commit policy. 034 * 035 * This setter will also update the formatted text field value when the underlying value model value changes. 036 * 037 * @author Oliver Hutchison 038 * @author Keith Donald 039 */ 040 public class FormattedTextFieldAdapter extends AbstractValueModelAdapter implements PropertyChangeListener, 041 DocumentListener, FocusListener { 042 043 private final JFormattedTextField component; 044 045 private boolean settingValue; 046 047 private boolean ignoreValue; 048 049 public FormattedTextFieldAdapter(JFormattedTextField component, ValueModel valueModel, 050 ValueCommitPolicy commitPolicy) { 051 super(valueModel); 052 this.component = component; 053 this.component.setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT); 054 this.component.addPropertyChangeListener("value", this); 055 if (commitPolicy == ValueCommitPolicy.AS_YOU_TYPE) { 056 component.getDocument().addDocumentListener(this); 057 } 058 059 // mathiasbr: register focus listener to avoid a race condition. 060 // If the formatted text field lost its focus the value will be replaced. 061 // This results into two events: the first one sets the value to null 062 // the second one sets the value to its value before it was set to null. 063 // If the focus is moved to the button which is bound to the validation 064 // and the field has a constraint (like required) the button will be disabled 065 // while it is pressed. Although the button will be enabled when the second 066 // event with the previous value is set again but the button will lost its 067 // armed and pressed state when it is disabled. 068 // The result is that a user has to click the button twice 069 // before the button fires the actionPerformed event 070 component.addFocusListener(this); 071 072 initalizeAdaptedValue(); 073 } 074 075 protected void valueModelValueChanged(Object value) { 076 settingValue = true; 077 try { 078 component.setValue(value); 079 } finally { 080 settingValue = false; 081 } 082 } 083 084 public void propertyChange(PropertyChangeEvent e) { 085 if (logger.isDebugEnabled()) { 086 Class valueClass = (e.getNewValue() != null ? e.getNewValue().getClass() : null); 087 logger.debug("Formatted text field property '" + e.getPropertyName() + "' changed; new value is '" 088 + e.getNewValue() + "', valueClass=" + valueClass); 089 } 090 adaptedValueChanged(component.getValue()); 091 } 092 093 public void insertUpdate(DocumentEvent e) { 094 tryToCommitEdit(); 095 } 096 097 public void removeUpdate(DocumentEvent e) { 098 if (!ignoreValue) 099 tryToCommitEdit(); 100 else 101 ignoreValue = false; 102 } 103 104 public void changedUpdate(DocumentEvent e) { 105 tryToCommitEdit(); 106 } 107 108 private void tryToCommitEdit() { 109 if (!settingValue) { 110 try { 111 component.commitEdit(); 112 } catch (ParseException e) { 113 // ignore 114 } 115 } 116 } 117 118 public void focusGained(FocusEvent e) { 119 ignoreValue = false; 120 } 121 122 public void focusLost(FocusEvent e) { 123 ignoreValue = true; 124 } 125 }