package com.eas.widgets.containers;
import com.eas.core.XElement;
import com.eas.menu.MenuItemImageText;
import com.eas.menu.PlatypusPopupMenu;
import com.eas.ui.HasImageResource;
import com.eas.widgets.boxes.ImageLabel;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
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.resources.client.ImageResource;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeUri;
import com.google.gwt.safehtml.shared.UriUtils;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHTML;
import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.IndexedPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.ProvidesResize;
import com.google.gwt.user.client.ui.RequiresResize;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.TabLayoutPanel;
import com.google.gwt.user.client.ui.Widget;
/**
*
* @author mg
*/
public class TabsDecoratedPanel extends SimplePanel implements RequiresResize, ProvidesResize, IndexedPanel, HasSelectionHandlers<Widget> {
protected boolean tabsOnTop = true;
protected FlowPanel chevron = new FlowPanel();
protected Button scrollLeft;
protected Button scrollRight;
protected Button tabsList;
protected TabLayoutPanel tabs;
protected double barHeight;
protected Style.Unit barUnit;
//
protected LayoutPanel tabBarContainer;
protected Widget tabBar;
protected Widget tabsContent;
//
protected Widget selected;
public TabsDecoratedPanel(double aBarHeight, Style.Unit aBarUnit) {
super();
barHeight = aBarHeight;
barUnit = aBarUnit;
tabs = new TabLayoutPanel(barHeight, barUnit) {
@Override
protected void initWidget(Widget w) {
super.initWidget(w);
assert w instanceof LayoutPanel;
tabBarContainer = (LayoutPanel) w;
}
@Override
public void insert(Widget child, Widget aTabWidget, int beforeIndex) {
child.getElement().getStyle().clearWidth();
child.getElement().getStyle().clearHeight();
child.getElement().getStyle().clearRight();
child.getElement().getStyle().setWidth(100, Style.Unit.PCT);
com.eas.ui.CommonResources.INSTANCE.commons().ensureInjected();
child.getElement().addClassName(com.eas.ui.CommonResources.INSTANCE.commons().borderSized());
super.insert(child, aTabWidget, beforeIndex);
Widget tab = ((FlowPanel)tabBar).getWidget(beforeIndex);
tab.setStylePrimaryName("tabs-tab");
tabsList.setEnabled(true);
}
@Override
public boolean remove(int index) {
boolean res = super.remove(index);
if (tabs.getWidgetCount() == 0)
tabsList.setEnabled(false);
return res;
}
@Override
public void selectTab(final int index, boolean fireEvents) {
super.selectTab(index, fireEvents);
}
};
tabs.addSelectionHandler(new SelectionHandler<Integer>() {
@Override
public void onSelection(SelectionEvent<Integer> event) {
selected = event.getSelectedItem() != -1 ? tabs.getWidget(event.getSelectedItem()) : null;
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
if (selected instanceof RequiresResize) {
((RequiresResize) selected).onResize();
}
}
});
SelectionEvent.fire(TabsDecoratedPanel.this, selected);
}
});
tabBar = tabBarContainer.getWidget(0);
tabsContent = tabBarContainer.getWidget(1);
tabBar.getElement().getStyle().setProperty("lineHeight", "normal");
tabBar.setStylePrimaryName("tabs-bar");
tabs.setStylePrimaryName("tabs");
// GWT Layout animations are deprecated because of CSS3 transitions
tabs.setAnimationDuration(0);
scrollLeft = new Button("", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
int offsetLeft = tabBar.getElement().getOffsetLeft();
if (offsetLeft < 0) {
tabBar.getElement().getStyle().setLeft(Math.min(offsetLeft + 100, 0), Style.Unit.PX);
}
}
});
scrollLeft.setStyleName("tabs-chevron-left");
scrollLeft.addStyleName("btn");
scrollRight = new Button("", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
int newTabBarLeft = calcNewScrollRightPosition();
tabBar.getElement().getStyle().setLeft(newTabBarLeft, Style.Unit.PX);
}
});
scrollRight.setStyleName("tabs-chevron-right");
scrollRight.addStyleName("btn");
tabsList = new Button("", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
final PlatypusPopupMenu menu = new PlatypusPopupMenu();
for (int i = 0; i < tabs.getWidgetCount(); i++) {
final Widget content = tabs.getWidget(i);
Widget w = tabs.getTabWidget(i);
if (w instanceof SimplePanel) {
SimplePanel sp = (SimplePanel) w;
w = sp.getWidget();
}
ScheduledCommand tabSelector = new ScheduledCommand() {
@Override
public void execute() {
tabs.selectTab(content);
menu.hide();
Widget targetTab = tabs.getTabWidget(content);
int tabCenterX = targetTab.getParent().getElement().getOffsetLeft() + targetTab.getParent().getElement().getOffsetWidth() / 2;
int tabBarParentWidth = tabBar.getElement().getParentElement().getOffsetWidth() - chevron.getElement().getOffsetWidth();
int newOffsetLeft = tabBarParentWidth / 2 - tabCenterX;
Widget lastTab = tabs.getTabWidget(tabs.getWidgetCount() - 1);
int rightMostX = lastTab.getParent().getElement().getOffsetLeft() + lastTab.getParent().getElement().getOffsetWidth();
int width = rightMostX + newOffsetLeft;
if (width > tabBarParentWidth) {
tabBar.getElement().getStyle().setLeft(Math.min(newOffsetLeft, 0), Style.Unit.PX);
} else {
tabBar.getElement().getStyle().setLeft(Math.min(tabBarParentWidth - rightMostX, 0), Style.Unit.PX);
}
}
};
SafeUri imageUri = null;
if (w instanceof Image) {
Image image = (Image) w;
imageUri = UriUtils.fromTrustedString(image.getUrl());
} else if (w instanceof HasImageResource) {
HasImageResource imageHost = (HasImageResource) w;
if (imageHost.getImageResource() != null) {
imageUri = imageHost.getImageResource().getSafeUri();
}
}
if (w instanceof HasHTML) {
HasHTML h = (HasHTML) w;
String textAsHtml = h.getHTML();
menu.addItem(new MenuItemImageText(textAsHtml != null ? textAsHtml : h.getText(), true, imageUri, tabSelector));
} else if (w instanceof HasText) {
HasText l = (HasText) w;
menu.addItem(new MenuItemImageText(l.getText(), false, imageUri, tabSelector));
}
}
Widget lastWidget = chevron.getWidget(chevron.getWidgetCount() - 1);
menu.setPopupPosition(lastWidget.getAbsoluteLeft(), lastWidget.getAbsoluteTop() + lastWidget.getElement().getOffsetHeight());
menu.showRelativeTo(lastWidget);
}
});
tabsList.setStyleName("tabs-chevron-list");
tabsList.addStyleName("btn");
tabsList.setEnabled(false);
getElement().getStyle().setPosition(Style.Position.RELATIVE);
tabs.getElement().getStyle().setPosition(Style.Position.ABSOLUTE);
tabs.getElement().getStyle().setWidth(100, Style.Unit.PCT);
tabs.getElement().getStyle().setHeight(100, Style.Unit.PCT);
setWidget(tabs);
scrollLeft.getElement().getStyle().setPadding(0, Style.Unit.PX);
scrollLeft.getElement().getStyle().setMargin(0, Style.Unit.PX);
scrollRight.getElement().getStyle().setPadding(0, Style.Unit.PX);
scrollRight.getElement().getStyle().setMargin(0, Style.Unit.PX);
tabsList.getElement().getStyle().setPadding(0, Style.Unit.PX);
tabsList.getElement().getStyle().setMargin(0, Style.Unit.PX);
chevron.add(scrollLeft);
chevron.add(scrollRight);
chevron.add(tabsList);
chevron.getElement().addClassName("tabs-chevron");
chevron.getElement().getStyle().setPosition(Style.Position.ABSOLUTE);
assert tabBarContainer != null;
tabBarContainer.getWidgetContainerElement(tabBar).appendChild(chevron.getElement());
getElement().<XElement> cast().addResizingTransitionEnd(this);
}
public boolean isTabsOnTop() {
return tabsOnTop;
}
public void setTabsOnTop(boolean aValue) {
if (tabsOnTop != aValue) {
tabsOnTop = aValue;
applyTabsOnTop();
}
}
protected void applyTabsOnTop() {
if (tabBar != null && tabBarContainer != null && tabsContent != null) {
final String tabBarLeft = tabBar.getElement().getStyle().getLeft();
Element tabBarContainerElement = tabBarContainer.getWidgetContainerElement(tabBar);
tabBarContainerElement.getStyle().clearTop();
tabBarContainerElement.getStyle().clearHeight();
tabBarContainerElement.getStyle().clearBottom();
Element tabContentContainerElement = tabBarContainer.getWidgetContainerElement(tabsContent);
tabContentContainerElement.getStyle().clearTop();
tabContentContainerElement.getStyle().clearHeight();
tabContentContainerElement.getStyle().clearBottom();
if (tabsOnTop) {
tabBarContainer.setWidgetTopHeight(tabBar, 0, Style.Unit.PX, barHeight, barUnit);
tabBarContainer.setWidgetTopBottom(tabsContent, barHeight, barUnit, 0, Style.Unit.PX);
} else {
tabBarContainer.setWidgetBottomHeight(tabBar, 0, Style.Unit.PX, barHeight, barUnit);
tabBarContainer.setWidgetTopBottom(tabsContent, 0, Style.Unit.PX, barHeight, barUnit);
}
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
tabBar.getElement().getStyle().setProperty("left", tabBarLeft);
}
});
}
}
@Override
protected void onAttach() {
super.onAttach();
adopt(chevron);
}
@Override
protected void onDetach() {
orphan(chevron);
super.onDetach();
}
@Override
public void onResize() {
tabs.onResize();
}
protected int calcNewScrollRightPosition() {
Widget lastTab = tabs.getWidgetCount() > 0 ? tabs.getTabWidget(tabs.getWidgetCount() - 1) : null;
int rightMostX = lastTab != null ? lastTab.getParent().getElement().getOffsetLeft() + lastTab.getParent().getElement().getOffsetWidth() : tabBar.getElement().getOffsetLeft();
int tabBarParentWidth = tabBar.getElement().getParentElement().getOffsetWidth() - chevron.getElement().getOffsetWidth();
int tabBarMostLeft = Math.min(tabBarParentWidth - rightMostX, 0);
int nextTabBarLeft = tabBar.getElement().getOffsetLeft() - 100;
if (nextTabBarLeft < tabBarMostLeft)
nextTabBarLeft = tabBarMostLeft;
return nextTabBarLeft;
}
/**
* Adds a widget to the panel. If the Widget is already attached, it will be
* moved to the right-most index.
*
* @param child
* the widget to be added
* @param text
* the text to be shown on its tab
* @param asHtml
* <code>true</code> to treat the specified text as HTML
*/
public void add(Widget child, String text, boolean asHtml) {
tabs.insert(child, text, asHtml, tabs.getWidgetCount());
}
/**
* Adds a widget to the panel. If the Widget is already attached, it will be
* moved to the right-most index.
*
* @param child
* the widget to be added
* @param text
* the text to be shown on its tab
* @param asHtml
* <code>true</code> to treat the specified text as HTML
*/
public void add(Widget child, String text, boolean asHtml, ImageResource aImage) {
tabs.insert(child, new ImageLabel(text, asHtml, aImage), tabs.getWidgetCount());
}
/**
* Adds a widget to the panel. If the Widget is already attached, it will be
* moved to the right-most index.
*
* @param child
* the widget to be added
* @param text
* the text to be shown on its tab
*/
public void add(Widget child, String text) {
tabs.insert(child, text, tabs.getWidgetCount());
}
/**
* Adds a widget to the panel. If the Widget is already attached, it will be
* moved to the right-most index.
*
* @param child
* the widget to be added
* @param html
* the html to be shown on its tab
*/
public void add(Widget child, SafeHtml html) {
tabs.add(child, html.asString(), true);
}
/**
* Adds a widget to the panel. If the Widget is already attached, it will be
* moved to the right-most index.
*
* @param child
* the widget to be added
* @param tab
* the widget to be placed in the associated tab
*/
public void add(Widget child, Widget tab) {
tabs.insert(child, tab, tabs.getWidgetCount());
}
/**
* Inserts a widget into the panel. If the Widget is already attached, it
* will be moved to the requested index.
*
* @param child
* the widget to be added
* @param beforeIndex
* the index before which it will be inserted
*/
public void insert(Widget child, int beforeIndex) {
tabs.insert(child, "", beforeIndex);
}
/**
* Inserts a widget into the panel. If the Widget is already attached, it
* will be moved to the requested index.
*
* @param child
* the widget to be added
* @param html
* the html to be shown on its tab
* @param beforeIndex
* the index before which it will be inserted
*/
public void insert(Widget child, SafeHtml html, int beforeIndex) {
tabs.insert(child, html.asString(), true, beforeIndex);
}
/**
* Inserts a widget into the panel. If the Widget is already attached, it
* will be moved to the requested index.
*
* @param child
* the widget to be added
* @param text
* the text to be shown on its tab
* @param asHtml
* <code>true</code> to treat the specified text as HTML
* @param beforeIndex
* the index before which it will be inserted
*/
public void insert(Widget child, String text, boolean asHtml, int beforeIndex) {
Widget contents;
if (asHtml) {
contents = new HTML(text);
} else {
contents = new Label(text);
}
tabs.insert(child, contents, beforeIndex);
}
/**
* Inserts a widget into the panel. If the Widget is already attached, it
* will be moved to the requested index.
*
* @param child
* the widget to be added
* @param text
* the text to be shown on its tab
* @param beforeIndex
* the index before which it will be inserted
*/
public void insert(Widget child, String text, int beforeIndex) {
tabs.insert(child, text, false, beforeIndex);
}
/**
* Inserts a widget into the panel. If the Widget is already attached, it
* will be moved to the requested index.
*
* @param child
* the widget to be added
* @param tab
* the widget to be placed in the associated tab
* @param beforeIndex
* the index before which it will be inserted
*/
public void insert(Widget child, Widget tab, int beforeIndex) {
tabs.insert(child, tab, beforeIndex);
}
/**
* Set the duration of the animated transition between tabs.
*
* @param duration
* the duration in milliseconds.
*/
public void setAnimationDuration(int duration) {
tabs.setAnimationDuration(duration);
}
/**
* Set whether or not transitions slide in vertically or horizontally.
*
* @param isVertical
* true for vertical transitions, false for horizontal
*/
public void setAnimationVertical(boolean isVertical) {
tabs.setAnimationVertical(isVertical);
}
/**
* Sets a tab's HTML contents.
*
* Use care when setting an object's HTML; it is an easy way to expose
* script-based security problems. Consider using
* {@link #setTabHTML(int, SafeHtml)} or {@link #setTabText(int, String)}
* whenever possible.
*
* @param index
* the index of the tab whose HTML is to be set
* @param html
* the tab's new HTML contents
*/
public void setTabHTML(int index, String html) {
tabs.setTabHTML(index, html);
}
/**
* Sets a tab's HTML contents.
*
* @param index
* the index of the tab whose HTML is to be set
* @param html
* the tab's new HTML contents
*/
public void setTabHTML(int index, SafeHtml html) {
tabs.setTabHTML(index, html);
}
/**
* Sets a tab's text contents.
*
* @param index
* the index of the tab whose text is to be set
* @param text
* the object's new text
*/
public void setTabText(int index, String text) {
tabs.setTabText(index, text);
}
@Override
public boolean remove(Widget w) {
return tabs.remove(w);
}
@Override
public Widget getWidget(int index) {
return tabs.getWidget(index);
}
@Override
public int getWidgetCount() {
return tabs.getWidgetCount();
}
@Override
public int getWidgetIndex(Widget child) {
return tabs.getWidgetIndex(child);
}
@Override
public boolean remove(int aIndex) {
return tabs.remove(aIndex);
}
/**
* Programmatically selects the specified tab and fires events.
*
* @param child
* the child whose tab is to be selected
*/
public void selectTab(Widget child) {
tabs.selectTab(child);
}
/**
* Programmatically selects the specified tab.
*
* @param child
* the child whose tab is to be selected
* @param fireEvents
* true to fire events, false not to
*/
public void selectTab(Widget child, boolean fireEvents) {
tabs.selectTab(child, fireEvents);
}
/**
* Programmatically selects the specified tab and fires events.
*
* @param index
* the index of the tab to be selected
*/
public void selectTab(int index) {
tabs.selectTab(index);
}
/**
* Programmatically selects the specified tab.
*
* @param index
* the index of the tab to be selected
* @param fireEvents
* true to fire events, false not to
*/
public void selectTab(int index, boolean fireEvents) {
tabs.selectTab(index, fireEvents);
}
@Override
public HandlerRegistration addSelectionHandler(SelectionHandler<Widget> handler) {
return addHandler(handler, SelectionEvent.getType());
}
}