001    /*
002     * $Id: EnumComboBoxModel.java,v 1.5 2006/04/18 23:43:30 rbair Exp $
003     *
004     * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005     * Santa Clara, California 95054, U.S.A. All rights reserved.
006     *
007     * This library is free software; you can redistribute it and/or
008     * modify it under the terms of the GNU Lesser General Public
009     * License as published by the Free Software Foundation; either
010     * version 2.1 of the License, or (at your option) any later version.
011     * 
012     * This library is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015     * Lesser General Public License for more details.
016     * 
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this library; if not, write to the Free Software
019     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020     */
021    package org.jdesktop.swingx.combobox;
022    
023    import java.util.ArrayList;
024    import java.util.EnumSet;
025    import java.util.List;
026    import javax.swing.AbstractListModel;
027    import javax.swing.BoxLayout;
028    import javax.swing.ComboBoxModel;
029    import javax.swing.JComboBox;
030    import javax.swing.JFrame;
031    
032    /**
033     * <p>A ComboBoxModel implementation that safely wraps an Enum. It allows the
034     * developer to directly use an enum as their model for a combobox without any
035     * extra work, though the display can can be further customized. </p>
036     *
037     * <h4>Simple Usage</h4>
038     * 
039     * <p>The simplest usage is to wrap an <code>enum</code> inside the 
040     * <code>EnumComboBoxModel</code> and then set it as the model on the
041     * combo box. The combo box will then appear on screen with each value 
042     * in the <code>enum</code> as a value in the combobox.
043     * </p>
044     * <p>ex:</p>
045     * <pre><code>
046     *  enum MyEnum { GoodStuff, BadStuff };
047     *  ...
048     *  JComboBox combo = new JComboBox();
049     *  combo.setModel(new EnumComboBoxModel(MyEnum.class));
050     * </code></pre>
051     *
052     * <h4>Type safe access</h4>
053     * <p>By using generics and co-variant types you can make accessing elements from the model
054     * be completely typesafe. ex:
055     *</p>
056     *
057     *<pre><code>
058     *  EnumComboBoxModel<MyEnum> enumModel = new EnumComboBoxModel<MyEnum1>(MyEnum1.class);
059     *  MyEnum first = enumModel.getElement(0);
060     *  MyEnum selected = enumModel.getSelectedItem();
061     *</code></pre>
062     *
063     * <h4>Advanced Usage</h4>
064     * <p>Since the exact <code>toString()</code> value of each enum constant 
065     * may not be exactly what you want on screen (the values 
066     * won't have spaces, for example) you can override to 
067     * toString() method on the values when you declare your 
068     * enum. Thus the display value is localized to the enum 
069     * and not in your GUI code. ex:
070     * <pre><code>
071     *    private enum MyEnum {GoodStuff, BadStuff;
072     *        public String toString() {
073     *           switch(this) {
074     *               case GoodStuff: return "Some Good Stuff";
075     *               case BadStuff: return "Some Bad Stuff";
076     *           }
077     *           return "ERROR";
078     *        }
079     *    };
080     * </code></pre>
081     * 
082     *
083     * @author joshy
084     */
085    public class EnumComboBoxModel<E extends Enum<E>> 
086            extends AbstractListModel implements ComboBoxModel {
087        private E selected = null;
088        private List<E> list;
089    
090        public EnumComboBoxModel(Class<E> en) {
091            EnumSet<E> ens = EnumSet.allOf(en);
092            list = new ArrayList<E>(ens);
093            selected = list.get(0);
094        }
095    
096        public int getSize() {
097            return list.size();
098        }
099    
100        public E getElementAt(int index) {
101            return list.get(index);
102        }
103    
104        public void setSelectedItem(Object anItem) {
105            try {
106                selected = (E)anItem;
107            } catch (ClassCastException e) {
108                throw new IllegalArgumentException(anItem + " not of the expected type", e);
109            }
110            this.fireContentsChanged(this,0,getSize());
111        }
112        
113        public E getSelectedItem() {
114        return selected;
115        }
116        
117        /*
118        public static void main(String[] args) {
119            JFrame frame = new JFrame();
120            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
121            frame.setLayout(new BoxLayout(frame.getContentPane(),BoxLayout.Y_AXIS));
122            
123            
124            JComboBox combo1 = new JComboBox();
125            combo1.setModel(new EnumComboBoxModel(MyEnum1.class));
126            frame.add(combo1);
127            
128            JComboBox combo2 = new JComboBox();
129            combo2.setModel(new EnumComboBoxModel(MyEnum2.class));
130            frame.add(combo2);
131            
132            EnumComboBoxModel<MyEnum1> enumModel = new EnumComboBoxModel<MyEnum1>(MyEnum1.class);
133            JComboBox combo3 = new JComboBox();
134            combo3.setModel(enumModel);
135            frame.add(combo3);
136            
137            MyEnum1 selected = enumModel.getSelectedItem();
138            
139            //uncomment to see the ClassCastException
140    //        enumModel.setSelectedItem("Die clown");
141            
142            frame.pack();
143            frame.setVisible(true);
144        }
145        
146        private enum MyEnum1 {GoodStuff, BadStuff};
147        private enum MyEnum2 {GoodStuff, BadStuff;
148        public String toString() {
149            switch(this) {
150                case GoodStuff: return "Some Good Stuff";
151                case BadStuff: return "Some Bad Stuff";
152            }
153            return "ERROR";
154        }
155        };
156        */
157    
158    }