001package org.gwtbootstrap3.extras.select.client.ui;
002
003/*
004 * #%L
005 * GwtBootstrap3
006 * %%
007 * Copyright (C) 2013 - 2016 GwtBootstrap3
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import static org.gwtbootstrap3.extras.select.client.ui.SelectOptions.ICON;
024import static org.gwtbootstrap3.extras.select.client.ui.SelectOptions.MAX_OPTIONS;
025import static org.gwtbootstrap3.extras.select.client.ui.SelectOptions.SUBTEXT;
026
027import java.util.HashMap;
028import java.util.Map;
029
030import org.gwtbootstrap3.client.ui.base.ComplexWidget;
031import org.gwtbootstrap3.client.ui.base.mixin.AttributeMixin;
032import org.gwtbootstrap3.client.ui.base.mixin.EnabledMixin;
033import org.gwtbootstrap3.client.ui.constants.IconType;
034
035import com.google.gwt.dom.client.Document;
036import com.google.gwt.dom.client.OptionElement;
037import com.google.gwt.user.client.ui.HasEnabled;
038import com.google.gwt.user.client.ui.Widget;
039
040/**
041 * Select option group widget.
042 *
043 * @author Xiaodong Sun
044 */
045public class OptGroup extends ComplexWidget implements HasEnabled {
046
047    private final Map<OptionElement, Option> itemMap = new HashMap<>(0);
048    private final AttributeMixin<OptGroup> attrMixin = new AttributeMixin<>(this);
049    private final EnabledMixin<OptGroup> enabledMixin = new EnabledMixin<>(this);
050
051    private static final String LABEL = "label";
052
053    public OptGroup() {
054        setElement(Document.get().createOptGroupElement());
055    }
056
057    /**
058     * Set the label of the option group.
059     *
060     * @param label
061     */
062    public void setLabel(final String label) {
063        if (label != null)
064            attrMixin.setAttribute(LABEL, label);
065        else
066            attrMixin.removeAttribute(LABEL);
067    }
068
069    /**
070     * Returns the label of the option group; may be <code>null</code>.
071     *
072     * @return the label of the option group
073     */
074    public String getLabel() {
075        String label = attrMixin.getAttribute(LABEL);
076        return label.isEmpty() ? null : label;
077    }
078
079    @Override
080    public boolean isEnabled() {
081        return enabledMixin.isEnabled();
082    }
083
084    @Override
085    public void setEnabled(final boolean enabled) {
086        enabledMixin.setEnabled(enabled);
087    }
088
089    /**
090     * Set the specified sub-text to the option.
091     *
092     * @param subtext
093     */
094    public void setSubtext(final String subtext) {
095        if (subtext != null)
096            attrMixin.setAttribute(SUBTEXT, subtext);
097        else
098            attrMixin.removeAttribute(SUBTEXT);
099    }
100
101    /**
102     * Returns the sub-text of the option.
103     *
104     * @return
105     */
106    public String getSubtext() {
107        String subtext = attrMixin.getAttribute(SUBTEXT);
108        return subtext.isEmpty() ? null : subtext;
109    }
110
111    /**
112     * Add an icon to the option.
113     *
114     * @param iconType
115     */
116    public void setIcon(final IconType iconType) {
117        if (iconType != null)
118            attrMixin.setAttribute(ICON, iconType.getCssName());
119        else
120            attrMixin.removeAttribute(ICON);
121    }
122
123    /**
124     * Returns the icon of the option; may be <code>null</code>.
125     *
126     * @return
127     */
128    public IconType getIcon() {
129        return IconType.fromStyleName(attrMixin.getAttribute(ICON));
130    }
131
132    /**
133     * When set to a positive value and in a multi-select, the
134     * number of selected options cannot exceed the given value.
135     * When set to a strict negative value (less than zero), this
136     * options will be deactivated.
137     *
138     * @param maxOptions
139     */
140    public void setMaxOptions(final int maxOptions) {
141        attrMixin.setAttribute(MAX_OPTIONS, Integer.toString(maxOptions));
142    }
143
144    @Override
145    public void add(Widget child) {
146        super.add(child);
147        updateItemMap(child, true);
148    }
149
150    @Override
151    public void insert(Widget child, int beforeIndex) {
152        super.insert(child, beforeIndex);
153        updateItemMap(child, true);
154    }
155
156    @Override
157    public boolean remove(Widget w) {
158        boolean removed = super.remove(w);
159        if (removed) {
160            updateItemMap(w, false);
161        }
162        return removed;
163    }
164
165    private void updateItemMap(Widget widget, boolean toAdd) {
166
167        // Not option element ==> ignore it
168        if (!(widget instanceof Option))
169            return;
170
171        // Update item map
172        Option option = (Option) widget;
173        if (toAdd) {
174            itemMap.put(option.getSelectElement(), option);
175        } else {
176            itemMap.remove(option.getSelectElement());
177        }
178
179        // Update select item map
180        Widget parent = getParent();
181        if (parent != null && parent instanceof SelectBase) {
182            SelectBase<?> select = (SelectBase<?>) parent;
183            select.updateItemMap(option, toAdd);
184        }
185    }
186
187    Map<OptionElement, Option> getItemMap() {
188        return itemMap;
189    }
190}