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.richclient.dialog;
017    
018    import java.awt.Window;
019    import java.awt.event.FocusAdapter;
020    import java.awt.event.FocusEvent;
021    import java.beans.PropertyChangeListener;
022    
023    import javax.swing.JComponent;
024    import javax.swing.JFormattedTextField;
025    import javax.swing.SwingUtilities;
026    import javax.swing.text.JTextComponent;
027    
028    import org.springframework.binding.form.ValidatingFormModel;
029    import org.springframework.rules.closure.Closure;
030    import org.springframework.rules.constraint.Constraint;
031    import org.springframework.richclient.core.Message;
032    import org.springframework.richclient.form.FormGuard;
033    import org.springframework.richclient.form.FormModelHelper;
034    import org.springframework.richclient.form.SimpleValidationResultsReporter;
035    import org.springframework.richclient.form.binding.swing.SwingBindingFactory;
036    import org.springframework.richclient.layout.TableLayoutBuilder;
037    import org.springframework.util.Assert;
038    
039    /**
040     * Simple input application dialog consisting of a label and a text field for
041     * accepting input.
042     *
043     * @author Keith Donald
044     */
045    public class InputApplicationDialog extends ApplicationDialog implements Messagable {
046    
047        private String inputLabelMessage = "dialog.input";
048    
049        private JComponent inputField;
050    
051        private Constraint inputConstraint;
052    
053        private Closure finishAction;
054    
055        private MessagePane reporter;
056    
057        private ValidatingFormModel formModel;
058    
059        public InputApplicationDialog(Object bean, String propertyName) {
060            this(bean, propertyName, true);
061        }
062    
063        public InputApplicationDialog(Object bean, String propertyName, boolean bufferChanges) {
064            this(FormModelHelper.createFormModel(bean, bufferChanges), propertyName);
065        }
066    
067        public InputApplicationDialog(ValidatingFormModel formModel, String propertyName) {
068            this();
069            this.formModel = formModel;
070            setInputField(new SwingBindingFactory(formModel).createBinding(propertyName).getControl());
071        }
072    
073        public InputApplicationDialog() {
074            this(null, null, CloseAction.DISPOSE);
075        }
076    
077        public InputApplicationDialog(String title, Window parent) {
078            this(title, parent, CloseAction.DISPOSE);
079        }
080    
081        public InputApplicationDialog(String title, Window parent, CloseAction closeAction) {
082            super(title, parent, closeAction);
083            setResizable(true);
084        }
085    
086        public void setInputField(JComponent field) {
087            Assert.notNull(field);
088            this.inputField = field;
089        }
090    
091        public void setInputLabelMessage(String inputLabel) {
092            Assert.hasText(inputLabel, "The input label is required");
093            this.inputLabelMessage = inputLabel;
094        }
095    
096        public void setInputConstraint(Constraint constraint) {
097            this.inputConstraint = constraint;
098        }
099    
100        public void setFinishAction(Closure procedure) {
101            this.finishAction = procedure;
102        }
103    
104        protected MessagePane createMessagePane() {
105            return new DefaultMessageAreaPane();
106        }
107    
108        private MessagePane getMessagePane() {
109            if (reporter == null) {
110                reporter = createMessagePane();
111    
112                    if (this.formModel != null) {
113                    new SimpleValidationResultsReporter(formModel.getValidationResults(), reporter);
114                    FormGuard formGuard = new FormGuard(formModel);
115                    formGuard.addGuarded(this, FormGuard.FORMERROR_GUARDED);
116                }
117            }
118            return reporter;
119        }
120    
121        protected JComponent createDialogContentPane() {
122            TableLayoutBuilder layoutBuilder = new TableLayoutBuilder();
123    
124            if (this.inputField == null) {
125                this.inputField = getComponentFactory().createTextField();
126            }
127            // work around for bug in JFormattedTextField text field for selectAll
128            if (inputField instanceof JFormattedTextField) {
129                SelectAllBugFixer selectAllBugFixer = new SelectAllBugFixer();
130                inputField.addFocusListener(selectAllBugFixer);
131            }
132    
133            layoutBuilder.cell(createInputLabel(), TableLayoutBuilder.DEFAULT_LABEL_ATTRIBUTES);
134            layoutBuilder.labelGapCol();
135            layoutBuilder.cell(inputField);
136    
137            layoutBuilder.unrelatedGapRow();
138            layoutBuilder.cell(getMessagePane().getControl());
139    
140            layoutBuilder.relatedGapRow();
141            layoutBuilder.separator("");
142            return layoutBuilder.getPanel();
143        }
144    
145        protected JComponent createInputLabel() {
146            return getComponentFactory().createLabelFor(inputLabelMessage, getInputField());
147        }
148    
149        protected boolean onFinish() {
150            if (checkInputConstraint()) {
151                onFinish(getInputValue());
152                return true;
153            }
154            return false;
155        }
156    
157        private boolean checkInputConstraint() {
158            if (inputConstraint != null)
159                return inputConstraint.test(getInputValue());
160    
161            return true;
162        }
163    
164        private Object getInputValue() {
165            if (inputField instanceof JFormattedTextField) {
166                return ((JFormattedTextField)inputField).getValue();
167            }
168            else if (inputField instanceof JTextComponent) {
169                return ((JTextComponent)inputField).getText();
170            }
171            else {
172                throw new IllegalStateException("Input field type not supported");
173            }
174        }
175    
176        protected void onFinish(Object inputValue) {
177            if (formModel != null) {
178                formModel.commit();
179            }
180            if (finishAction != null) {
181                finishAction.call(inputValue);
182            }
183        }
184    
185        public ValidatingFormModel getFormModel() {
186            return formModel;
187        }
188    
189        /**
190         * @return Returns the inputField.
191         */
192        public JComponent getInputField() {
193            return inputField;
194        }
195    
196        private static class SelectAllBugFixer extends FocusAdapter {
197            public void focusGained(final FocusEvent evt) {
198                SwingUtilities.invokeLater(new Runnable() {
199                    public void run() {
200                        ((JFormattedTextField)evt.getComponent()).selectAll();
201                    }
202                });
203            }
204        }
205    
206            public void setMessage(Message message) {
207                    getMessagePane().setMessage(message);
208            }
209    
210            public void addPropertyChangeListener(PropertyChangeListener listener) {
211                    getMessagePane().addPropertyChangeListener(listener);
212            }
213    
214            public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
215                    getMessagePane().addPropertyChangeListener(propertyName, listener);
216            }
217    
218            public void removePropertyChangeListener(PropertyChangeListener listener) {
219                    getMessagePane().removePropertyChangeListener(listener);
220            }
221    
222            public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
223                    getMessagePane().removePropertyChangeListener(propertyName, listener);
224            }
225    }