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;
017
018import java.util.ArrayList;
019import java.util.List;
020
021import com.github.gwtbootstrap.client.ui.base.DivWidget;
022import com.github.gwtbootstrap.client.ui.resources.Bootstrap;
023import com.google.gwt.core.client.GWT;
024import com.google.gwt.core.client.Scheduler;
025import com.google.gwt.core.client.Scheduler.ScheduledCommand;
026import com.google.gwt.dom.client.Element;
027import com.google.gwt.dom.client.NativeEvent;
028import com.google.gwt.event.dom.client.DomEvent;
029import com.google.gwt.event.shared.EventHandler;
030import com.google.gwt.event.shared.HandlerRegistration;
031import com.google.gwt.user.client.Event;
032import com.google.gwt.user.client.ui.IsWidget;
033import com.google.gwt.user.client.ui.Widget;
034
035//@formatter:off
036/**
037 * The container for a tabbable nav.
038 * 
039 * @since 2.0.4.0
040 * @author Dominik Mayer
041 * @author ohashi keisuke
042 */
043//@formatter:on
044public class TabPanel extends DivWidget {
045
046    public static class ShowEvent extends DomEvent<ShowEvent.Handler> {
047        private static final Type<ShowEvent.Handler> TYPE = new Type<ShowEvent.Handler>(
048                "show", new ShowEvent());
049
050        private TabLink target;
051        private TabLink relatedTarget;
052
053        protected ShowEvent() {
054        }
055
056        public ShowEvent(NativeEvent event) {
057            setNativeEvent(event);
058            if(Element.is(event.getRelatedEventTarget())) {
059                setRelativeElement(Element.as(event.getRelatedEventTarget()));
060            }
061        }
062
063        public interface Handler extends EventHandler {
064
065            void onShow(ShowEvent showEvent);
066        }
067
068        @Override
069        protected void dispatch(Handler handler) {
070            handler.onShow(this);
071        }
072
073        @Override
074        public com.google.gwt.event.dom.client.DomEvent.Type<ShowEvent.Handler> getAssociatedType() {
075            return TYPE;
076        }
077
078        /**
079         * Get target
080         * 
081         * @return target
082         */
083        public TabLink getTarget() {
084            return target;
085        }
086
087        /**
088         * Set target
089         * 
090         * @param target
091         *            target
092         */
093        public void setTarget(TabLink target) {
094            this.target = target;
095        }
096
097        /**
098         * Get relatedTarget�B
099         * 
100         * @return relatedTarget
101         */
102        public TabLink getRelatedTarget() {
103            return relatedTarget;
104        }
105
106        /**
107         * Set relatedTarget
108         * 
109         * @param relatedTarget
110         *            relatedTarget
111         */
112        public void setRelatedTarget(TabLink relatedTarget) {
113            this.relatedTarget = relatedTarget;
114        }
115    }
116
117    public static class ShownEvent extends DomEvent<ShownEvent.Handler> {
118        private static final Type<ShownEvent.Handler> TYPE = new Type<ShownEvent.Handler>(
119                "shown", new ShownEvent());
120
121        private TabLink target;
122        private TabLink relatedTarget;
123
124        protected ShownEvent() {
125        }
126
127        public ShownEvent(NativeEvent event) {
128            setNativeEvent(event);
129            if(Element.is(event.getRelatedEventTarget())) {
130                setRelativeElement(Element.as(event.getRelatedEventTarget()));
131            }
132        }
133
134        public interface Handler extends EventHandler {
135
136            void onShow(ShownEvent shownEvent);
137        }
138
139        @Override
140        protected void dispatch(Handler handler) {
141            handler.onShow(this);
142        }
143
144        @Override
145        public com.google.gwt.event.dom.client.DomEvent.Type<ShownEvent.Handler> getAssociatedType() {
146            return TYPE;
147        }
148
149        /**
150         * Get target
151         * 
152         * @return target
153         */
154        public TabLink getTarget() {
155            return target;
156        }
157
158        /**
159         * Set target
160         * 
161         * @param target
162         *            target
163         */
164        public void setTarget(TabLink target) {
165            this.target = target;
166        }
167
168        /**
169         * Get relatedTarget�B
170         * 
171         * @return relatedTarget
172         */
173        public TabLink getRelatedTarget() {
174            return relatedTarget;
175        }
176
177        /**
178         * Set relatedTarget
179         * 
180         * @param relatedTarget
181         *            relatedTarget
182         */
183        public void setRelatedTarget(TabLink relatedTarget) {
184            this.relatedTarget = relatedTarget;
185        }
186    }
187
188    private static class TabContent extends DivWidget {
189
190        public TabContent() {
191            setStyleName(Bootstrap.tab_content);
192        }
193    }
194
195    private NavTabs tabs = new NavTabs();
196
197    private List<TabLink> tabLinkList = new ArrayList<TabLink>();
198
199    private TabContent tabContent = new TabContent();
200
201    /**
202     * Create an empty {@link Bootstrap.Tabs#ABOVE} style TabPanel.
203     */
204    public TabPanel() {
205        this(Bootstrap.Tabs.ABOVE);
206    }
207
208    /**
209     * Create an empty TabPanel.
210     * @param position tab position.
211     */
212    public TabPanel(Bootstrap.Tabs position) {
213        setStyle(position);
214        if(Bootstrap.Tabs.BELOW == position) {
215            //tabs should be added after content to display it below content in this case
216            super.add(tabContent);
217            super.add(tabs);
218        } else {
219            super.add(tabs);
220            super.add(tabContent);
221        }
222
223        setHandlerFunctions(getElement());
224    }
225
226    /**
227     * Set tab position
228     * @param position tab position.
229     */
230    public void setTabPosition(String position) {
231        if (tabs.getParent() != null) {
232            remove(tabs);
233            remove(tabContent);
234        }
235
236        if (position.equalsIgnoreCase("below")) {
237            //tabs should be added after content to display it below content in this case
238            setStyle(Bootstrap.Tabs.BELOW);
239            super.add(tabContent);
240            super.add(tabs);
241        } else if (position.equalsIgnoreCase("left")) {
242            setStyle(Bootstrap.Tabs.LEFT);
243            super.add(tabs);
244            super.add(tabContent);
245        } else if (position.equalsIgnoreCase("right")) {
246            setStyle(Bootstrap.Tabs.RIGHT);
247            super.add(tabs);
248            super.add(tabContent);
249        } else {
250            setStyle(Bootstrap.Tabs.ABOVE);
251            super.add(tabs);
252            super.add(tabContent);
253        }
254    }
255
256    @Override
257    public void add(Widget child) {
258
259        if (child instanceof TabPane) {
260            add((TabPane) child);
261            return;
262        }
263
264        if (child instanceof TabLink) {
265            add((TabLink) child);
266            return;
267        }
268
269        if (child instanceof DropdownTab) {
270            add((DropdownTab) child);
271            return;
272        }
273
274        if (GWT.isProdMode()) {
275            throw new IllegalArgumentException(
276                    "TabPanel can add only TabPane or TabLink or Tab or DorpdownTab. you added "
277                            + child);
278        }
279    }
280
281    private void add(DropdownTab dropdownTab) {
282
283        tabs.add(dropdownTab);
284
285        List<Tab> tabList = dropdownTab.getTabList();
286        for (Tab tab : tabList) {
287            tabLinkList.add(tab.asTabLink());
288            TabPane tabPane = tab.getTabPane();
289            tabContent.add(tabPane);
290        }
291    }
292
293    private void add(TabPane child) {
294
295        if (child.isCreateTabLink()) {
296            TabLink tabLink = new TabLink(child);
297            tabs.add(tabLink);
298            tabLinkList.add(tabLink);
299        }
300        tabContent.add(child);
301    }
302
303    private void add(final TabLink child) {
304
305        if (child.isCreateTabPane() && child.getTabPane() == null) {
306            TabPane pane = new TabPane(child.getText());
307            child.setTablePane(pane);
308            tabContent.add(pane);
309        } else if (child.getTabPane() != null) {
310            tabContent.add(child.getTabPane());
311        }
312        tabs.add(child);
313        tabLinkList.add(child);
314    }
315
316    @Override
317    public void clear() {
318        tabContent.clear();
319        tabs.clear();
320        tabLinkList.clear();
321    }
322
323    /**
324     * Remove tab or tabpane.
325     * <p>
326     * If Tablink has TabPane,romve TabPane with TabLink. </pre> {@inheritDoc}
327     */
328    @Override
329    public boolean remove(int index) {
330        Widget widget = tabs.getWidget(index);
331
332        if (widget instanceof TabLink) {
333            TabLink link = (TabLink) widget;
334            if (link.getTabPane() != null) {
335                link.getTabPane().removeFromParent();
336            }
337            tabLinkList.remove(link);
338            return tabs.remove(index);
339        } else if (widget instanceof DropdownTab) {
340
341            DropdownTab dropdownTab = (DropdownTab) widget;
342
343            List<Tab> tabList = dropdownTab.getTabList();
344
345            for (Tab tab : tabList) {
346                tabLinkList.remove(tab.asTabLink());
347                if (tab.getTabPane() != null) {
348                    tab.getTabPane().removeFromParent();
349                }
350            }
351            return tabs.remove(dropdownTab);
352        } else if (widget instanceof TabPane) {
353
354            return tabContent.remove(widget);
355        }
356
357        return super.remove(widget);
358    }
359
360    /**
361     * remove TabLink or TabPane.
362     * <p>
363     * </p>
364     * {@inheritDoc}
365     */
366    @Override
367    public boolean remove(Widget w) {
368
369        if (w instanceof TabLink) {
370            TabLink link = (TabLink) w;
371            tabLinkList.remove(link);
372            if (link.getTabPane() != null) {
373                link.getTabPane().removeFromParent();
374            }
375            return tabs.remove(w);
376        } else if (w instanceof DropdownTab) {
377            DropdownTab dropdownTab = (DropdownTab) w;
378
379            List<Tab> tabList = dropdownTab.getTabList();
380
381            for (Tab tab : tabList) {
382
383                tabLinkList.remove(tab.asTabLink());
384                if (tab.getTabPane() != null) {
385                    tab.getTabPane().removeFromParent();
386                }
387            }
388
389            return tabs.remove(dropdownTab);
390
391        } else if (w instanceof TabPane) {
392            return tabContent.remove(w);
393        }
394
395        return super.remove(w);
396    }
397
398    /**
399     * {@inheritDoc}
400     */
401    @Override
402    public boolean remove(IsWidget child) {
403
404        if (child instanceof Tab) {
405            Tab tab = (Tab) child;
406
407            TabLink link = tab.asTabLink();
408
409            if (link.getTabPane() != null) {
410                link.getTabPane().removeFromParent();
411            }
412            tabLinkList.remove(link);
413            return tabs.remove(link);
414        } else if (child instanceof DropdownTab) {
415            DropdownTab tab = (DropdownTab) child;
416
417            List<Tab> tabList = tab.getTabList();
418
419            for (Tab tab2 : tabList) {
420                tabLinkList.remove(tab2.asTabLink());
421                if (tab2.getTabPane() != null) {
422                    tabContent.remove(tab2.getTabPane());
423                }
424            }
425            return super.remove(child);
426        }
427
428        return super.remove(child);
429    }
430
431    /**
432     * Activate tab by index.
433     * @param index tab index.
434     */
435    public void selectTab(int index) {
436        tabLinkList.get(index).show();
437    }
438
439    /**
440     * Get Current selected tab index.
441     * <p>
442     * if not found, return <code>-1.</code>
443     * </p>
444     * 
445     * @return tab index.
446     */
447    public int getSelectedTab() {
448
449        for (int i = 0; i < tabLinkList.size(); i++) {
450            if (tabLinkList.get(i).isActive()) {
451                return i;
452            }
453        }
454        return -1;
455    }
456
457    private void setHandlerFunctions(final TabLink e) {
458        if (isOrWasAttached()) {
459            setHandlerFunctions(e.getAnchor().getElement());
460            return;
461        }
462
463        Scheduler.get().scheduleDeferred(new ScheduledCommand() {
464
465            @Override
466            public void execute() {
467                setHandlerFunctions(e.getAnchor().getElement());
468            }
469        });
470
471    }
472
473    protected void onShow(Event e, Element target, Element relatedTarget) {
474        ShowEvent event = new ShowEvent(e);
475        event.setTarget(findTabLink(target));
476        event.setRelatedTarget(findTabLink(relatedTarget));
477        fireEvent(event);
478    }
479
480    protected void onShown(Event e, Element target, Element relatedTarget) {
481        ShownEvent event = new ShownEvent(e);
482        event.setTarget(findTabLink(target));
483        event.setRelatedTarget(findTabLink(relatedTarget));
484        fireEvent(event);
485    }
486
487    public HandlerRegistration addShowHandler(ShowEvent.Handler handler) {
488        return addHandler(handler, ShowEvent.TYPE);
489    }
490
491    public HandlerRegistration addShownHandler(ShownEvent.Handler handler) {
492        return addHandler(handler, ShownEvent.TYPE);
493    }
494
495    private TabLink findTabLink(Element e) {
496        for (TabLink tabLink : tabLinkList)
497            if (tabLink.getAnchor().getElement().equals(e))
498                return tabLink;
499
500        return null;
501    }
502
503    //@formatter:off
504    private native void setHandlerFunctions(Element e) /*-{
505        var that = this;
506        var $this = $wnd.jQuery(e);
507    
508        $this.off('show');
509        $this.off('shown');
510    
511        $this.on('show', function(e) {
512            [email protected]::onShow(Lcom/google/gwt/user/client/Event;Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/dom/client/Element;)(e, e.target, e.relatedTarget);
513        });
514        $this.on('shown', function(e) {
515            [email protected]::onShown(Lcom/google/gwt/user/client/Event;Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/dom/client/Element;)(e, e.target, e.relatedTarget);
516        });
517    }-*/;
518    //@formatter:on
519
520}