001    package org.springframework.richclient.form.binding.swing;
002    
003    import java.awt.event.ActionEvent;
004    import java.awt.event.ActionListener;
005    import java.util.ArrayList;
006    import java.util.LinkedHashMap;
007    import java.util.List;
008    import java.util.Map;
009    
010    import javax.swing.ButtonGroup;
011    import javax.swing.JComponent;
012    import javax.swing.JPanel;
013    import javax.swing.JRadioButton;
014    
015    import org.springframework.binding.form.FormModel;
016    import org.springframework.context.support.MessageSourceAccessor;
017    import org.springframework.richclient.form.binding.support.CustomBinding;
018    import org.springframework.util.Assert;
019    
020    import com.jgoodies.forms.factories.FormFactory;
021    import com.jgoodies.forms.layout.CellConstraints;
022    import com.jgoodies.forms.layout.ColumnSpec;
023    import com.jgoodies.forms.layout.FormLayout;
024    import com.jgoodies.forms.layout.RowSpec;
025    
026    /**
027     * Radiobutton binding for Enum values.
028     *
029     * Labels for the radio buttons can be configured in the messages:
030     *
031     * <pre>
032     * my.package.MyClass.MY_ENUM = My Enum Label
033     * my.package.MyClass.null = None
034     * </pre>
035     *
036     * @author Lieven Doclo
037     *
038     */
039    public class EnumRadioButtonBinding extends CustomBinding {
040    
041        private JPanel contentPanel;
042    
043        private List<Enum> selectableEnumsList;
044    
045        private Map<String, ContainerJRadioButton<Enum>> radioButtons;
046    
047        private Class propertyType;
048    
049        private ButtonGroup group;
050    
051        private MessageSourceAccessor messageSourceAccessor;
052    
053        public EnumRadioButtonBinding(JPanel contentPanel, FormModel formModel, String formPropertyPath,
054                Class<?> propertyType, List<Enum> selectableEnumsList) {
055            super(formModel, formPropertyPath, propertyType);
056            this.contentPanel = contentPanel;
057            this.propertyType = propertyType;
058            radioButtons = new LinkedHashMap<String, ContainerJRadioButton<Enum>>();
059            messageSourceAccessor = getMessages();
060            this.selectableEnumsList = selectableEnumsList;
061            createRadioButtons();
062        }
063    
064        @Override
065        protected void valueModelChanged(Object newValue) {
066            deselectAll();
067            Enum enumValue = (Enum) newValue;
068            ContainerJRadioButton<Enum> button;
069            if (enumValue == null) {
070                button = radioButtons.get(null);
071            }
072            else {
073                button = radioButtons.get(enumValue.name());
074            }
075            if (button != null) {
076                button.setSelected(true);
077            }
078        }
079    
080        private void deselectAll() {
081            if (group != null)
082                group.clearSelection();
083        }
084    
085        @Override
086        protected JComponent doBindControl() {
087            Assert.notNull(selectableEnumsList);
088            return createBindingControl();
089        }
090    
091        private JPanel createBindingControl() {
092            group = new ButtonGroup();
093            FormLayout layout = new FormLayout(new ColumnSpec[] { FormFactory.DEFAULT_COLSPEC },
094                    getDefaultRowsWithGap(radioButtons.keySet().size()));
095            int count = 1;
096            contentPanel.setLayout(layout);
097            for (ContainerJRadioButton<Enum> button : radioButtons.values()) {
098                group.add(button);
099                contentPanel.add(button, new CellConstraints(1, count));
100                count += 2;
101            }
102            valueModelChanged(getValue());
103            return contentPanel;
104        }
105    
106        private static RowSpec[] getDefaultRowsWithGap(int rowCount) {
107            List<RowSpec> rows = new ArrayList<RowSpec>();
108            for (int i = 0; i < rowCount; i++) {
109                rows.add(new RowSpec("fill:pref:nogrow"));
110                rows.add(FormFactory.LINE_GAP_ROWSPEC);
111            }
112            rows.remove(rows.size() - 1);
113            return rows.toArray(new RowSpec[] {});
114        }
115    
116        @Override
117        protected void enabledChanged() {
118            for (ContainerJRadioButton<Enum> button : radioButtons.values()) {
119                button.setEnabled(isEnabled());
120            }
121    
122        }
123    
124        @Override
125        protected void readOnlyChanged() {
126            for (ContainerJRadioButton<Enum> button : radioButtons.values()) {
127                button.setEnabled(isReadOnly());
128            }
129        }
130    
131        private void createRadioButtons() {
132            for (Enum enumValue : selectableEnumsList) {
133                ContainerJRadioButton<Enum> button = new ContainerJRadioButton<Enum>();
134                String text;
135                if (enumValue == null) {
136                    text = messageSourceAccessor.getMessage(propertyType.getName() + ".null", "null");
137                    button.setText(text == null ? propertyType.getName() + ".null" : text);
138                }
139                else {
140                    text = messageSourceAccessor.getMessage(propertyType.getName() + "." + enumValue.name(), enumValue
141                            .name());
142                    button.setText(text == null ? propertyType.getName() + "." + enumValue.name() : text);
143                }
144                button.setContainedObject(enumValue);
145                button.addActionListener(new ActionListener() {
146    
147                    public void actionPerformed(ActionEvent e) {
148                        ContainerJRadioButton<Enum> button = (ContainerJRadioButton<Enum>) e.getSource();
149                        controlValueChanged(button.getContainedObject());
150                    }
151    
152                });
153                if (enumValue == null)
154                    radioButtons.put(null, button);
155                else
156                    radioButtons.put(enumValue.name(), button);
157    
158            }
159        }
160    
161        private class ContainerJRadioButton<T> extends JRadioButton {
162    
163            private T containedObject;
164    
165            public T getContainedObject() {
166                return containedObject;
167            }
168    
169            public void setContainedObject(T containedObject) {
170                this.containedObject = containedObject;
171            }
172    
173        }
174    
175    }