001    /*
002     * Copyright 2002-2008 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.selection.binding.support;
017    
018    import java.awt.BorderLayout;
019    import java.awt.FlowLayout;
020    import java.beans.PropertyChangeListener;
021    
022    import javax.swing.JComponent;
023    import javax.swing.JPanel;
024    
025    import org.springframework.binding.value.PropertyChangePublisher;
026    import org.springframework.binding.value.support.PropertyChangeSupport;
027    import org.springframework.richclient.application.ApplicationServicesLocator;
028    import org.springframework.richclient.command.ActionCommand;
029    import org.springframework.richclient.command.config.CommandConfigurer;
030    import org.springframework.richclient.dialog.ApplicationDialog;
031    import org.springframework.richclient.factory.AbstractControlFactory;
032    
033    /**
034     * <tt>SelectField</tt> base class. Allows for customization of the renderer component.
035     * <p>
036     * A <tt>SelectField</tt> provides a renderer component (provided by subclasses), a select button and a clear button.
037     * The renderer component shows the current value, the select button opens the selection dialog, and the clear button
038     * sets the value to <code>null</code>.
039     * </p>
040     * 
041     * @author Peter De Bruycker
042     */
043    public abstract class SelectField extends AbstractControlFactory implements PropertyChangePublisher {
044    
045        private JComponent renderer;
046        private SelectCommand selectCommand = new SelectCommand();
047        private ClearCommand clearCommand = new ClearCommand();
048        private boolean editable;
049        private Object value;
050        private ApplicationDialog dialog;
051        private LabelProvider labelProvider;
052        private JPanel control;
053        private boolean nullable = true;
054    
055        private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
056    
057        protected JComponent createControl() {
058            control = new JPanel(new BorderLayout());
059    
060            renderer = createRenderer();
061            control.add(renderer);
062    
063            // configure commands
064            CommandConfigurer configurer = (CommandConfigurer) ApplicationServicesLocator.services().getService(
065                    CommandConfigurer.class);
066            configurer.configure(selectCommand);
067            configurer.configure(clearCommand);
068    
069            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
070    
071            buttonPanel.add(selectCommand.createButton());
072            if (nullable) {
073                buttonPanel.add(clearCommand.createButton());
074            }
075    
076            control.add(buttonPanel, BorderLayout.LINE_END);
077    
078            return control;
079        }
080    
081        /**
082         * Create the component that will do the rendering. Cannot return <code>null</code>.
083         * 
084         * @return the renderer component
085         */
086        protected abstract JComponent createRenderer();
087    
088        public void setEnabled(boolean enabled) {
089            control.setEnabled(enabled);
090    
091            renderer.setEnabled(enabled);
092            selectCommand.setEnabled(enabled);
093            clearCommand.setEnabled(enabled);
094        }
095    
096        public void setEditable(boolean editable) {
097            this.editable = editable;
098    
099            selectCommand.setEnabled(control.isEnabled() && editable);
100            clearCommand.setEnabled(control.isEnabled() && editable);
101        }
102    
103        public boolean isEditable() {
104            return editable;
105        }
106    
107        public void setValue(Object value) {
108            Object oldValue = this.value;
109            this.value = value;
110    
111            render(value);
112    
113            propertyChangeSupport.firePropertyChange("value", oldValue, value);
114        }
115    
116        /**
117         * Convenience method, calls <code>setValue(null)</code>.
118         */
119        public void clear() {
120            setValue(null);
121        }
122    
123        /**
124         * Render the given value. Warning: the value can be <code>null</code>.
125         * 
126         * @param value
127         *            the value
128         */
129        protected abstract void render(Object value);
130    
131        public Object getValue() {
132            return value;
133        }
134    
135        public void setSelectionDialog(ApplicationDialog dialog) {
136            this.dialog = dialog;
137        }
138    
139        public void setLabelProvider(LabelProvider labelProvider) {
140            this.labelProvider = labelProvider;
141        }
142    
143        public LabelProvider getLabelProvider() {
144            return labelProvider;
145        }
146    
147        /**
148         * Returns whether the property is nullable. If set to true, the "clear" button is shown.
149         * 
150         * @return whether the property is nullable
151         */
152        public boolean isNullable() {
153            return nullable;
154        }
155    
156        /**
157         * Sets whether the clear button is shown
158         * 
159         * @param nullable
160         *            whether the clear button is shown
161         */
162        public void setNullable(boolean nullable) {
163            this.nullable = nullable;
164        }
165    
166        private class ClearCommand extends ActionCommand {
167    
168            public ClearCommand() {
169                super("selectField.clearCommand");
170            }
171    
172            protected void doExecuteCommand() {
173                clear();
174            }
175    
176        }
177    
178        private class SelectCommand extends ActionCommand {
179    
180            public SelectCommand() {
181                super("selectField.selectCommand");
182            }
183    
184            protected void doExecuteCommand() {
185                dialog.showDialog();
186            }
187        }
188    
189        public void addPropertyChangeListener(PropertyChangeListener listener) {
190            propertyChangeSupport.addPropertyChangeListener(listener);
191        }
192    
193        public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
194            propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
195        }
196    
197        public void removePropertyChangeListener(PropertyChangeListener listener) {
198            propertyChangeSupport.removePropertyChangeListener(listener);
199        }
200    
201        public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
202            propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
203        }
204    }