001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.extensions.markup.html.form.palette.component;
018
019import java.util.Iterator;
020import java.util.Map;
021
022import org.apache.wicket.extensions.markup.html.form.palette.Palette;
023import org.apache.wicket.markup.ComponentTag;
024import org.apache.wicket.markup.MarkupStream;
025import org.apache.wicket.markup.head.IHeaderResponse;
026import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
027import org.apache.wicket.markup.html.form.FormComponent;
028import org.apache.wicket.markup.html.form.IChoiceRenderer;
029import org.apache.wicket.util.convert.IConverter;
030import org.apache.wicket.util.string.Strings;
031import org.apache.wicket.util.value.IValueMap;
032
033
034/**
035 * Generates html option elements based on iterator specified by getOptionsIterator() and
036 * IChoiceRender specified by the palette
037 * 
038 * @param <T>
039 * @author Igor Vaynberg ( ivaynberg )
040 */
041public abstract class AbstractOptions<T> extends FormComponent<T>
042{
043        private static final long serialVersionUID = 1L;
044
045        private final Palette<T> palette;
046
047        protected Palette<T> getPalette()
048        {
049                return palette;
050        }
051
052        /**
053         * @param id
054         *            component id
055         * @param palette
056         *            parent palette
057         */
058        public AbstractOptions(final String id, final Palette<T> palette)
059        {
060                super(id);
061                this.palette = palette;
062                setOutputMarkupId(true);
063        }
064
065        protected abstract Iterator<T> getOptionsIterator();
066
067        /**
068         * {@inheritDoc}
069         */
070        @Override
071        public void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag)
072        {
073                StringBuilder buffer = new StringBuilder(128);
074                Iterator<T> options = getOptionsIterator();
075                IChoiceRenderer<? super T> renderer = getPalette().getChoiceRenderer();
076
077                boolean localizeDisplayValues = localizeDisplayValues();
078
079                while (options.hasNext())
080                {
081                        final T choice = options.next();
082
083                        final CharSequence id;
084                        {
085                                String value = renderer.getIdValue(choice, 0);
086
087                                if (getEscapeModelStrings())
088                                {
089                                        id = Strings.escapeMarkup(value);
090                                }
091                                else
092                                {
093                                        id = value;
094                                }
095                        }
096
097                        final CharSequence value;
098                        {
099                                Object displayValue = renderer.getDisplayValue(choice);
100                                Class<?> displayClass = displayValue == null ? null : displayValue.getClass();
101
102                                @SuppressWarnings("unchecked")
103                                IConverter<Object> converter = (IConverter<Object>)getConverter(displayClass);
104                                String displayString = converter.convertToString(displayValue, getLocale());
105                                if (localizeDisplayValues)
106                                {
107                                        displayString = getLocalizer().getString(displayString, this, displayString);
108                                }
109
110                                if (getEscapeModelStrings())
111                                {
112                                        value = Strings.escapeMarkup(displayString);
113                                }
114                                else
115                                {
116                                        value = displayString;
117                                }
118                        }
119
120                        buffer.append("\n<option value=\"").append(id).append("\"");
121
122                        Map<String, String> additionalAttributesMap = getAdditionalAttributes(choice);
123                        if (additionalAttributesMap != null)
124                        {
125                                for (Map.Entry<String, String> entry : additionalAttributesMap.entrySet())
126                                {
127                                        buffer.append(' ')
128                                                .append(entry.getKey())
129                                                .append("=\"")
130                                                .append(entry.getValue())
131                                                .append("\"");
132                                }
133                        }
134
135                        buffer.append(">").append(value).append("</option>");
136                }
137
138                buffer.append("\n");
139
140                replaceComponentTagBody(markupStream, openTag, buffer);
141        }
142
143        /**
144         * Should display values be localized.
145         * 
146         * @return default {@code true}
147         */
148        protected boolean localizeDisplayValues()
149        {
150                return true;
151        }
152
153        /**
154         * @param choice
155         * @return map of attribute/value pairs (String/String)
156         */
157        protected Map<String, String> getAdditionalAttributes(final T choice)
158        {
159                return null;
160        }
161
162        /**
163         * {@inheritDoc}
164         */
165        @Override
166        protected void onComponentTag(final ComponentTag tag)
167        {
168                checkComponentTag(tag, "select");
169
170                super.onComponentTag(tag);
171                IValueMap attrs = tag.getAttributes();
172
173                attrs.put("multiple", "multiple");
174                attrs.put("size", getPalette().getRows());
175
176                if (!palette.isPaletteEnabled())
177                {
178                        attrs.put("disabled", "disabled");
179                }
180        }
181
182        @Override
183        public void renderHead(IHeaderResponse response)
184        {
185                super.renderHead(response);
186
187                // A piece of javascript to avoid serializing the options during AJAX serialization.
188                response.render(OnDomReadyHeaderItem.forScript(
189                        "if (typeof(Wicket) != \"undefined\" && typeof(Wicket.Form) != \"undefined\")"
190                                + "    Wicket.Form.excludeFromAjaxSerialization." + getMarkupId() + "='true';"));
191        }
192        
193        /**
194         * {@inheritDoc}
195         */
196        @Override
197        public void updateModel()
198        {
199        }
200
201        /**
202         * {@inheritDoc}
203         */
204        @Override
205        protected String getModelValue()
206        {
207                return null;
208        }
209}