123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540 |
- /*
- @ITMillApache2LicenseForJavaFiles@
- */
-
- package com.itmill.toolkit.terminal.gwt.client.ui;
-
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Set;
-
- import com.google.gwt.user.client.Command;
- import com.google.gwt.user.client.DOM;
- import com.google.gwt.user.client.DeferredCommand;
- import com.google.gwt.user.client.Element;
- import com.google.gwt.user.client.Event;
- import com.google.gwt.user.client.Timer;
- import com.google.gwt.user.client.ui.ClickListener;
- import com.google.gwt.user.client.ui.ComplexPanel;
- import com.google.gwt.user.client.ui.Label;
- import com.google.gwt.user.client.ui.Widget;
- import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
- import com.itmill.toolkit.terminal.gwt.client.BrowserInfo;
- import com.itmill.toolkit.terminal.gwt.client.ContainerResizedListener;
- import com.itmill.toolkit.terminal.gwt.client.ICaption;
- import com.itmill.toolkit.terminal.gwt.client.Paintable;
- import com.itmill.toolkit.terminal.gwt.client.RenderInformation;
- import com.itmill.toolkit.terminal.gwt.client.RenderSpace;
- import com.itmill.toolkit.terminal.gwt.client.UIDL;
-
- public class ITabsheet extends ITabsheetBase implements
- ContainerResizedListener {
-
- class TabBar extends ComplexPanel implements ClickListener {
-
- private Element tr = DOM.createTR();
-
- private Element spacerTd = DOM.createTD();
-
- TabBar() {
- Element el = DOM.createTable();
- Element tbody = DOM.createTBody();
- DOM.appendChild(el, tbody);
- DOM.appendChild(tbody, tr);
- setStyleName(spacerTd, CLASSNAME + "-spacertd");
- DOM.appendChild(tr, spacerTd);
- DOM.appendChild(spacerTd, DOM.createDiv());
- setElement(el);
- }
-
- protected Element getContainerElement() {
- return tr;
- }
-
- private Widget oldSelected;
-
- public int getTabCount() {
- return getWidgetCount();
- }
-
- public void addTab(ICaption c) {
- Element td = DOM.createTD();
- setStyleName(td, CLASSNAME + "-tabitemcell");
-
- if (getWidgetCount() == 0) {
- setStyleName(td, CLASSNAME + "-tabitemcell-first", true);
- }
-
- Element div = DOM.createDiv();
- setStyleName(div, CLASSNAME + "-tabitem");
- DOM.appendChild(td, div);
- DOM.insertBefore(tr, td, spacerTd);
- c.addClickListener(this);
- add(c, div);
- }
-
- public void onClick(Widget sender) {
- int index = getWidgetIndex(sender);
- onTabSelected(index);
- }
-
- public void selectTab(int index) {
- Widget newSelected = getWidget(index);
- Widget.setStyleName(DOM.getParent(newSelected.getElement()),
- CLASSNAME + "-tabitem-selected", true);
- if (oldSelected != null && oldSelected != newSelected) {
- Widget.setStyleName(DOM.getParent(oldSelected.getElement()),
- CLASSNAME + "-tabitem-selected", false);
- }
- oldSelected = newSelected;
- }
-
- public void removeTab(int i) {
- remove(i);
- }
-
- public boolean remove(Widget w) {
- ((ICaption) w).removeClickListener(this);
- return super.remove(w);
- }
-
- public ICaption getTab(int index) {
- if (index >= getWidgetCount()) {
- return null;
- }
- return (ICaption) getWidget(index);
- }
-
- }
-
- public static final String CLASSNAME = "i-tabsheet";
-
- public static final String TABS_CLASSNAME = "i-tabsheet-tabcontainer";
- public static final String SCROLLER_CLASSNAME = "i-tabsheet-scroller";
- private final Element tabs; // tabbar and 'scroller' container
- private final Element scroller; // tab-scroller element
- private final Element scrollerNext; // tab-scroller next button element
- private final Element scrollerPrev; // tab-scroller prev button element
- private int scrollerIndex = 0;
-
- private final TabBar tb = new TabBar();
- private final ITabsheetPanel tp = new ITabsheetPanel();
- private final Element contentNode, deco;
-
- private final HashMap captions = new HashMap();
-
- private String height;
- private String width;
-
- private boolean waitingForResponse;
-
- private RenderInformation renderInformation = new RenderInformation();
-
- /**
- * Previous visible widget is set invisible with CSS (not display: none, but
- * visibility: hidden), to avoid flickering during render process. Normal
- * visibility must be returned later when new widget is rendered.
- */
- private Widget previousVisibleWidget;
-
- private void onTabSelected(final int tabIndex) {
- if (disabled || waitingForResponse) {
- return;
- }
- final Object tabKey = tabKeys.get(tabIndex);
- if (disabledTabKeys.contains(tabKey)) {
- return;
- }
- if (client != null && activeTabIndex != tabIndex) {
- tb.selectTab(tabIndex);
- addStyleDependentName("loading");
- // run updating variables in deferred command to bypass some
- // FF
- // optimization issues
- DeferredCommand.addCommand(new Command() {
- public void execute() {
- previousVisibleWidget = tp.getWidget(tp.getVisibleWidget());
- DOM.setStyleAttribute(previousVisibleWidget.getElement(),
- "visibility", "hidden");
- client.updateVariable(id, "selected", tabKeys.get(tabIndex)
- .toString(), true);
- }
- });
- waitingForResponse = true;
- }
- }
-
- public ITabsheet() {
- super(CLASSNAME);
-
- // Tab scrolling
- DOM.setStyleAttribute(getElement(), "overflow", "hidden");
- tabs = DOM.createDiv();
- DOM.setElementProperty(tabs, "className", TABS_CLASSNAME);
- scroller = DOM.createDiv();
-
- DOM.setElementProperty(scroller, "className", SCROLLER_CLASSNAME);
- scrollerPrev = DOM.createButton();
- DOM.setElementProperty(scrollerPrev, "className", SCROLLER_CLASSNAME
- + "Prev");
- DOM.sinkEvents(scrollerPrev, Event.ONCLICK);
- scrollerNext = DOM.createButton();
- DOM.setElementProperty(scrollerNext, "className", SCROLLER_CLASSNAME
- + "Next");
- DOM.sinkEvents(scrollerNext, Event.ONCLICK);
- DOM.appendChild(getElement(), tabs);
-
- // Tabs
- tp.setStyleName(CLASSNAME + "-tabsheetpanel");
- contentNode = DOM.createDiv();
-
- deco = DOM.createDiv();
-
- addStyleDependentName("loading"); // Indicate initial progress
- tb.setStyleName(CLASSNAME + "-tabs");
- DOM
- .setElementProperty(contentNode, "className", CLASSNAME
- + "-content");
- DOM.setElementProperty(deco, "className", CLASSNAME + "-deco");
-
- add(tb, tabs);
- DOM.appendChild(scroller, scrollerPrev);
- DOM.appendChild(scroller, scrollerNext);
-
- DOM.appendChild(getElement(), contentNode);
- add(tp, contentNode);
- DOM.appendChild(getElement(), deco);
-
- DOM.appendChild(tabs, scroller);
-
- // TODO Use for Safari only. Fix annoying 1px first cell in TabBar.
- // DOM.setStyleAttribute(DOM.getFirstChild(DOM.getFirstChild(DOM
- // .getFirstChild(tb.getElement()))), "display", "none");
-
- }
-
- public void onBrowserEvent(Event event) {
-
- // Tab scrolling
- if (isScrolledTabs() && DOM.eventGetTarget(event) == scrollerPrev) {
- if (scrollerIndex > 0) {
- scrollerIndex--;
- DOM.setStyleAttribute(DOM.getChild(DOM.getFirstChild(DOM
- .getFirstChild(tb.getElement())), scrollerIndex),
- "display", "");
- updateTabScroller();
- }
- } else if (isClippedTabs() && DOM.eventGetTarget(event) == scrollerNext) {
- int tabs = tb.getTabCount();
- if (scrollerIndex + 1 <= tabs) {
- DOM.setStyleAttribute(DOM.getChild(DOM.getFirstChild(DOM
- .getFirstChild(tb.getElement())), scrollerIndex),
- "display", "none");
- scrollerIndex++;
- updateTabScroller();
- }
- } else {
- super.onBrowserEvent(event);
- }
- }
-
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- super.updateFromUIDL(uidl, client);
-
- // Add proper stylenames for all elements (easier to prevent unwanted
- // style inheritance)
- if (uidl.hasAttribute("style")) {
- final String[] styles = uidl.getStringAttribute("style").split(" ");
- final String contentBaseClass = CLASSNAME + "-content";
- String contentClass = contentBaseClass;
- final String decoBaseClass = CLASSNAME + "-deco";
- String decoClass = decoBaseClass;
- for (int i = 0; i < styles.length; i++) {
- tb.addStyleDependentName(styles[i]);
- contentClass += " " + contentBaseClass + "-" + styles[i];
- decoClass += " " + decoBaseClass + "-" + styles[i];
- }
- DOM.setElementProperty(contentNode, "className", contentClass);
- DOM.setElementProperty(deco, "className", decoClass);
- } else {
- tb.setStyleName(CLASSNAME + "-tabs");
- DOM.setElementProperty(contentNode, "className", CLASSNAME
- + "-content");
- DOM.setElementProperty(deco, "className", CLASSNAME + "-deco");
- }
-
- if (uidl.hasAttribute("hidetabs")) {
- tb.setVisible(false);
- addStyleName(CLASSNAME + "-hidetabs");
- } else {
- tb.setVisible(true);
- removeStyleName(CLASSNAME + "-hidetabs");
- }
-
- // tabs; push or not
- if (uidl.hasAttribute("width")) {
- // update width later, in updateTabScroller();
- DOM.setStyleAttribute(tabs, "width", "1px");
- DOM.setStyleAttribute(tabs, "overflow", "hidden");
- } else {
- showAllTabs();
- DOM.setStyleAttribute(tabs, "width", "");
- DOM.setStyleAttribute(tabs, "overflow", "visible");
- }
-
- updateTabScroller();
- waitingForResponse = false;
- }
-
- protected void renderTab(final UIDL tabUidl, int index, boolean selected) {
- ICaption c = tb.getTab(index);
- if (c == null) {
- c = new ICaption(null, client);
- tb.addTab(c);
- }
- c.updateCaption(tabUidl);
- captions.put("" + index, c);
- if (selected) {
- renderContent(tabUidl.getChildUIDL(0));
- tb.selectTab(index);
- } else {
- if (tabUidl.getChildCount() > 0) {
- // updating a drawn child on hidden tab
- Paintable paintable = client.getPaintable(tabUidl
- .getChildUIDL(0));
-
- if (tp.getWidgetIndex((Widget) paintable) < 0) {
- tp.insert((Widget) paintable, index);
- }
- paintable.updateFromUIDL(tabUidl.getChildUIDL(0), client);
- } else if (tp.getWidgetCount() <= index) {
- tp.add(new Label(""));
- }
- }
- }
-
- protected void selectTab(int index, final UIDL contentUidl) {
- if (index != activeTabIndex) {
- activeTabIndex = index;
- tb.selectTab(activeTabIndex);
- }
- renderContent(contentUidl);
- }
-
- private void renderContent(final UIDL contentUIDL) {
- final Paintable content = client.getPaintable(contentUIDL);
- if (tp.getWidgetCount() > activeTabIndex) {
- Widget old = tp.getWidget(activeTabIndex);
- if (old != content) {
- tp.remove(activeTabIndex);
- if (old instanceof Paintable) {
- client.unregisterPaintable((Paintable) old);
- }
- tp.insert((Widget) content, activeTabIndex);
- }
- } else {
- tp.add((Widget) content);
- }
-
- tp.showWidget(activeTabIndex);
-
- ITabsheet.this.iLayout();
- (content).updateFromUIDL(contentUIDL, client);
- ITabsheet.this.removeStyleDependentName("loading");
- if (previousVisibleWidget != null) {
- DOM.setStyleAttribute(previousVisibleWidget.getElement(),
- "visibility", "");
- previousVisibleWidget = null;
- }
- }
-
- public void setHeight(String height) {
- super.setHeight(height);
- this.height = height;
- if (height != null && !"".equals(height)) {
- int contentHeight = getOffsetHeight()
- - DOM.getElementPropertyInt(deco, "offsetHeight")
- - tb.getOffsetHeight() - 5;
- if (contentHeight < 0) {
- contentHeight = 0;
- }
-
- // Set proper values for content element
- DOM.setStyleAttribute(contentNode, "height", contentHeight + "px");
- renderSpace.setHeight(contentHeight);
- DOM.setStyleAttribute(contentNode, "overflow", "auto");
- } else {
- DOM.setStyleAttribute(contentNode, "height", "");
- DOM.setStyleAttribute(contentNode, "overflow", "");
- renderSpace.setHeight(0);
- }
- iLayout();
- }
-
- public void setWidth(String width) {
- super.setWidth(width);
- this.width = width;
- if ("".equals(width)) {
- renderSpace.setWidth(0);
- contentNode.getStyle().setProperty("width", "");
- } else {
- int contentWidth = getOffsetWidth() - getContentAreaBorderWidth();
- contentNode.getStyle().setProperty("width", contentWidth + "px");
- renderSpace.setWidth(contentWidth);
- }
- iLayout();
- }
-
- public void iLayout() {
- renderInformation.updateSize(getElement());
-
- if (client != null) {
- client.runDescendentsLayout(this);
- }
-
- updateTabScroller();
-
- if (BrowserInfo.get().getWebkitVersion() > 0) {
- DeferredCommand.addCommand(new Command() {
- public void execute() {
- // Dough, safari scoll auto means actually just a moped
- contentNode.getStyle().setProperty("overflow", "hidden");
- (new Timer() {
- @Override
- public void run() {
- contentNode.getStyle().setProperty("overflow",
- "auto");
- }
- }).schedule(100);
- }
- });
- }
-
- }
-
- /**
- * Layouts the tab-scroller elements, and applies styles.
- */
- private void updateTabScroller() {
- if (width != null) {
- DOM.setStyleAttribute(tabs, "width", width);
- }
- if (scrollerIndex > tb.getTabCount()) {
- scrollerIndex = 0;
- }
- boolean scrolled = isScrolledTabs();
- boolean clipped = isClippedTabs();
- if (tb.isVisible() && (scrolled || clipped)) {
- DOM.setStyleAttribute(scroller, "display", "");
- DOM.setElementProperty(scrollerPrev, "className",
- SCROLLER_CLASSNAME + (scrolled ? "Prev" : "Prev-disabled"));
- DOM.setElementProperty(scrollerNext, "className",
- SCROLLER_CLASSNAME + (clipped ? "Next" : "Next-disabled"));
- } else {
- DOM.setStyleAttribute(scroller, "display", "none");
- }
-
- }
-
- private void showAllTabs() {
- scrollerIndex = 0;
- Element tr = DOM.getFirstChild(DOM.getFirstChild(tb.getElement()));
- for (int i = 0; i < tb.getTabCount(); i++) {
- DOM.setStyleAttribute(DOM.getChild(tr, i), "display", "");
- }
- }
-
- private boolean isScrolledTabs() {
- return scrollerIndex > 0;
- }
-
- private boolean isClippedTabs() {
- return tb.getOffsetWidth() > getOffsetWidth();
- }
-
- protected void clearPaintables() {
-
- int i = tb.getTabCount();
- while (i > 0) {
- tb.removeTab(--i);
- }
- tp.clear();
-
- }
-
- protected Iterator getPaintableIterator() {
- return tp.iterator();
- }
-
- public boolean hasChildComponent(Widget component) {
- if (tp.getWidgetIndex(component) < 0) {
- return false;
- } else {
- return true;
- }
- }
-
- public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
- int widgetIndex = tp.getWidgetIndex(oldComponent);
- tp.remove(oldComponent);
- tp.insert(newComponent, widgetIndex);
- }
-
- public void updateCaption(Paintable component, UIDL uidl) {
- int i = tp.getWidgetIndex((Widget) component);
- ICaption c = (ICaption) captions.get("" + i);
- c.updateCaption(uidl);
- }
-
- public boolean requestLayout(Set<Paintable> child) {
- if (height != null && width != null) {
- /*
- * If the height and width has been specified for this container the
- * child components cannot make the size of the layout change
- */
-
- return true;
- }
-
- if (renderInformation.updateSize(getElement())) {
- /*
- * Size has changed so we let the child components know about the
- * new size.
- */
- iLayout();
-
- return false;
- } else {
- /*
- * Size has not changed so we do not need to propagate the event
- * further
- */
- return true;
- }
-
- }
-
- private int borderW = -1;
-
- private void detectBorder() {
- String property = contentNode.getStyle().getProperty("overflow");
- contentNode.getStyle().setProperty("overflow", "hidden");
- borderW = contentNode.getOffsetWidth()
- - contentNode.getPropertyInt("clientWidth");
- contentNode.getStyle().setProperty("overflow", property);
- }
-
- private int getContentAreaBorderWidth() {
- if (borderW < 0) {
- detectBorder();
- }
- return borderW;
- }
-
- private RenderSpace renderSpace = new RenderSpace(0, 0, true);
-
- public RenderSpace getAllocatedSpace(Widget child) {
- // All tabs have equal amount of space allocated
- return renderSpace;
- }
- }
|