Package com.sencha.gxt.widget.core.client

Source Code of com.sencha.gxt.widget.core.client.TabPanel

/**
* Sencha GXT 3.1.0-beta - Sencha for GWT
* Copyright(c) 2007-2014, Sencha, Inc.
* licensing@sencha.com
*
* http://www.sencha.com/products/gxt/license/
*/
package com.sencha.gxt.widget.core.client;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.core.client.GWT;
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.NodeList;
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.SafeHtmlBuilder;
import com.google.gwt.uibinder.client.UiChild;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.IndexedPanel;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.core.client.GXT;
import com.sencha.gxt.core.client.Style.ScrollDirection;
import com.sencha.gxt.core.client.Style.Side;
import com.sencha.gxt.core.client.dom.XDOM;
import com.sencha.gxt.core.client.dom.XElement;
import com.sencha.gxt.core.client.util.AccessStack;
import com.sencha.gxt.core.client.util.Size;
import com.sencha.gxt.fx.client.FxElement;
import com.sencha.gxt.fx.client.animation.AfterAnimateEvent;
import com.sencha.gxt.fx.client.animation.AfterAnimateEvent.AfterAnimateHandler;
import com.sencha.gxt.fx.client.animation.Fx;
import com.sencha.gxt.messages.client.DefaultMessages;
import com.sencha.gxt.widget.core.client.container.CardLayoutContainer;
import com.sencha.gxt.widget.core.client.container.HasActiveWidget;
import com.sencha.gxt.widget.core.client.container.HasLayout;
import com.sencha.gxt.widget.core.client.event.BeforeCloseEvent;
import com.sencha.gxt.widget.core.client.event.BeforeCloseEvent.BeforeCloseHandler;
import com.sencha.gxt.widget.core.client.event.BeforeCloseEvent.HasBeforeCloseHandlers;
import com.sencha.gxt.widget.core.client.event.CloseEvent;
import com.sencha.gxt.widget.core.client.event.CloseEvent.CloseHandler;
import com.sencha.gxt.widget.core.client.event.CloseEvent.HasCloseHandlers;
import com.sencha.gxt.widget.core.client.event.HideEvent;
import com.sencha.gxt.widget.core.client.event.HideEvent.HideHandler;
import com.sencha.gxt.widget.core.client.menu.Menu;
import com.sencha.gxt.widget.core.client.menu.MenuItem;

