001    /*
002     * Created on Dec 23, 2003
003    */
004    package net.sf.jolene.dom;
005    
006    import net.sf.jolene.constants.Prefs;
007    import net.sf.jolene.constants.Tags;
008    
009    import java.util.*;
010    
011    /**
012     * A Select in an html document.
013     *
014     * @author Dan Howard
015     */
016    
017    public final class Select extends HTMLElement {
018    
019        private boolean multiple;
020    
021        // Not public because we don't want the user to access the arraylist directly.
022        // The only way to add a new option is to use the addOption method.
023        List<Option> options = new ArrayList<Option>(3);
024    
025        /**
026         * Default constructor.
027         */
028        public Select() {
029            tag = Tags.select;
030            multiple = false;
031        }
032    
033    
034        /**
035         * Construct a select with the specified name.
036         *
037         * @param name name of the select.
038         */
039        public Select(String name) {
040            this();
041            setName(name);
042        }
043    
044        /**
045         * This method adds a new option to the available options for the select object.
046         *
047         * @param option An option object to add to the select list
048         * @return int - the new size of the option list.
049         */
050        public int addOption(Option option) {
051            int index = -1;
052            //option.parent = this;
053    
054            StringTokenizer st = new StringTokenizer(getValue(), Prefs.SelectValueSeperator.getValue());
055            String itemValue;
056            while (st.hasMoreTokens()) {
057                itemValue = st.nextToken();
058                if (itemValue.equals(option.getValue())) {
059                    option.setSelected(true);
060                }
061            }
062    
063            options.add(option);
064            index = options.size();
065            return index;
066        }
067    
068        /**
069         * Clears the list of options on the select.
070         */
071        public void clearOptions() {
072            options.clear();
073        }
074    
075    
076        /**
077         * Returns a clone of the select object.
078         *
079         * @return Select object.
080         */
081        @Override
082        public Select clone() {
083            Select select = (Select) super.clone();
084    
085            for (int j = 0; j < options.size(); j++) {
086                select.addOption(new Option(options.get(j).getValue(), options.get(j).getText()));
087            }
088            return select;
089        }
090    
091        /**
092         * Returns the specified option object by the numeric index.
093         *
094         * @param index the index of the option to retrive
095         * @return Option object.
096         */
097        public Option options(int index) {
098            return options.get(index);
099        }
100    
101        /**
102         * Gets the value of the select object.
103         *
104         * @return value of the select object.
105         */
106        @Override
107        public String getValue() {
108            String selectValue = super.getValue();
109    
110            // Ensure that exisiting options are flagged properly.
111            setValue(selectValue);
112    
113            String value = "";
114    
115            // Loop through the options and add the values of the 'selected' options
116            // to the value string + commas...
117            String sep = Prefs.SelectValueSeperator.getValue();
118            for (int j = 0; j < options.size(); j++) {
119                Option option = options.get(j);
120    
121                if (option.isSelected()) {
122                    value += option.getValue() + sep;
123                }
124            }
125    
126            // Strip last comma
127            int n = value.lastIndexOf(",");
128            if (n > -1) {
129                value = value.substring(0, n);
130            }
131    
132            if (value.trim().length() == 0 && selectValue.trim().length() > 0) {
133                // If there was no value found in the options list but the user
134                // had set a value in the select object itself then return that
135                // value but log a warning.
136                value = selectValue;
137                log.warn("Returning Select object " + getName() + " assigned value: " + value + " which does not exist in the options list.");
138            }
139            return value;
140        }
141    
142        /**
143         * Indicates if the select is a multiple select.
144         *
145         * @return mulitple
146         */
147        public boolean isMultiple() {
148            return multiple;
149        }
150    
151        /**
152         * Set the name of the select object.
153         *
154         * @param name name of the select object.
155         */
156        @Override
157        public void setName(String name) {
158            super.setName(name);
159            setAttribute("name", name);
160        }
161    
162        /**
163         * Sets if this select is a multiple select.
164         *
165         * @param multiple boolean.
166         */
167        public void setMultiple(boolean multiple) {
168    
169            this.multiple = multiple;
170            if (multiple) {
171                setAttribute("multiple", "multiple");
172            } else {
173                removeAttribute("multiple");
174            }
175        }
176    
177        /**
178         * Sets the value for the select object. The value to  assign
179         * may be a single value or multiple values seperate by a comma.
180         *
181         * @param value String value to set.
182         */
183        @Override
184        public void setValue(String value) {
185            super.setValue(value);
186    
187            // locate the 1st option whose itemValue = value
188            // If multi-select value could be comma seperated?
189            for (int j = 0; j < options.size(); j++) {
190    
191                Option option = options.get(j);
192    
193                option.setSelected(false);
194    
195                StringTokenizer st = new StringTokenizer(value, Prefs.SelectValueSeperator.getValue());
196                while (st.hasMoreTokens()) {
197                    String itemValue = st.nextToken();
198                    String optionValue = option.getValue();
199    
200                    if (optionValue.equals(itemValue)) {
201                        option.setSelected(true);
202                        break;
203                    }
204                }
205            }
206    
207        }
208    
209        /**
210         * Sort the options on the select.
211         */
212        public void sortOptions() {
213            Collections.sort(options, new Comparator<Option>() {
214    
215                public int compare(Option o1, Option o2) {
216                    String s1 = o1.getText();
217                    String s2 = o2.getText();
218                    return s1.compareTo(s2);
219                }
220            });
221        }
222    
223    
224        /**
225         * Renders the select.
226         *
227         * @return The select as a html string.
228         */
229        @Override
230        public String toString() {
231    
232            if (swapWith != null) {
233                return swapWith.toString();
234            }
235    
236            if (!isRenderable() && !log.isDebugEnabled()) {
237                return "";
238            }
239    
240            // Used to ensure options are initialized properly.
241            getValue();
242    
243            StringBuilder sb = new StringBuilder(super.toString());
244            for (int j = 0; j < options.size(); j++) {
245                sb.append(options.get(j).toString());
246            }
247            String ls = System.getProperty("line.separator");
248            sb.append(ls);
249            sb.append("</").append(tag).append(">");
250            sb.append(ls);
251            return sb.toString();
252        }
253    }