/*
* Copyright 2007 Hilbrand Bouwkamp, hs@bouwkamp.com
*
* This file is a derivative work of the file:
* com.google.gwt.user.client.ui.TabBar.java
* The original file is available from:
* http://code.google.com/webtoolkit/
*
* 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.
*
* License of original work
*
* Copyright 2006 Google Inc.
*
* 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.cobogw.gwt.user.client.ui;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.SourcesClickEvents;
import com.google.gwt.user.client.ui.SourcesTabEvents;
import com.google.gwt.user.client.ui.TabListener;
import com.google.gwt.user.client.ui.TabListenerCollection;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
/**
* A vertical bar of folder-style tabs, most commonly used as part of a
* {@link org.cobogw.gwt.user.client.ui.VerticalTabPanel}.
*
* The vertical bar is a derivate of the TabBar
* {@link com.google.gwt.user.client.ui.TabBar}. This class uses the same
* CSS style names as the TabBar class to minimize differences between
* that class because the only difference is the orientation of the TabBar.
*
* <p>
* <img class='gallery' src='VerticalTabBar.png'/>
* </p>
* <h3>CSS Style Rules</h3>
* <ul class='css'>
* <li>.gwt-TabBar { the tab bar itself }</li>
* <li>.gwt-TabBar .gwt-TabBarFirst { the top edge of the bar }</li>
* <li>.gwt-TabBar .gwt-TabBarRest { the bottom edge of the bar }</li>
* <li>.gwt-TabBar .gwt-TabBarItem { unselected tabs }</li>
* <li>.gwt-TabBar .gwt-TabBarItem-selected { additional style for selected
* tabs } </li>
* </ul>
* <p>
* <h3>Example</h3>
* {@example com.bouwkamp.gwt..examples.VerticalTabBarExample}
* </p>
*/
public class VerticalTabBar extends Composite implements SourcesTabEvents,
ClickListener {
/**
* <code>ClickDecoratorPanel</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 static final class ClickDecoratorPanel extends SimplePanel {
ClickListener delegate;
ClickDecoratorPanel(Widget child, ClickListener delegate) {
this.delegate = delegate;
setWidget(child);
sinkEvents(Event.ONCLICK);
}
public void onBrowserEvent(Event event) {
// No need for call to super.
switch (DOM.eventGetType(event)) {
case Event.ONCLICK:
delegate.onClick(this);
}
}
}
private static final String STYLENAME_DEFAULT = "gwt-TabBarItem";
private VerticalPanel panel = new VerticalPanel();
private Widget selectedTab;
private TabListenerCollection tabListeners;
/**
* Creates an empty tab bar.
*/
public VerticalTabBar() {
initWidget(panel);
sinkEvents(Event.ONCLICK);
setStyleName("gwt-TabBar");
panel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
HTML first = new HTML(" ", true), rest = new HTML(" ", true);
rest.setStyleName("gwt-TabBarRest");
panel.add(first);
//set gwt-TabBarFirst on TR otherwise a 1px line remains visible in IE6 when display:none
DOM.setAttribute(DOM.getParent(DOM.getParent(first.getElement())), "className", "gwt-TabBarFirst");
panel.add(rest);
panel.setCellWidth(rest, "100%");
}
/**
* Adds a new tab with the specified text.
*
* @param text the new tab's text
*/
public void addTab(String text) {
insertTab(text, getTabCount());
}
/**
* Adds a new tab with the specified text.
*
* @param text the new tab's text
* @param asHTML <code>true</code> to treat the specified text as html
*/
public void addTab(String text, boolean asHTML) {
insertTab(text, asHTML, getTabCount());
}
/**
* Adds a new tab with the specified widget.
*
* @param widget the new tab's widget.
*/
public void addTab(Widget widget) {
insertTab(widget, getTabCount());
}
public void addTabListener(TabListener listener) {
if (tabListeners == null) {
tabListeners = new TabListenerCollection();
}
tabListeners.add(listener);
}
/**
* Gets the tab that is currently selected.
*
* @return the selected tab
*/
public int getSelectedTab() {
if (selectedTab == null) {
return -1;
}
return panel.getWidgetIndex(selectedTab) - 1;
}
/**
* Gets the widget of the tab that is currently selected.
*
* @return the selected tab widget
*/
public Widget getSelectedTabWidget() {
return null != selectedTab && selectedTab instanceof ClickDecoratorPanel
? ((ClickDecoratorPanel) selectedTab).getWidget()
: selectedTab;
}
/**
* Gets the number of tabs present.
*
* @return the tab count
*/
public int getTabCount() {
return panel.getWidgetCount() - 2;
}
/**
* Gets the specified tab's HTML.
*
* @param index the index of the tab whose HTML is to be retrieved
* @return the tab's HTML
*/
public String getTabHTML(int index) {
if (index >= getTabCount()) {
return null;
}
Widget widget = panel.getWidget(index + 1);
if (widget instanceof HTML) {
return ((HTML) widget).getHTML();
} else if (widget instanceof Label) {
return ((Label) widget).getText();
} else {
// This will be a ClickDecorator holding a user-supplied widget.
return DOM.getInnerHTML(widget.getElement());
}
}
/**
* Inserts a new tab at the specified index.
*
* @param text the new tab's text
* @param asHTML <code>true</code> to treat the specified text as HTML
* @param beforeIndex the index before which this tab will be inserted
*/
public void insertTab(String text, boolean asHTML, int beforeIndex) {
checkInsertBeforeTabIndex(beforeIndex);
Label item;
if (asHTML) {
item = new HTML(text);
} else {
item = new Label(text);
}
item.setWordWrap(false);
item.addClickListener(this);
item.setStyleName(STYLENAME_DEFAULT);
panel.insert(item, beforeIndex + 1);
}
/**
* 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) {
insertTab(text, false, beforeIndex);
}
/**
* 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) {
checkInsertBeforeTabIndex(beforeIndex);
ClickDecoratorPanel decWidget = new ClickDecoratorPanel(widget, this);
decWidget.addStyleName(STYLENAME_DEFAULT);
panel.insert(decWidget, beforeIndex + 1);
}
public void onClick(Widget sender) {
for (int i = 1; i < panel.getWidgetCount() - 1; ++i) {
if (panel.getWidget(i) == sender) {
selectTab(i - 1);
return;
}
}
}
/**
* Removes the tab at the specified index.
*
* @param index the index of the tab to be removed
*/
public void removeTab(int index) {
checkTabIndex(index);
// (index + 1) to account for 'first' placeholder widget.
Widget toRemove = panel.getWidget(index + 1);
if (toRemove == selectedTab) {
selectedTab = null;
}
panel.remove(toRemove);
}
public void removeTabListener(TabListener listener) {
if (tabListeners != null) {
tabListeners.remove(listener);
}
}
/**
* 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 TabListener}.
*/
public boolean selectTab(int index) {
checkTabIndex(index);
if (tabListeners != null) {
if (!tabListeners.fireBeforeTabSelected(this, index)) {
return false;
}
}
// Check for -1.
setSelectionStyle(selectedTab, false);
if (index == -1) {
selectedTab = null;
return true;
}
selectedTab = panel.getWidget(index + 1);
setSelectionStyle(selectedTab, true);
if (tabListeners != null) {
tabListeners.fireTabSelected(this, index);
}
return true;
}
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();
}
}
private void setSelectionStyle(Widget item, boolean selected) {
if (item != null) {
if (selected) {
item.addStyleName("gwt-TabBarItem-selected");
} else {
item.removeStyleName("gwt-TabBarItem-selected");
}
}
}
}