Java tutorial
/* * Copyright 2014 cruxframework.org. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.cruxframework.crux.smartfaces.client.tab; import org.cruxframework.crux.core.client.event.SelectEvent; import org.cruxframework.crux.core.client.event.SelectHandler; import org.cruxframework.crux.smartfaces.client.backbone.common.FacesBackboneResourcesCommon; import org.cruxframework.crux.smartfaces.client.label.HTML; import org.cruxframework.crux.smartfaces.client.label.Label; import org.cruxframework.crux.smartfaces.client.panel.SelectablePanel; import org.cruxframework.crux.smartfaces.client.rollingpanel.RollingPanel; import com.google.gwt.aria.client.Roles; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.logical.shared.BeforeSelectionEvent; import com.google.gwt.event.logical.shared.BeforeSelectionHandler; import com.google.gwt.event.logical.shared.HasBeforeSelectionHandlers; import com.google.gwt.event.logical.shared.HasSelectionHandlers; import com.google.gwt.event.logical.shared.SelectionEvent; import com.google.gwt.event.logical.shared.SelectionHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HasWordWrap; import com.google.gwt.user.client.ui.UIObject; import com.google.gwt.user.client.ui.Widget; /** * Modified version of GWT TabBar that uses a RollingPanel wrapping its Tabs. * * @author Thiago da Rosa de Bustamante * @author Bruno Medeiros * * */ class TabBar extends Composite implements HasBeforeSelectionHandlers<Integer>, HasSelectionHandlers<Integer> { private static final String DEFAULT_STYLE_NAME = "faces-TabBar"; private static final String ITEM_STYLE_NAME = "faces-TabBar-item"; private static final String TAB_BAR_ITEM_SELECTED_STYLE_NAME = "faces-TabBar-item--selected"; private static final String FLAP_LABEL_STYLE_NAME = "faces-TabBar-flapLabel"; private RollingPanel panel; private Widget selectedTab; /** * Creates an empty tab bar. */ TabBar() { FacesBackboneResourcesCommon.INSTANCE.css().ensureInjected(); panel = new RollingPanel(); initWidget(panel); setStyleName(DEFAULT_STYLE_NAME); addStyleName(FacesBackboneResourcesCommon.INSTANCE.css().flexBoxHorizontalContainer()); panel.setScrollToAddedWidgets(true); // Add a11y role "tablist" Roles.getTablistRole().set(panel.getElement()); } @Override public HandlerRegistration addBeforeSelectionHandler(BeforeSelectionHandler<Integer> handler) { return addHandler(handler, BeforeSelectionEvent.getType()); } @Override public HandlerRegistration addSelectionHandler(SelectionHandler<Integer> handler) { return addHandler(handler, SelectionEvent.getType()); } /** * Gets the tab that is currently selected. * * @return the selected tab */ public int getSelectedTab() { if (selectedTab == null) { return -1; } return panel.getWidgetIndex(selectedTab); } /** * Gets the number of tabs present. * * @return the tab count */ public int getTabCount() { return panel.getWidgetCount(); } /** * Enable or disable a tab. When disabled, users cannot select the tab. * * @param index the index of the tab to enable or disable * @param enabled true to enable, false to disable */ public void setTabEnabled(int index, boolean enabled) { assert (index >= 0) && (index < getTabCount()) : "Flap index out of bounds"; // Style the wrapper ClickDelegatePanel delPanel = (ClickDelegatePanel) panel.getWidget(index); delPanel.setEnabled(enabled); if (enabled) { delPanel.removeStyleDependentName("disabled"); } else { delPanel.addStyleDependentName("disabled"); } } public void setTabWordWrap(int index, boolean wordWrap) { assert (index >= 0) && (index < getTabCount()) : "Flap index out of bounds"; // Style the wrapper ClickDelegatePanel delPanel = (ClickDelegatePanel) panel.getWidget(index); delPanel.setWordWrap(wordWrap); } /** * Inserts a new tab at the specified index. * * @param widget widget to be used in the new tab * @param beforeIndex the index before which this tab will be inserted */ public void insertTab(Widget widget, int beforeIndex) { insertTabWidget(widget, beforeIndex); } /** * Inserts a new tab at the specified index. * * @param text the new tab's text * @param beforeIndex the index before which this tab will be inserted */ public void insertTab(String text, int beforeIndex) { checkInsertBeforeTabIndex(beforeIndex); Label label = new Label(text); label.setWordWrap(false); label.setStyleName(FLAP_LABEL_STYLE_NAME); insertTabWidget(label, beforeIndex); } /** * * @param html * @param berforeIndex */ public void insertTab(SafeHtml html, int beforeIndex) { HTML label = new HTML(html); label.setWordWrap(false); label.setStyleName(FLAP_LABEL_STYLE_NAME); insertTabWidget(label, beforeIndex); } /** * Programmatically selects the specified tab. Use index -1 to specify that no tab should be selected. * * @param index the index of the tab to be selected * @return <code>true</code> if successful, <code>false</code> if the change is denied by the {@link BeforeSelectionHandler}. */ public boolean selectTab(int index) { checkTabIndex(index); BeforeSelectionEvent<?> event = BeforeSelectionEvent.fire(this, index); if (event != null && event.isCanceled()) { return false; } // Check for -1. setSelectionStyle(selectedTab, false); if (index == -1) { selectedTab = null; return true; } selectedTab = panel.getWidget(index); setSelectionStyle(selectedTab, true); panel.scrollToWidget(selectedTab); SelectionEvent.fire(this, index); return true; } /** * Inserts a new tab at the specified index. * * @param widget widget to be used in the new tab * @param beforeIndex the index before which this tab will be inserted */ protected void insertTabWidget(Widget widget, int beforeIndex) { checkInsertBeforeTabIndex(beforeIndex); ClickDelegatePanel delWidget = new ClickDelegatePanel(widget); delWidget.setStyleName(ITEM_STYLE_NAME); // Add a11y role "tab" SelectablePanel focusablePanel = delWidget.getFocusablePanel(); Roles.getTabRole().set(focusablePanel.getElement()); panel.insert(delWidget, beforeIndex); } /** * <b>Affected Elements:</b> * <ul> * <li>-tab# = The element containing the contents of the tab.</li> * <li>-tab-wrapper# = The cell containing the tab at the index.</li> * </ul> * * @see UIObject#onEnsureDebugId(String) */ @Override protected void onEnsureDebugId(String baseID) { super.onEnsureDebugId(baseID); int numTabs = getTabCount(); for (int i = 0; i < numTabs; i++) { ClickDelegatePanel delPanel = (ClickDelegatePanel) panel.getWidget(i); SelectablePanel focusablePanel = delPanel.getFocusablePanel(); ensureDebugId(focusablePanel.getElement(), baseID, "tab" + i); } } /** * Removes the tab at the specified index. * * @param index the index of the tab to be removed */ protected void removeTab(int index) { checkTabIndex(index); Widget toRemove = panel.getWidget(index); if (toRemove == selectedTab) { selectedTab = null; } panel.remove(toRemove); } private void checkInsertBeforeTabIndex(int beforeIndex) { if ((beforeIndex < 0) || (beforeIndex > getTabCount())) { throw new IndexOutOfBoundsException(); } } private void checkTabIndex(int index) { if ((index < -1) || (index >= getTabCount())) { throw new IndexOutOfBoundsException(); } } /** * Selects the tab corresponding to the widget for the tab. To be clear the widget for the tab is not the widget INSIDE of the tab; it * is the widget used to represent the tab itself. * * @param tabWidget The widget for the tab to be selected * @return true if the tab corresponding to the widget for the tab could located and selected, false otherwise */ private boolean selectTabByTabWidget(Widget tabWidget) { int numTabs = panel.getWidgetCount(); for (int i = 0; i < numTabs; ++i) { if (panel.getWidget(i) == tabWidget) { return selectTab(i); } } return false; } private void setSelectionStyle(Widget item, boolean selected) { if (item != null) { if (selected) { item.addStyleName(TAB_BAR_ITEM_SELECTED_STYLE_NAME); } else { item.removeStyleName(TAB_BAR_ITEM_SELECTED_STYLE_NAME); } } } /** * <code>ClickDelegatePanel</code> decorates any widget with the minimal amount of machinery to receive clicks for delegation to the * parent. {@link SourcesClickEvents} is not implemented due to the fact that only a single observer is needed. */ private class ClickDelegatePanel extends Composite { private boolean enabled = true; private SelectablePanel focusablePanel; ClickDelegatePanel(Widget child) { focusablePanel = new SelectablePanel(); focusablePanel.getElement().setTabIndex(0); focusablePanel.setWidget(child); focusablePanel.addSelectHandler(new SelectHandler() { @Override public void onSelect(SelectEvent event) { TabBar.this.selectTabByTabWidget(ClickDelegatePanel.this); } }); initWidget(focusablePanel); sinkEvents(Event.ONKEYDOWN); } SelectablePanel getFocusablePanel() { return focusablePanel; } public boolean hasWordWrap() { return focusablePanel.getChildWidget() instanceof HasWordWrap; } @Override public void onBrowserEvent(Event event) { if (!enabled) { return; } // No need for call to super. switch (DOM.eventGetType(event)) { case Event.ONKEYDOWN: if (((char) event.getKeyCode()) == KeyCodes.KEY_ENTER) { TabBar.this.selectTabByTabWidget(this); } break; } super.onBrowserEvent(event); } public void setEnabled(boolean enabled) { this.enabled = enabled; } public void setWordWrap(boolean wrap) { if (hasWordWrap()) { ((HasWordWrap) focusablePanel.getChildWidget()).setWordWrap(wrap); } else { throw new UnsupportedOperationException("Widget does not implement HasWordWrap"); } } } }