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.ChangeEvent;
025import com.google.gwt.event.dom.client.ChangeHandler;
026import com.google.gwt.event.dom.client.ClickEvent;
027import com.google.gwt.event.dom.client.ClickHandler;
028import com.google.gwt.event.dom.client.DomEvent;
029import com.google.gwt.event.dom.client.HasChangeHandlers;
030import com.google.gwt.event.dom.client.HasClickHandlers;
031import com.google.gwt.event.shared.HandlerRegistration;
032import com.google.gwt.uibinder.client.UiChild;
033import com.google.gwt.user.client.ui.HasText;
034import com.google.gwt.user.client.ui.HasWidgets;
035import com.google.gwt.user.client.ui.Widget;
036
037//@formatter:off
038
039/**
040 * Base class for dropdown widgets.
041 *
042 * @author Carlos A Becker
043 * @author Dominik Mayer
044 * @since 2.0.4.0
045 */
046//@formatter:on
047public abstract class DropdownBase extends ComplexWidget implements HasChangeHandlers, HasClickHandlers, HasWidgets, HasText ,HasIcon {
048
049        private UnorderedList menu = new UnorderedList();
050        
051        protected IconAnchor trigger;
052
053        private NavLink link;
054
055        private NavLinkClickHandler handler = new NavLinkClickHandler();
056
057    private boolean dropup;
058
059        /**
060         * Creates a new widget of the given type.
061         * 
062         * @param type
063         *            the HTML tag to be used for the widget
064         */
065        public DropdownBase(String type) {
066                super(type);
067                createAndAddTrigger();
068                menu.setStyleName("dropdown-menu");
069                super.add(menu);
070        }
071
072        private void createAndAddTrigger() {
073                trigger = createTrigger();
074                trigger.addStyleName("dropdown-toggle");
075                trigger.getElement().setAttribute(Constants.DATA_TOGGLE, "dropdown");
076                super.add(trigger);
077        }
078
079        /**
080         * Sets the text of the dropdown trigger.
081         * 
082         * @param text
083         */
084        public void setText(String text) {
085                trigger.setText(text);
086        }
087
088        /**
089         * @return the text of the dropdown trigger.
090         */
091        public String getText() {
092                return trigger.getText();
093        }
094        
095    /**
096     * Get trigger wiget
097     * @return trigger wiget
098     */
099    public IconAnchor getTriggerWidget() {
100        return trigger;
101    }
102
103    
104    /**
105     * Get menu unordered list widget
106     * @return menu
107     */
108    public UnorderedList getMenuWiget() {
109        return menu;
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
123         *            true:Set Dropup false:Un-set Dropup
124         */
125        public void setDropup(boolean dropup) {
126            
127            this.dropup = dropup;
128            
129                if (dropup)
130                        addStyleName(Constants.DROPUP);
131                else
132                        removeStyleName(Constants.DROPUP);
133        }
134        
135        /**
136         * Is widget dropup?
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
158         *            the widget that will be added to the menu
159         * @see #addWidget(Widget)
160         */
161        @Override
162        public void add(Widget widget) {
163                menu.add(widget);
164                if (widget instanceof NavLink) {
165                        ((NavLink) widget).addClickHandler(handler);
166                }
167        }
168
169        @Override
170        public HandlerRegistration addChangeHandler(ChangeHandler handler) {
171                return addDomHandler(handler, ChangeEvent.getType());
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
182         *            the widget to be added.
183         */
184        protected void addWidget(Widget widget) {
185                super.add(widget);
186        }
187        
188        private native void configure(Element e) /*-{
189                $wnd.jQuery(e).dropdown();
190        }-*/;
191
192        /**
193         * Pull the dropdown menu to right
194         * 
195         * @param rightDropdown
196         *            <code>true</code> pull to right, otherwise to left. Default is
197         *            <code>false</code>
198         */
199        public void setRightDropdown(boolean rightDropdown) {
200        menu.setStyleName(Alignment.RIGHT.get(), rightDropdown);
201        }
202
203        private class NavLinkClickHandler implements ClickHandler {
204
205                @Override
206                public void onClick(ClickEvent event) {
207                        try {
208                                IconAnchor iconAnchor = (IconAnchor) event.getSource();
209                                link = (NavLink) iconAnchor.getParent();
210                        } catch (Exception e) {
211                                GWT.log(e.getMessage() , e);
212                        }
213                        DomEvent.fireNativeEvent(Document.get().createChangeEvent(), DropdownBase.this);
214                }
215
216        }
217
218        /**
219         * Method to get the {@link NavLink} that has been clicked most recently.
220         * 
221         * @return Last clicked NavLink or <code>null</code> if none have been
222         *         clicked.
223         */
224        public NavLink getLastSelectedNavLink() {
225                return link;
226        }
227
228        @Override
229        public void clear() {
230                menu.clear();
231        }
232
233        @Override
234        public HandlerRegistration addClickHandler(ClickHandler handler) {
235                return trigger.addClickHandler(handler);
236        }
237        
238        /**
239         * Add widget to trigger anchodr
240         * @param w added widget
241         */
242        @UiChild(tagname="customTrigger" , limit=1)
243        public void addCustomTrigger(Widget w) {
244            trigger.insert(w , 0);
245        }
246        
247}