001/*
002 *  Copyright 2012 GWT-Bootstrap
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.github.gwtbootstrap.client.ui.base;
017
018import com.github.gwtbootstrap.client.ui.NavLink;
019import com.github.gwtbootstrap.client.ui.constants.Alignment;
020import com.github.gwtbootstrap.client.ui.constants.Constants;
021import com.google.gwt.core.client.GWT;
022import com.google.gwt.dom.client.Document;
023import com.google.gwt.dom.client.Element;
024import com.google.gwt.event.dom.client.*;
025import com.google.gwt.event.shared.HandlerRegistration;
026import com.google.gwt.uibinder.client.UiChild;
027import com.google.gwt.user.client.ui.HasText;
028import com.google.gwt.user.client.ui.HasWidgets;
029import com.google.gwt.user.client.ui.Widget;
030
031//@formatter:off
032
033/**
034 * Base class for dropdown widgets.
035 *
036 * @author Carlos A Becker
037 * @author Dominik Mayer
038 *
039 * @since 2.0.4.0
040 */
041//@formatter:on
042public abstract class DropdownBase extends ComplexWidget implements HasChangeHandlers, HasClickHandlers, HasWidgets, HasText, HasIcon {
043
044    private UnorderedList menu = new UnorderedList();
045
046    protected IconAnchor trigger;
047
048    private NavLink link;
049
050    private NavLinkClickHandler handler = new NavLinkClickHandler();
051
052    private boolean dropup;
053
054    /**
055     * Creates a new widget of the given type.
056     *
057     * @param type the HTML tag to be used for the widget
058     */
059    public DropdownBase(String type) {
060        super(type);
061        createAndAddTrigger();
062        menu.setStyleName("dropdown-menu");
063        super.add(menu);
064    }
065
066    private void createAndAddTrigger() {
067        trigger = createTrigger();
068        // Prevents exception when the impl class does not have a trigger.
069        if (trigger != null) {
070            trigger.addStyleName("dropdown-toggle");
071            trigger.getElement().setAttribute(Constants.DATA_TOGGLE, "dropdown");
072            super.add(trigger);
073        }
074    }
075
076    /**
077     * Sets the text of the dropdown trigger.
078     *
079     * @param text
080     */
081    public void setText(String text) {
082        trigger.setText(text);
083    }
084
085    /**
086     * @return the text of the dropdown trigger.
087     */
088    public String getText() {
089        return trigger.getText();
090    }
091
092    /**
093     * Get trigger wiget
094     *
095     * @return trigger wiget
096     */
097    public IconAnchor getTriggerWidget() {
098        return trigger;
099    }
100
101
102    /**
103     * Get menu unordered list widget
104     *
105     * @return menu
106     */
107    public UnorderedList getMenuWiget() {
108        return menu;
109    }
110
111    /**
112     * Implement this method to create the trigger appropriate for your widget.
113     * It has to be an {@link IconAnchor} or a subtype.
114     *
115     * @return the created trigger
116     */
117    protected abstract IconAnchor createTrigger();
118
119    /**
120     * Set dropup style.
121     *
122     * @param dropup true:Set Dropup false:Un-set Dropup
123     */
124    public void setDropup(boolean dropup) {
125
126        this.dropup = dropup;
127
128        if (dropup)
129            addStyleName(Constants.DROPUP);
130        else
131            removeStyleName(Constants.DROPUP);
132    }
133
134    /**
135     * Is widget dropup?
136     *
137     * @return true:Dropup false:Dropdown
138     */
139    public boolean isDropup() {
140        return this.dropup;
141    }
142
143    /**
144     * {@inheritDoc}
145     */
146    @Override
147    protected void onLoad() {
148        super.onLoad();
149        if (trigger != null) {
150            configure(trigger.getElement());
151        }
152    }
153
154    /**
155     * Adds a widget to the dropdown menu.
156     *
157     * @param widget the widget that will be added to the menu
158     * @see #addWidget(Widget)
159     */
160    @Override
161    public void add(Widget widget) {
162        menu.add(widget);
163        if (widget instanceof NavLink) {
164            ((NavLink) widget).addClickHandler(handler);
165        }
166    }
167
168    @Override
169    public HandlerRegistration addChangeHandler(ChangeHandler handler) {
170        return addDomHandler(handler, ChangeEvent.getType());
171    }
172
173    /**
174     * Adds a widget to the the dropdown widget, <b>not</b> to the dropdown
175     * menu.
176     * <p/>
177     * <p/>
178     * Use {@link #add(Widget)} if you want to add a widget to the dropdown
179     * menu.
180     *
181     * @param widget the widget to be added.
182     */
183    protected void addWidget(Widget widget) {
184        super.add(widget);
185    }
186
187    private native void configure(Element e) /*-{
188        $wnd.jQuery(e).dropdown();
189    }-*/;
190
191    /**
192     * Pull the dropdown menu to right
193     *
194     * @param rightDropdown <code>true</code> pull to right, otherwise to left. Default is
195     *                      <code>false</code>
196     */
197    public void setRightDropdown(boolean rightDropdown) {
198        menu.setStyleName(Alignment.RIGHT.get(), rightDropdown);
199    }
200
201    private class NavLinkClickHandler implements ClickHandler {
202
203        @Override
204        public void onClick(ClickEvent event) {
205            try {
206                IconAnchor iconAnchor = (IconAnchor) event.getSource();
207                link = (NavLink) iconAnchor.getParent();
208            } catch (Exception e) {
209                GWT.log(e.getMessage(), e);
210            }
211            DomEvent.fireNativeEvent(Document.get().createChangeEvent(), DropdownBase.this);
212        }
213
214    }
215
216    /**
217     * Method to get the {@link NavLink} that has been clicked most recently.
218     *
219     * @return Last clicked NavLink or <code>null</code> if none have been
220     *         clicked.
221     */
222    public NavLink getLastSelectedNavLink() {
223        return link;
224    }
225
226    @Override
227    public void clear() {
228        menu.clear();
229    }
230
231    @Override
232    public HandlerRegistration addClickHandler(ClickHandler handler) {
233        return trigger.addClickHandler(handler);
234    }
235
236    /**
237     * Add widget to trigger anchodr
238     *
239     * @param w added widget
240     */
241    @UiChild(tagname = "customTrigger", limit = 1)
242    public void addCustomTrigger(Widget w) {
243        trigger.insert(w, 0);
244    }
245
246}