/**
* A basic tab container.
* <p/>
* Code snippet:
* <p/>
*
* <pre>
*   TabPanel panel = new TabPanel();
*   panel.setTabScroll(true);
*   panel.setAnimScroll(true);
*   panel.add(new Label("Tab 1 Content"), new TabItemConfig("Tab 1", true));
*   panel.add(new Label("Tab 2 Content"), new TabItemConfig("Tab 2", true));
* </pre>
*/
public class TabPanel extends Component implements IndexedPanel.ForIsWidget, HasActiveWidget,
    HasBeforeSelectionHandlers<Widget>, HasSelectionHandlers<Widget>, HasBeforeCloseHandlers<Widget>,
    HasCloseHandlers<Widget>, HasLayout, HasWidgets {

  @SuppressWarnings("javadoc")
  public static interface TabPanelAppearance {

    void createScrollers(XElement parent);

    XElement getBar(XElement parent);

    XElement getBody(XElement parent);

    String getItemSelector();

    XElement getScrollLeft(XElement parent);

    XElement getScrollRight(XElement parent);

    XElement getStripEdge(XElement parent);

    XElement getStripWrap(XElement parent);

    void insert(XElement parent, TabItemConfig config, int index);

    boolean isClose(XElement target);

    void onDeselect(Element item);

    void onMouseOut(XElement parent, XElement target);

    void onMouseOver(XElement parent, XElement target);

    void onScrolling(XElement bar, boolean scrolling);

    void onSelect(Element item);

    void render(SafeHtmlBuilder builder);

    void setItemWidth(XElement element, int width);

    void updateItem(XElement item, TabItemConfig config);

    void updateScrollButtons(XElement parent);

  }

  public static interface TabPanelBottomAppearance extends TabPanelAppearance {

  }

  @SuppressWarnings("javadoc")
  public interface TabPanelMessages {

    String closeOtherTabs();

    String closeTab();

  }

  protected class DefaultTabPanelMessages implements TabPanelMessages {

    public String closeOtherTabs() {
      return DefaultMessages.getMessages().tabPanelItem_closeOtherText();
    }

    public String closeTab() {
      return DefaultMessages.getMessages().tabPanelItem_closeText();
    }

  }

  private final TabPanelAppearance appearance;

  protected Menu closeContextMenu;
  private boolean animScroll = true;
  private boolean autoSelect = true;
  private boolean bodyBorder = true;
  private boolean closeMenu = false;
  private boolean scheduledDelegateUpdates;
  private TabPanelMessages messages;
  private boolean resizeTabs = false;
  private int scrollDuration = 150;
  private int scrollIncrement = 100;
  private boolean scrolling;
  private AccessStack<Widget> stack;
  private boolean tabScroll = false;
  private Widget contextMenuItem;

  private int tabMargin = 2;
  private int tabWidth = 120;
  private int minTabWidth = 30;

  private HashMap<Widget, TabItemConfig> configMap = new HashMap<Widget, TabItemConfig>();
  private CardLayoutContainer container = new CardLayoutContainer() {
    @Override
    protected Widget getParentLayoutWidget() {
      return container.getParent();
    }

    protected void onRemove(Widget child) {
      super.onRemove(child);
      configMap.remove(child);
    }
  };

  /**
   * Creates a new tab panel with the default appearance.
   */
  public TabPanel() {
    this(GWT.<TabPanelAppearance> create(TabPanelAppearance.class));
  }

  /**
   * Creates a new tab panel with the specified appearance.
   *
   * @param appearance the appearance of the tab panel
   */
  public TabPanel(TabPanelAppearance appearance) {
    this.appearance = appearance;

    SafeHtmlBuilder sb = new SafeHtmlBuilder();
    appearance.render(sb);

    setElement((Element) XDOM.create(sb.toSafeHtml()));

    ComponentHelper.setParent(this, container);
    appearance.getBody(getElement()).appendChild(container.getElement());

    setDeferHeight(true);
  }

  /**
   * Adds an item to the tab panel with the specified tab configuration.
   *
   * @param widget the widget to add to the tab panel
   * @param config the configuration of the tab
   */
  @UiChild(tagname = "child")
  public void add(IsWidget widget, TabItemConfig config) {
    add(asWidgetOrNull(widget), config);
  }

  /**
   * Adds an item to the tab panel with the specified text.
   *
   * @param widget the widget to add to the tab panel
   * @param text the text for the tab
   */
  public void add(IsWidget widget, String text) {
    add(asWidgetOrNull(widget), text);
  }

  @Override
  public void add(Widget w) {
    throw new UnsupportedOperationException("this add method not supported");
  }

  /**
   * Adds an item to the tab panel with the specified text. Shorthand for {@link #add(Widget, TabItemConfig)}.
   *
   * @param widget the widget to add to the tab panel
   * @param text the text for the tab
   */
  public void add(Widget widget, String text) {
    insert(widget, getWidgetCount(), new TabItemConfig(text));
  }

  /**
   * Adds an item to the tab panel with the specified tab configuration.
   *
   * @param widget the item to add to the tab panel
   * @param config the configuration of the tab
   */
  public void add(Widget widget, TabItemConfig config) {
    insert(widget, getWidgetCount(), config);
  }

  @Override
  public HandlerRegistration addBeforeCloseHandler(BeforeCloseHandler<Widget> handler) {
    return addHandler(handler, BeforeCloseEvent.getType());
  }

  @Override
  public HandlerRegistration addBeforeSelectionHandler(BeforeSelectionHandler<Widget> handler) {
    return addHandler(handler, BeforeSelectionEvent.getType());
  }

  @Override
  public HandlerRegistration addCloseHandler(CloseHandler<Widget> handler) {
    return addHandler(handler, CloseEvent.getType());
  }

  @Override
  public HandlerRegistration addSelectionHandler(SelectionHandler<Widget> handler) {
    return addHandler(handler, SelectionEvent.getType());
  }

  @Override
  public void clear() {
    container.clear();
  }

  /**
   * Searches for a child widget based on its id and optionally the text of the {@link TabItemConfig}.
   * <p/>
   * Iterates through each item and checks if its id matches the parameter {@code id}. Then, if the
   * {@code alsoCheckText} parameter is true, this also looks at the last passed in string of html or text for each
   * {@code TabItemConfig}. If that content matches, then it returns that tab.
   * <p/>
   * With {@code alsoCheckText} set to true, the first matching item will be returned.
   *
   * @param id the item id
   * @param alsoCheckText {@code false} to only compare with id, {@code true} to compare both the items id and text
   * @return the item
   */
  public Widget findItem(String id, boolean alsoCheckText) {
    int count = container.getWidgetCount();
    for (int i = 0; i < count; i++) {
      Widget item = container.getWidget(i);
      String widgetId = ComponentHelper.getWidgetId(item);

      if (widgetId.equals(id)) return item;
      if (item instanceof Component && ((Component) item).getItemId().equals(id)) return item;
      if (alsoCheckText && getConfig(item).getHTML().equals(id)) return item;
    }
    return null;
  }

  @Override
  public void forceLayout() {
    container.forceLayout();

  }

  @Override
  public Widget getActiveWidget() {
    return container.getActiveWidget();
  }

  public TabPanelAppearance getAppearance() {
    return appearance;
  }

  /**
   * Returns true if scrolling is animated.
   *
   * @return the animation scroll state
   */
  public boolean getAnimScroll() {
    return animScroll;
  }

  /**
   * Returns true if the body border is enabled.
   *
   * @return the body border state
   */
  public boolean getBodyBorder() {
    return bodyBorder;
  }

  /**
   * Returns the tab item config for the given widget.
   *
   * @param widget the widget
   * @return the config or null
   */
  public TabItemConfig getConfig(Widget widget) {
    return configMap.get(widget);
  }

  /**
   * Returns the internal card layout container.
   *
   * @return the card layout container
   */
  public CardLayoutContainer getContainer() {
    return container;
  }

  /**
   * Returns the tab panel messages.
   *
   * @return the messages
   */
  public TabPanelMessages getMessages() {
    if (messages == null) {
      messages = new DefaultTabPanelMessages();
    }
    return messages;
  }

  /**
   * Returns the minimum tab width.
   *
   * @return the minimum tab width
   */
  public int getMinTabWidth() {
    return minTabWidth;
  }

  /**
   * Returns true if tab resizing is enabled.
   *
   * @return the tab resizing state
   */
  public boolean getResizeTabs() {
    return resizeTabs;
  }

  /**
   * Returns the scroll duration in milliseconds.
   *
   * @return the duration
   */
  public int getScrollDuration() {
    return scrollDuration;
  }

  /**
   * Returns the panel's tab margin.
   *
   * @return the margin
   */
  public int getTabMargin() {
    return tabMargin;
  }

  /**
   * Returns true if tab scrolling is enabled.
   *
   * @return the tab scroll state
   */
  public boolean getTabScroll() {
    return tabScroll;
  }

  /**
   * Returns the default tab width.
   *
   * @return the width
   */
  public int getTabWidth() {
    return tabWidth;
  }

  @Override
  public Widget getWidget(int index) {
    return container.getWidget(index);
  }

  @Override
  public int getWidgetCount() {
    return container.getWidgetCount();
  }

  @Override
  public int getWidgetIndex(IsWidget child) {
    return container.getWidgetIndex(child);
  }

  public int getWidgetIndex(Widget widget) {
    return container.getWidgetIndex(widget);
  }

  /**
   * Inserts the specified item into the tab panel.
   *
   * @param widget the item to insert
   * @param index the insert index
   * @param config the configuration of the tab item
   */
  public void insert(Widget widget, int index, TabItemConfig config) {
    configMap.put(widget, config);
    container.insert(widget, index);
    appearance.insert(getElement(), config, index);

    if (getActiveWidget() == null && autoSelect) {
      setActiveWidget(widget);
    }

    if (getWidgetCount() == 1) {
      syncSize();
    }
  }

  /**
   * Returns true if auto select is enabled.
   *
   * @return the auto select state
   */
  public boolean isAutoSelect() {
    return autoSelect;
  }

  /**
   * Returns true if close context menu is enabled.
   *
   * @return the close menu state
   */
  public boolean isCloseContextMenu() {
    return closeMenu;
  }

  @Override
  public boolean isLayoutRunning() {
    return container.isLayoutRunning();
  }

  @Override
  public boolean isOrWasLayoutRunning() {
    return container.isOrWasLayoutRunning();
  }

  @Override
  public Iterator<Widget> iterator() {
    return container.iterator();
  }

  @Override
  public void onBrowserEvent(Event event) {
    XElement target = event.getEventTarget().cast();
    if (target == null) {
      return;
    }
    boolean isbar = appearance.getBar(getElement()).isOrHasChild(target);
    boolean orig = disableContextMenu;

    // allow right clicks in tab panel body
    if (!isbar && disableContextMenu) {
      disableContextMenu = false;
    }

    super.onBrowserEvent(event);

    if (!isbar) {
      disableContextMenu = orig;
      return;
    }

    Element item = findItem(target);
    if (item != null) {
      int index = itemIndex(item);
      TabItemConfig config = getConfig(getWidget(index));
      if (config != null && !config.isEnabled()) {
        return;
      }
    }

    switch (event.getTypeInt()) {
      case Event.ONCLICK:
        onClick(event);
        if (appearance.getScrollLeft(getElement()) != null
            && target.isOrHasChild(appearance.getScrollLeft(getElement()))) {
          event.stopPropagation();
          onScrollLeft();
        }
        if (appearance.getScrollRight(getElement()) != null
            && target.isOrHasChild(appearance.getScrollRight(getElement()))) {
          event.stopPropagation();
          onScrollRight();
        }
        break;
      case Event.ONMOUSEOVER:
        appearance.onMouseOver(getElement(), event.getEventTarget().<XElement>cast());
        break;
      case Event.ONMOUSEOUT:

        appearance.onMouseOut(getElement(), event.getEventTarget().<XElement>cast());
        break;
    }
  }

  @Override
  public boolean remove(int index) {
    return remove(getWidget(index));
  }

  public boolean remove(Widget child) {
    int idx = getWidgetIndex(child);
    Widget activeWidget = getActiveWidget();
    boolean removed = container.remove(child);

    if (removed) {
      if (stack != null) {
        stack.remove(child);
      }

      Element item = findItem(idx);
      item.removeFromParent();

      if (child == activeWidget) {
        Widget next = stack != null ? stack.next() : null;
        if (next != null) {
          setActiveWidget(next);
        } else if (getWidgetCount() > 0) {
          setActiveWidget(getWidget(0));
        } else {
          setActiveWidget(null);
        }
      }
      delegateUpdates();
    }

    return removed;
  }

  /**
   * Scrolls to a particular tab if tab scrolling is enabled.
   *
   * @param item the item to scroll to
   * @param animate true to animate the scroll
   */
  public void scrollToTab(Widget item, boolean animate) {
    if (item == null) return;
    int pos = getScrollPos();
    int area = getScrollArea();
    XElement itemEl = findItem(container.getWidgetIndex(item)).cast();
    int left = itemEl.getOffsetsTo(getStripWrap()).getX() + pos;
    int right = left + itemEl.getOffsetWidth();
    if (left < pos) {
      scrollTo(left, animate);
    } else if (right > (pos + area)) {
      scrollTo(right - area, animate);
    }
  }

  /**
   * Sets the active widget.
   *
   * @param widget the widget
   */
  public void setActiveWidget(IsWidget widget) {
    setActiveWidget(asWidgetOrNull(widget));
  }

  /**
   * Sets the active widget.
   *
   * @param item the widget
   * @param fireEvents {@code true} to fire events
   */
  public void setActiveWidget(Widget item, boolean fireEvents) {
    if (item == null || item.getParent() != container) {
      return;
    }

    if (getActiveWidget() != item) {
      if (fireEvents) {
        BeforeSelectionEvent<Widget> event = BeforeSelectionEvent.fire(this, item);
        // event can be null if no handlers
        if (event != null && event.isCanceled()) {
          return;
        }
      }

      if (getActiveWidget() != null) {
        appearance.onDeselect(findItem(getWidgetIndex(getActiveWidget())));
      }
      appearance.onSelect(findItem(getWidgetIndex(item)));
      container.setActiveWidget(item);

      if (stack == null) {
        stack = new AccessStack<Widget>();
      }
      stack.add(item);

      focusTab(item, false);
      if (fireEvents) {
        SelectionEvent.fire(this, item);
      }
      delegateUpdates();
    }
  }

  @Override
  public void setActiveWidget(Widget item) {
    setActiveWidget(item, true);
  }

  /**
   * True to animate tab scrolling so that hidden tabs slide smoothly into view (defaults to true). Only applies when
   * {@link #tabScroll} = true.
   *
   * @param animScroll the animation scroll state
   */
  public void setAnimScroll(boolean animScroll) {
    this.animScroll = animScroll;
  }

  /**
   * True to have the first item selected when the panel is displayed for the first time if there is not selection
   * (defaults to true).
   *
   * @param autoSelect the auto select state
   */
  public void setAutoSelect(boolean autoSelect) {
    this.autoSelect = autoSelect;
  }

  /**
   * True to display an interior border on the body element of the panel, false to hide it (defaults to true,
   * pre-render).
   *
   * @param bodyBorder the body border style
   */
  public void setBodyBorder(boolean bodyBorder) {
    this.bodyBorder = bodyBorder;
  }

  /**
   * True to show the close context menu (defaults to false).
   *
   * @param closeMenu true to show it
   */
  public void setCloseContextMenu(boolean closeMenu) {
    this.closeMenu = closeMenu;
    disableContextMenu = true;
    if (closeMenu) {
      sinkEvents(Event.ONCONTEXTMENU);
    }
  }

  /**
   * Sets the tab panel messages.
   *
   * @param messages the messages
   */
  public void setMessages(TabPanelMessages messages) {
    this.messages = messages;
  }

  /**
   * The minimum width in pixels for each tab when {@link #resizeTabs} = true (defaults to 30).
   *
   * @param minTabWidth the minimum tab width
   */
  public void setMinTabWidth(int minTabWidth) {
    this.minTabWidth = minTabWidth;
  }

  /**
   * True to automatically resize tabs. The resize operation takes into consideration the current width of the tab panel
   * as well as the current values of {@link #setTabWidth(int)} and {@link #setMinTabWidth(int)}. The resulting tab
   * width will not be less than the value specified by <code>setMinTabWidth</code> nor greater than the value specified
   * by <code>setTabWidth</code>. To automatically resize the tabs to completely fill the tab strip, use
   * <code>setTabWidth(Integer.MAX_VALUE)</code> and <code>setResizeTabs(true)</code>.
   *
   * @param resizeTabs true to enable tab resizing
   */
  public void setResizeTabs(boolean resizeTabs) {
    this.resizeTabs = resizeTabs;
  }

  /**
   * Sets the number of milliseconds that each scroll animation should last (defaults to 150).
   *
   * @param scrollDuration the scroll duration
   */
  public void setScrollDuration(int scrollDuration) {
    this.scrollDuration = scrollDuration;
  }

  /**
   * Sets the number of pixels to scroll each time a tab scroll button is pressed (defaults to 100, or if
   * {@link #setResizeTabs(boolean)} = true, the calculated tab width). Only applies when {@link #setTabScroll(boolean)}
   * = true.
   *
   * @param scrollIncrement the scroll increment
   */
  public void setScrollIncrement(int scrollIncrement) {
    this.scrollIncrement = scrollIncrement;
  }

  /**
   * The number of pixels of space to calculate into the sizing and scrolling of tabs (defaults to 2).
   *
   * @param tabMargin the tab margin
   */
  public void setTabMargin(int tabMargin) {
    this.tabMargin = tabMargin;
  }

  /**
   * True to enable scrolling to tabs that may be invisible due to overflowing the overall TabPanel width. Only
   * available with tabs on top. (defaults to false).
   *
   * @param tabScroll true to enable tab scrolling
   */
  public void setTabScroll(boolean tabScroll) {
    this.tabScroll = tabScroll;
  }

  /**
   * Sets the initial width in pixels of each new tab (defaults to 120).
   *
   * @param tabWidth the tab width
   */
  public void setTabWidth(int tabWidth) {
    this.tabWidth = tabWidth;
  }

  /**
   * Updates the appearance of the specified tab item. Must be invoked after changing the tab item configuration.
   *
   * @param widget the widget for the tab to update
   * @param config the new or updated tab item configuration
   */
  public void update(Widget widget, TabItemConfig config) {
    XElement item = findItem(getWidgetIndex(widget));
    if (item != null) {
      configMap.put(widget, config);
      appearance.updateItem(item, config);
    }
  }

  protected void close(Widget item) {
    if (fireCancellableEvent(new BeforeCloseEvent<Widget>(item)) && remove(item)) {
      fireEvent(new CloseEvent<Widget>(item));
    }
  }

  @Override
  protected void doAttachChildren() {
    super.doAttachChildren();
    ComponentHelper.doAttach(container);
  }

  @Override
  protected void doDetachChildren() {
    super.doDetachChildren();
    ComponentHelper.doDetach(container);
  }

  protected Element findItem(Element target) {
    return target.<XElement> cast().findParentElement(appearance.getItemSelector(), -1);
  }

  protected XElement findItem(int index) {
    NodeList<Element> items = appearance.getBar(getElement()).select(appearance.getItemSelector());
    return items.getItem(index).cast();
  }

  protected XElement getStripWrap() {
    return appearance.getStripWrap(getElement());
  }

  protected int itemIndex(Element item) {
    NodeList<Element> items = appearance.getBar(getElement()).select(appearance.getItemSelector());
    for (int i = 0; i < items.getLength(); i++) {
      if (items.getItem(i) == item) {
        return i;
      }
    }
    return -1;
  }

  @Override
  protected void onAfterFirstAttach() {
    super.onAfterFirstAttach();

    if (!bodyBorder) {
      appearance.getBody(getElement()).getStyle().setProperty("border", "none");
    }

    getElement().setTabIndex(0);
    getElement().setAttribute("hideFocus", "true");

    sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.ONKEYUP | Event.FOCUSEVENTS);
  }

  @Override
  protected void onAttach() {
    super.onAttach();
    appearance.getBar(getElement()).disableTextSelection(true);

    if (getActiveWidget() == null && autoSelect && getWidgetCount() > 0) {
      setActiveWidget(getWidget(0));
    }
  }

  @Override
  protected void onBlur(Event event) {
    super.onBlur(event);
  }

  protected void onClick(Event event) {
    XElement target = event.getEventTarget().cast();
    Element item = findItem(target);
    if (item != null) {
      event.stopPropagation();
      Widget w = getWidget(itemIndex(item));
      boolean close = appearance.isClose(target);
      if (close) {
        close(w);
      } else if (w != getActiveWidget()) {
        setActiveWidget(w);
        focusTab(w, true);
      } else if (w == getActiveWidget()) {
        focusTab(w, true);
      }
    }
  }

  @Override
  protected void onDetach() {
    appearance.getBar(getElement()).disableTextSelection(false);
    super.onDetach();
  }

  @Override
  protected void onFocus(Event event) {
    if (getWidgetCount() > 0 && getActiveWidget() == null) {
      setActiveWidget(getWidget(0));
    } else if (getActiveWidget() != null) {
      focusTab(getActiveWidget(), true);
    }
  }

  protected void onItemContextMenu(final Widget item, int x, int y) {
    if (closeMenu) {
      if (closeContextMenu == null) {
        closeContextMenu = new Menu();
        closeContextMenu.addHideHandler(new HideHandler() {

          @Override
          public void onHide(HideEvent event) {
            contextMenuItem = null;
          }
        });

        closeContextMenu.add(new MenuItem(getMessages().closeTab(), new SelectionHandler<MenuItem>() {
          @Override
          public void onSelection(SelectionEvent<MenuItem> event) {
            close(contextMenuItem);
          }
        }));

        closeContextMenu.add(new MenuItem(getMessages().closeOtherTabs(), new SelectionHandler<MenuItem>() {
          @Override
          public void onSelection(SelectionEvent<MenuItem> event) {
            List<Widget> widgets = new ArrayList<Widget>();
            for (int i = 0, len = getWidgetCount(); i < len; i++) {
              widgets.add(getWidget(i));
            }

            for (Widget w : widgets) {
              TabItemConfig config = getConfig(w);
              if (w != contextMenuItem && config.isClosable()) {
                close(w);
              }
            }
          }

        }));
      }
      TabItemConfig c = configMap.get(item);
      MenuItem mi = (MenuItem) closeContextMenu.getWidget(0);
      mi.setEnabled(c.isClosable());
      contextMenuItem = item;
      boolean hasClosable = false;

      for (int i = 0, len = getWidgetCount(); i < len; i++) {
        Widget item2 = container.getWidget(i);
        TabItemConfig config = configMap.get(item2);
        if (config.isClosable() && item2 != item) {
          hasClosable = true;
          break;
        }
      }
      MenuItem m = (MenuItem) closeContextMenu.getWidget(1);
      m.setEnabled(hasClosable);
      closeContextMenu.showAt(x, y);
    }
  }

  protected void onItemTextChange(Widget tabItem, String oldText, String newText) {
    delegateUpdates();
  }

  @Override
  protected void onResize(int width, int height) {
    super.onResize(width, height);
    Size frameWidth = getElement().getFrameSize();

    if (!isAutoHeight()) {
      height -= frameWidth.getHeight() + appearance.getBar(getElement()).getOffsetHeight();
    }
    if (!isAutoWidth()) {
      width -= frameWidth.getWidth();
    }

    appearance.getBody(getElement()).setSize(width, height, true);
    appearance.getBar(getElement()).setWidth(width, true);

    if (!isAutoHeight()) {
      height -= appearance.getBody(getElement()).getFrameWidth(Side.TOP, Side.BOTTOM);
    }
    if (!isAutoWidth()) {
      width -= appearance.getBody(getElement()).getFrameWidth(Side.LEFT, Side.RIGHT);
    }
    container.setPixelSize(width, height);

    delegateUpdates();
  }

  @Override
  protected void onRightClick(Event event) {
    Element target = event.getEventTarget().cast();
    if (appearance.getBar(getElement()).isOrHasChild(target)) {
      Element item = findItem(event.getEventTarget().<Element> cast());
      if (item != null) {
        int idx = itemIndex(item);
        if (idx != -1) {
          onItemContextMenu(getWidget(idx), event.getClientX(), event.getClientY());
        }
      }
    } else {
      super.onRightClick(event);
    }
  }

  @Override
  protected void onUnload() {
    super.onUnload();
    if (stack != null) {
      stack.clear();
    }
  }

  private void autoScrollTabs() {
    int count = getWidgetCount();
    int tw = appearance.getBar(getElement()).getClientWidth();
    if (tw == 0) {
      tw = getElement().getStyleSize().getWidth();
    }

    XElement stripWrap = appearance.getStripWrap(getElement());
    XElement edge = appearance.getStripEdge(getElement());
    XElement scrollLeft = appearance.getScrollLeft(getElement());
    XElement scrollRight = appearance.getScrollRight(getElement());

    int cw = stripWrap.getOffsetWidth();

    int pos = getScrollPos();
    int l = edge.<XElement> cast().getOffsetsTo(stripWrap).getX() + pos;

    if (!getTabScroll() || count < 1 || cw < 20) {
      return;
    }

    if (l <= tw) {
      stripWrap.<XElement> cast().setWidth(tw);
      if (scrolling) {
        stripWrap.setScrollLeft(0);
        scrolling = false;

        scrollLeft.setVisible(false);
        scrollRight.setVisible(false);
        appearance.onScrolling(getElement(), false);
      }
    } else {
      if (!scrolling) {
        appearance.onScrolling(getElement(), true);
      }
      tw -= 36;
      stripWrap.<XElement> cast().setWidth(tw > 20 ? tw : 20);
      if (!scrolling) {
        if (scrollLeft == null) {
          appearance.createScrollers(getElement());
        } else {
          scrollLeft.setVisible(true);
          scrollRight.setVisible(true);
        }
      }
      scrolling = true;
      if (pos > (l - tw)) {
        stripWrap.setScrollLeft(l - tw);
      } else {
        scrollToTab(getActiveWidget(), false);
      }
      appearance.updateScrollButtons(getElement());
    }
  }

  private void autoSizeTabs() {
    int count = getWidgetCount();
    if (count == 0) return;
    int aw = appearance.getBar(getElement()).getClientWidth();
    if (aw == 0) {
      aw = getElement().getStyleSize().getWidth();
    }
    int each = (int) Math.max(Math.min(Math.floor((aw - 4) / count) - tabMargin, tabWidth), minTabWidth);

    for (int i = 0; i < count; i++) {
      XElement el = findItem(i).cast();
      appearance.setItemWidth(el, each);
    }
  }

  private void delegateUpdates() {
    if (!scheduledDelegateUpdates) {
      scheduledDelegateUpdates = true;
      Scheduler.get().scheduleFinally(new ScheduledCommand() {
        @Override
        public void execute() {
          scheduledDelegateUpdates = false;
          if (resizeTabs) {
            autoSizeTabs();
          }
          if (tabScroll) {
            autoScrollTabs();
          }
        }
      });
    }
  }

  private void focusTab(Widget item, boolean setFocus) {
    if (setFocus && !GXT.isIE7()) {
      // item.getHeader().getElement().focus();
    }
  }

  private int getScrollArea() {
    return Math.max(0, appearance.getStripWrap(getElement()).getClientWidth());
  }

  private int getScrollIncrement() {
    return scrollIncrement;
  }

  private int getScrollPos() {
    return appearance.getStripWrap(getElement()).getScrollLeft();
  }

  private int getScrollWidth() {
    return appearance.getStripEdge(getElement()).getOffsetsTo(getStripWrap()).getX() + getScrollPos();
  }

  private void onScrollLeft() {
    int pos = getScrollPos();
    int s = Math.max(0, pos - getScrollIncrement());
    if (s != pos) {
      scrollTo(s, getAnimScroll());
    }
  }

  private void onScrollRight() {
    int sw = getScrollWidth() - getScrollArea();
    int pos = getScrollPos();
    int s = Math.min(sw, pos + getScrollIncrement());
    if (s != pos) {
      scrollTo(s, getAnimScroll());
    }
  }

  private void scrollTo(int pos, boolean animate) {
    XElement stripWrap = getStripWrap();
    if (animate) {
      Fx fx = new Fx();
      fx.addAfterAnimateHandler(new AfterAnimateHandler() {
        @Override
        public void onAfterAnimate(AfterAnimateEvent event) {
          appearance.updateScrollButtons(getElement());
        }
      });
      stripWrap.<FxElement> cast().scrollTo(ScrollDirection.LEFT, pos, true, fx);
    } else {
      stripWrap.setScrollLeft(pos);
      appearance.updateScrollButtons(getElement());
    }
  }
}
TOP

Related Classes of com.sencha.gxt.widget.core.client.TabPanel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.