|
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180 |
- /*
- @VaadinApache2LicenseForJavaFiles@
- */
-
- package com.vaadin.terminal.gwt.client.ui;
-
- import java.util.Iterator;
- import java.util.List;
-
- import com.google.gwt.core.client.Scheduler;
- import com.google.gwt.dom.client.DivElement;
- import com.google.gwt.dom.client.Style;
- import com.google.gwt.dom.client.Style.Visibility;
- import com.google.gwt.dom.client.TableCellElement;
- import com.google.gwt.dom.client.TableElement;
- import com.google.gwt.event.dom.client.BlurEvent;
- import com.google.gwt.event.dom.client.BlurHandler;
- import com.google.gwt.event.dom.client.ClickEvent;
- import com.google.gwt.event.dom.client.ClickHandler;
- import com.google.gwt.event.dom.client.FocusEvent;
- import com.google.gwt.event.dom.client.FocusHandler;
- import com.google.gwt.event.dom.client.HasBlurHandlers;
- import com.google.gwt.event.dom.client.HasFocusHandlers;
- import com.google.gwt.event.dom.client.HasKeyDownHandlers;
- import com.google.gwt.event.dom.client.KeyCodes;
- import com.google.gwt.event.dom.client.KeyDownEvent;
- import com.google.gwt.event.dom.client.KeyDownHandler;
- import com.google.gwt.event.shared.HandlerRegistration;
- import com.google.gwt.user.client.Command;
- import com.google.gwt.user.client.DOM;
- import com.google.gwt.user.client.Element;
- import com.google.gwt.user.client.Event;
- import com.google.gwt.user.client.ui.ComplexPanel;
- import com.google.gwt.user.client.ui.SimplePanel;
- import com.google.gwt.user.client.ui.Widget;
- import com.google.gwt.user.client.ui.impl.FocusImpl;
- import com.vaadin.terminal.gwt.client.ApplicationConnection;
- import com.vaadin.terminal.gwt.client.BrowserInfo;
- import com.vaadin.terminal.gwt.client.ComponentConnector;
- import com.vaadin.terminal.gwt.client.ComponentState;
- import com.vaadin.terminal.gwt.client.ConnectorMap;
- import com.vaadin.terminal.gwt.client.EventId;
- import com.vaadin.terminal.gwt.client.Focusable;
- import com.vaadin.terminal.gwt.client.TooltipInfo;
- import com.vaadin.terminal.gwt.client.UIDL;
- import com.vaadin.terminal.gwt.client.Util;
- import com.vaadin.terminal.gwt.client.VCaption;
- import com.vaadin.terminal.gwt.client.ui.label.VLabel;
-
- public class VTabsheet extends VTabsheetBase implements Focusable,
- FocusHandler, BlurHandler, KeyDownHandler {
-
- private static class VCloseEvent {
- private Tab tab;
-
- VCloseEvent(Tab tab) {
- this.tab = tab;
- }
-
- public Tab getTab() {
- return tab;
- }
-
- }
-
- private interface VCloseHandler {
- public void onClose(VCloseEvent event);
- }
-
- /**
- * Representation of a single "tab" shown in the TabBar
- *
- */
- private static class Tab extends SimplePanel implements HasFocusHandlers,
- HasBlurHandlers, HasKeyDownHandlers {
- private static final String TD_CLASSNAME = CLASSNAME + "-tabitemcell";
- private static final String TD_FIRST_CLASSNAME = TD_CLASSNAME
- + "-first";
- private static final String TD_SELECTED_CLASSNAME = TD_CLASSNAME
- + "-selected";
- private static final String TD_SELECTED_FIRST_CLASSNAME = TD_SELECTED_CLASSNAME
- + "-first";
- private static final String TD_DISABLED_CLASSNAME = TD_CLASSNAME
- + "-disabled";
-
- private static final String DIV_CLASSNAME = CLASSNAME + "-tabitem";
- private static final String DIV_SELECTED_CLASSNAME = DIV_CLASSNAME
- + "-selected";
-
- private TabCaption tabCaption;
- Element td = getElement();
- private VCloseHandler closeHandler;
-
- private boolean enabledOnServer = true;
- private Element div;
- private TabBar tabBar;
- private boolean hiddenOnServer = false;
-
- private String styleName;
-
- private Tab(TabBar tabBar) {
- super(DOM.createTD());
- this.tabBar = tabBar;
- setStyleName(td, TD_CLASSNAME);
-
- div = DOM.createDiv();
- focusImpl.setTabIndex(td, -1);
- setStyleName(div, DIV_CLASSNAME);
-
- DOM.appendChild(td, div);
-
- tabCaption = new TabCaption(this, getTabsheet()
- .getApplicationConnection());
- add(tabCaption);
-
- addFocusHandler(getTabsheet());
- addBlurHandler(getTabsheet());
- addKeyDownHandler(getTabsheet());
- }
-
- public boolean isHiddenOnServer() {
- return hiddenOnServer;
- }
-
- public void setHiddenOnServer(boolean hiddenOnServer) {
- this.hiddenOnServer = hiddenOnServer;
- }
-
- @Override
- protected Element getContainerElement() {
- // Attach caption element to div, not td
- return div;
- }
-
- public boolean isEnabledOnServer() {
- return enabledOnServer;
- }
-
- public void setEnabledOnServer(boolean enabled) {
- enabledOnServer = enabled;
- setStyleName(td, TD_DISABLED_CLASSNAME, !enabled);
- if (!enabled) {
- focusImpl.setTabIndex(td, -1);
- }
- }
-
- public void addClickHandler(ClickHandler handler) {
- tabCaption.addClickHandler(handler);
- }
-
- public void setCloseHandler(VCloseHandler closeHandler) {
- this.closeHandler = closeHandler;
- }
-
- /**
- * Toggles the style names for the Tab
- *
- * @param selected
- * true if the Tab is selected
- * @param first
- * true if the Tab is the first visible Tab
- */
- public void setStyleNames(boolean selected, boolean first) {
- // TODO #5100 doesn't belong here
- focusImpl.setTabIndex(td, selected ? getTabsheet().tabulatorIndex
- : -1);
-
- setStyleName(td, TD_FIRST_CLASSNAME, first);
- setStyleName(td, TD_SELECTED_CLASSNAME, selected);
- setStyleName(td, TD_SELECTED_FIRST_CLASSNAME, selected && first);
- setStyleName(div, DIV_SELECTED_CLASSNAME, selected);
- }
-
- public boolean isClosable() {
- return tabCaption.isClosable();
- }
-
- public void onClose() {
- closeHandler.onClose(new VCloseEvent(this));
- }
-
- public VTabsheet getTabsheet() {
- return tabBar.getTabsheet();
- }
-
- public void updateFromUIDL(UIDL tabUidl) {
- tabCaption.updateCaption(tabUidl);
-
- // Apply the styleName set for the tab
- String newStyleName = tabUidl.getStringAttribute(TAB_STYLE_NAME);
- // Find the nth td element
- if (newStyleName != null && newStyleName.length() != 0) {
- if (!newStyleName.equals(styleName)) {
- // If we have a new style name
- if (styleName != null && styleName.length() != 0) {
- // Remove old style name if present
- td.removeClassName(TD_CLASSNAME + "-" + styleName);
- }
- // Set new style name
- td.addClassName(TD_CLASSNAME + "-" + newStyleName);
- styleName = newStyleName;
- }
- } else if (styleName != null) {
- // Remove the set stylename if no stylename is present in the
- // uidl
- td.removeClassName(TD_CLASSNAME + "-" + styleName);
- styleName = null;
- }
- }
-
- public void recalculateCaptionWidth() {
- tabCaption.setWidth(tabCaption.getRequiredWidth() + "px");
- }
-
- public HandlerRegistration addFocusHandler(FocusHandler handler) {
- return addDomHandler(handler, FocusEvent.getType());
- }
-
- public HandlerRegistration addBlurHandler(BlurHandler handler) {
- return addDomHandler(handler, BlurEvent.getType());
- }
-
- public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
- return addDomHandler(handler, KeyDownEvent.getType());
- }
-
- public void focus() {
- focusImpl.focus(td);
- }
-
- public void blur() {
- focusImpl.blur(td);
- }
- }
-
- private static class TabCaption extends VCaption {
-
- private boolean closable = false;
- private Element closeButton;
- private Tab tab;
- private ApplicationConnection client;
-
- TabCaption(Tab tab, ApplicationConnection client) {
- super(client);
- this.client = client;
- this.tab = tab;
- }
-
- @Override
- public boolean updateCaption(UIDL uidl) {
- if (uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION)) {
- TooltipInfo tooltipInfo = new TooltipInfo();
- tooltipInfo
- .setTitle(uidl
- .getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION));
- // TODO currently, there is no error indicator and message for a tab
- client.registerTooltip(getTabsheet(), getElement(), tooltipInfo);
- } else {
- client.registerTooltip(getTabsheet(), getElement(), null);
- }
-
- // TODO need to call this instead of super because the caption does
- // not have an owner
- boolean ret = updateCaptionWithoutOwner(
- uidl,
- uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_CAPTION),
- uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DISABLED),
- uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION),
- uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ICON));
-
- setClosable(uidl.hasAttribute("closable"));
-
- return ret;
- }
-
- private VTabsheet getTabsheet() {
- return tab.getTabsheet();
- }
-
- @Override
- public void onBrowserEvent(Event event) {
- if (closable && event.getTypeInt() == Event.ONCLICK
- && event.getEventTarget().cast() == closeButton) {
- tab.onClose();
- event.stopPropagation();
- event.preventDefault();
- }
-
- super.onBrowserEvent(event);
-
- if (event.getTypeInt() == Event.ONLOAD) {
- getTabsheet().tabSizeMightHaveChanged(getTab());
- }
- client.handleTooltipEvent(event, getTabsheet(), getElement());
- }
-
- public Tab getTab() {
- return tab;
- }
-
- public void setClosable(boolean closable) {
- this.closable = closable;
- if (closable && closeButton == null) {
- closeButton = DOM.createSpan();
- closeButton.setInnerHTML("×");
- closeButton
- .setClassName(VTabsheet.CLASSNAME + "-caption-close");
- getElement().insertBefore(closeButton,
- getElement().getLastChild());
- } else if (!closable && closeButton != null) {
- getElement().removeChild(closeButton);
- closeButton = null;
- }
- if (closable) {
- addStyleDependentName("closable");
- } else {
- removeStyleDependentName("closable");
- }
- }
-
- public boolean isClosable() {
- return closable;
- }
-
- @Override
- public int getRequiredWidth() {
- int width = super.getRequiredWidth();
- if (closeButton != null) {
- width += Util.getRequiredWidth(closeButton);
- }
- return width;
- }
- }
-
- static class TabBar extends ComplexPanel implements ClickHandler,
- VCloseHandler {
-
- private final Element tr = DOM.createTR();
-
- private final Element spacerTd = DOM.createTD();
-
- private Tab selected;
-
- private VTabsheet tabsheet;
-
- TabBar(VTabsheet tabsheet) {
- this.tabsheet = tabsheet;
-
- 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);
- }
-
- public void onClose(VCloseEvent event) {
- Tab tab = event.getTab();
- if (!tab.isEnabledOnServer()) {
- return;
- }
- int tabIndex = getWidgetIndex(tab);
- getTabsheet().sendTabClosedEvent(tabIndex);
- }
-
- protected Element getContainerElement() {
- return tr;
- }
-
- public int getTabCount() {
- return getWidgetCount();
- }
-
- public Tab addTab() {
- Tab t = new Tab(this);
- int tabIndex = getTabCount();
-
- // Logical attach
- insert(t, tr, tabIndex, true);
-
- if (tabIndex == 0) {
- // Set the "first" style
- t.setStyleNames(false, true);
- }
-
- t.addClickHandler(this);
- t.setCloseHandler(this);
-
- return t;
- }
-
- public void onClick(ClickEvent event) {
- Widget caption = (Widget) event.getSource();
- int index = getWidgetIndex(caption.getParent());
- getTabsheet().onTabSelected(index);
- }
-
- public VTabsheet getTabsheet() {
- return tabsheet;
- }
-
- public Tab getTab(int index) {
- if (index < 0 || index >= getTabCount()) {
- return null;
- }
- return (Tab) super.getWidget(index);
- }
-
- public void selectTab(int index) {
- final Tab newSelected = getTab(index);
- final Tab oldSelected = selected;
-
- newSelected.setStyleNames(true, isFirstVisibleTab(index));
-
- if (oldSelected != null && oldSelected != newSelected) {
- oldSelected.setStyleNames(false,
- isFirstVisibleTab(getWidgetIndex(oldSelected)));
- }
-
- // Update the field holding the currently selected tab
- selected = newSelected;
-
- // The selected tab might need more (or less) space
- newSelected.recalculateCaptionWidth();
- getTab(tabsheet.activeTabIndex).recalculateCaptionWidth();
- }
-
- public void removeTab(int i) {
- Tab tab = getTab(i);
- if (tab == null) {
- return;
- }
-
- remove(tab);
-
- /*
- * If this widget was selected we need to unmark it as the last
- * selected
- */
- if (tab == selected) {
- selected = null;
- }
-
- // FIXME: Shouldn't something be selected instead?
- }
-
- private boolean isFirstVisibleTab(int index) {
- return getFirstVisibleTab() == index;
- }
-
- /**
- * Returns the index of the first visible tab
- *
- * @return
- */
- private int getFirstVisibleTab() {
- return getNextVisibleTab(-1);
- }
-
- /**
- * Find the next visible tab. Returns -1 if none is found.
- *
- * @param i
- * @return
- */
- private int getNextVisibleTab(int i) {
- int tabs = getTabCount();
- do {
- i++;
- } while (i < tabs && getTab(i).isHiddenOnServer());
-
- if (i == tabs) {
- return -1;
- } else {
- return i;
- }
- }
-
- /**
- * Find the previous visible tab. Returns -1 if none is found.
- *
- * @param i
- * @return
- */
- private int getPreviousVisibleTab(int i) {
- do {
- i--;
- } while (i >= 0 && getTab(i).isHiddenOnServer());
-
- return i;
-
- }
-
- public int scrollLeft(int currentFirstVisible) {
- int prevVisible = getPreviousVisibleTab(currentFirstVisible);
- if (prevVisible == -1) {
- return -1;
- }
-
- Tab newFirst = getTab(prevVisible);
- newFirst.setVisible(true);
- newFirst.recalculateCaptionWidth();
-
- return prevVisible;
- }
-
- public int scrollRight(int currentFirstVisible) {
- int nextVisible = getNextVisibleTab(currentFirstVisible);
- if (nextVisible == -1) {
- return -1;
- }
- Tab currentFirst = getTab(currentFirstVisible);
- currentFirst.setVisible(false);
- currentFirst.recalculateCaptionWidth();
- return nextVisible;
- }
- }
-
- public static final String CLASSNAME = "v-tabsheet";
-
- public static final String TABS_CLASSNAME = "v-tabsheet-tabcontainer";
- public static final String SCROLLER_CLASSNAME = "v-tabsheet-scroller";
-
- // Can't use "style" as it's already in use
- public static final String TAB_STYLE_NAME = "tabstyle";
-
- final Element tabs; // tabbar and 'scroller' container
- Tab focusedTab;
- int tabulatorIndex = 0;
-
- private static final FocusImpl focusImpl = FocusImpl.getFocusImplForPanel();
-
- 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
-
- /**
- * The index of the first visible tab (when scrolled)
- */
- private int scrollerIndex = 0;
-
- final TabBar tb = new TabBar(this);
- final VTabsheetPanel tp = new VTabsheetPanel();
- final Element contentNode;
-
- private final Element deco;
-
- boolean waitingForResponse;
-
- private String currentStyle;
-
- /**
- * @return Whether the tab could be selected or not.
- */
- private boolean onTabSelected(final int tabIndex) {
- if (disabled || waitingForResponse) {
- return false;
- }
- final Object tabKey = tabKeys.get(tabIndex);
- if (disabledTabKeys.contains(tabKey)) {
- return false;
- }
- if (client != null && activeTabIndex != tabIndex) {
- tb.selectTab(tabIndex);
-
- if (focusedTab != null) {
- focusedTab = tb.getTab(tabIndex);
- }
-
- addStyleDependentName("loading");
- // Hide the current contents so a loading indicator can be shown
- // instead
- Widget currentlyDisplayedWidget = tp.getWidget(tp
- .getVisibleWidget());
- currentlyDisplayedWidget.getElement().getParentElement().getStyle()
- .setVisibility(Visibility.HIDDEN);
- client.updateVariable(id, "selected", tabKeys.get(tabIndex)
- .toString(), true);
- waitingForResponse = true;
-
- return true;
- }
- return false;
- }
-
- public ApplicationConnection getApplicationConnection() {
- return client;
- }
-
- public void tabSizeMightHaveChanged(Tab tab) {
- // icon onloads may change total width of tabsheet
- if (isDynamicWidth()) {
- updateDynamicWidth();
- }
- updateTabScroller();
-
- }
-
- void sendTabClosedEvent(int tabIndex) {
- client.updateVariable(id, "close", tabKeys.get(tabIndex), true);
- }
-
- boolean isDynamicWidth() {
- ComponentConnector paintable = ConnectorMap.get(client).getConnector(
- this);
- return paintable.isUndefinedWidth();
- }
-
- boolean isDynamicHeight() {
- ComponentConnector paintable = ConnectorMap.get(client).getConnector(
- this);
- return paintable.isUndefinedHeight();
- }
-
- public VTabsheet() {
- super(CLASSNAME);
-
- addHandler(this, FocusEvent.getType());
- addHandler(this, BlurEvent.getType());
-
- // 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");
-
- }
-
- @Override
- public void onBrowserEvent(Event event) {
-
- // Tab scrolling
- if (isScrolledTabs() && DOM.eventGetTarget(event) == scrollerPrev) {
- int newFirstIndex = tb.scrollLeft(scrollerIndex);
- if (newFirstIndex != -1) {
- scrollerIndex = newFirstIndex;
- updateTabScroller();
- }
- } else if (isClippedTabs() && DOM.eventGetTarget(event) == scrollerNext) {
- int newFirstIndex = tb.scrollRight(scrollerIndex);
-
- if (newFirstIndex != -1) {
- scrollerIndex = newFirstIndex;
- updateTabScroller();
- }
- } else {
- super.onBrowserEvent(event);
- }
- }
-
- /**
- * Checks if the tab with the selected index has been scrolled out of the
- * view (on the left side).
- *
- * @param index
- * @return
- */
- private boolean scrolledOutOfView(int index) {
- return scrollerIndex > index;
- }
-
- void handleStyleNames(UIDL uidl, ComponentState state) {
- // Add proper stylenames for all elements (easier to prevent unwanted
- // style inheritance)
- if (state.hasStyles()) {
- final List<String> styles = state.getStyles();
- if (!currentStyle.equals(styles.toString())) {
- currentStyle = styles.toString();
- final String tabsBaseClass = TABS_CLASSNAME;
- String tabsClass = tabsBaseClass;
- final String contentBaseClass = CLASSNAME + "-content";
- String contentClass = contentBaseClass;
- final String decoBaseClass = CLASSNAME + "-deco";
- String decoClass = decoBaseClass;
- for (String style : styles) {
- tb.addStyleDependentName(style);
- tabsClass += " " + tabsBaseClass + "-" + style;
- contentClass += " " + contentBaseClass + "-" + style;
- decoClass += " " + decoBaseClass + "-" + style;
- }
- DOM.setElementProperty(tabs, "className", tabsClass);
- DOM.setElementProperty(contentNode, "className", contentClass);
- DOM.setElementProperty(deco, "className", decoClass);
- borderW = -1;
- }
- } else {
- tb.setStyleName(CLASSNAME + "-tabs");
- DOM.setElementProperty(tabs, "className", TABS_CLASSNAME);
- 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");
- }
- }
-
- void updateDynamicWidth() {
- // Find width consumed by tabs
- TableCellElement spacerCell = ((TableElement) tb.getElement().cast())
- .getRows().getItem(0).getCells().getItem(tb.getTabCount());
-
- int spacerWidth = spacerCell.getOffsetWidth();
- DivElement div = (DivElement) spacerCell.getFirstChildElement();
-
- int spacerMinWidth = spacerCell.getOffsetWidth() - div.getOffsetWidth();
-
- int tabsWidth = tb.getOffsetWidth() - spacerWidth + spacerMinWidth;
-
- // Find content width
- Style style = tp.getElement().getStyle();
- String overflow = style.getProperty("overflow");
- style.setProperty("overflow", "hidden");
- style.setPropertyPx("width", tabsWidth);
-
- boolean hasTabs = tp.getWidgetCount() > 0;
-
- Style wrapperstyle = null;
- if (hasTabs) {
- wrapperstyle = tp.getWidget(tp.getVisibleWidget()).getElement()
- .getParentElement().getStyle();
- wrapperstyle.setPropertyPx("width", tabsWidth);
- }
- // Get content width from actual widget
-
- int contentWidth = 0;
- if (hasTabs) {
- contentWidth = tp.getWidget(tp.getVisibleWidget()).getOffsetWidth();
- }
- style.setProperty("overflow", overflow);
-
- // Set widths to max(tabs,content)
- if (tabsWidth < contentWidth) {
- tabsWidth = contentWidth;
- }
-
- int outerWidth = tabsWidth + getContentAreaBorderWidth();
-
- tabs.getStyle().setPropertyPx("width", outerWidth);
- style.setPropertyPx("width", tabsWidth);
- if (hasTabs) {
- wrapperstyle.setPropertyPx("width", tabsWidth);
- }
-
- contentNode.getStyle().setPropertyPx("width", tabsWidth);
- super.setWidth(outerWidth + "px");
- updateOpenTabSize();
- }
-
- @Override
- protected void renderTab(final UIDL tabUidl, int index, boolean selected,
- boolean hidden) {
- Tab tab = tb.getTab(index);
- if (tab == null) {
- tab = tb.addTab();
- }
- tab.updateFromUIDL(tabUidl);
- tab.setEnabledOnServer((!disabledTabKeys.contains(tabKeys.get(index))));
- tab.setHiddenOnServer(hidden);
-
- if (scrolledOutOfView(index)) {
- // Should not set tabs visible if they are scrolled out of view
- hidden = true;
- }
- // Set the current visibility of the tab (in the browser)
- tab.setVisible(!hidden);
-
- /*
- * Force the width of the caption container so the content will not wrap
- * and tabs won't be too narrow in certain browsers
- */
- tab.recalculateCaptionWidth();
-
- UIDL tabContentUIDL = null;
- ComponentConnector tabContentPaintable = null;
- Widget tabContentWidget = null;
- if (tabUidl.getChildCount() > 0) {
- tabContentUIDL = tabUidl.getChildUIDL(0);
- tabContentPaintable = client.getPaintable(tabContentUIDL);
- tabContentWidget = tabContentPaintable.getWidget();
- }
-
- if (tabContentPaintable != null) {
- /* This is a tab with content information */
-
- int oldIndex = tp.getWidgetIndex(tabContentWidget);
- if (oldIndex != -1 && oldIndex != index) {
- /*
- * The tab has previously been rendered in another position so
- * we must move the cached content to correct position
- */
- tp.insert(tabContentWidget, index);
- }
- } else {
- /* A tab whose content has not yet been loaded */
-
- /*
- * Make sure there is a corresponding empty tab in tp. The same
- * operation as the moving above but for not-loaded tabs.
- */
- if (index < tp.getWidgetCount()) {
- Widget oldWidget = tp.getWidget(index);
- if (!(oldWidget instanceof PlaceHolder)) {
- tp.insert(new PlaceHolder(), index);
- }
- }
-
- }
-
- if (selected) {
- renderContent(tabContentUIDL);
- tb.selectTab(index);
- } else {
- if (tabContentUIDL != null) {
- // updating a drawn child on hidden tab
- if (tp.getWidgetIndex(tabContentWidget) < 0) {
- tp.insert(tabContentWidget, index);
- }
- tabContentPaintable.updateFromUIDL(tabContentUIDL, client);
- } else if (tp.getWidgetCount() <= index) {
- tp.add(new PlaceHolder());
- }
- }
- }
-
- public class PlaceHolder extends VLabel {
- public PlaceHolder() {
- super("");
- }
- }
-
- @Override
- 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 ComponentConnector content = client.getPaintable(contentUIDL);
- Widget newWidget = content.getWidget();
- if (tp.getWidgetCount() > activeTabIndex) {
- Widget old = tp.getWidget(activeTabIndex);
- if (old != newWidget) {
- tp.remove(activeTabIndex);
- ConnectorMap paintableMap = ConnectorMap.get(client);
- if (paintableMap.isConnector(old)) {
- paintableMap.unregisterConnector(paintableMap
- .getConnector(old));
- }
- tp.insert(content.getWidget(), activeTabIndex);
- }
- } else {
- tp.add(content.getWidget());
- }
-
- tp.showWidget(activeTabIndex);
-
- VTabsheet.this.iLayout();
- content.updateFromUIDL(contentUIDL, client);
- /*
- * The size of a cached, relative sized component must be updated to
- * report correct size to updateOpenTabSize().
- */
- if (contentUIDL.getBooleanAttribute("cached")) {
- client.handleComponentRelativeSize(content.getWidget());
- }
- updateOpenTabSize();
- VTabsheet.this.removeStyleDependentName("loading");
- }
-
- void updateContentNodeHeight() {
- if (!isDynamicHeight()) {
- int contentHeight = getOffsetHeight();
- contentHeight -= DOM.getElementPropertyInt(deco, "offsetHeight");
- contentHeight -= tb.getOffsetHeight();
- if (contentHeight < 0) {
- contentHeight = 0;
- }
-
- // Set proper values for content element
- DOM.setStyleAttribute(contentNode, "height", contentHeight + "px");
- } else {
- DOM.setStyleAttribute(contentNode, "height", "");
- }
- }
-
- public void iLayout() {
- updateTabScroller();
- tp.runWebkitOverflowAutoFix();
- }
-
- /**
- * Sets the size of the visible tab (component). As the tab is set to
- * position: absolute (to work around a firefox flickering bug) we must keep
- * this up-to-date by hand.
- */
- void updateOpenTabSize() {
- /*
- * The overflow=auto element must have a height specified, otherwise it
- * will be just as high as the contents and no scrollbars will appear
- */
- int height = -1;
- int width = -1;
- int minWidth = 0;
-
- if (!isDynamicHeight()) {
- height = contentNode.getOffsetHeight();
- }
- if (!isDynamicWidth()) {
- width = contentNode.getOffsetWidth() - getContentAreaBorderWidth();
- } else {
- /*
- * If the tabbar is wider than the content we need to use the tabbar
- * width as minimum width so scrollbars get placed correctly (at the
- * right edge).
- */
- minWidth = tb.getOffsetWidth() - getContentAreaBorderWidth();
- }
- tp.fixVisibleTabSize(width, height, minWidth);
-
- }
-
- /**
- * Layouts the tab-scroller elements, and applies styles.
- */
- private void updateTabScroller() {
- if (!isDynamicWidth()) {
- ComponentConnector paintable = ConnectorMap.get(client)
- .getConnector(this);
- DOM.setStyleAttribute(tabs, "width", paintable.getState()
- .getWidth());
- }
-
- // Make sure scrollerIndex is valid
- if (scrollerIndex < 0 || scrollerIndex > tb.getTabCount()) {
- scrollerIndex = tb.getFirstVisibleTab();
- } else if (tb.getTabCount() > 0
- && tb.getTab(scrollerIndex).isHiddenOnServer()) {
- scrollerIndex = tb.getNextVisibleTab(scrollerIndex);
- }
-
- boolean scrolled = isScrolledTabs();
- boolean clipped = isClippedTabs();
- if (tb.getTabCount() > 0 && 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");
- }
-
- if (BrowserInfo.get().isSafari()) {
- // fix tab height for safari, bugs sometimes if tabs contain icons
- String property = tabs.getStyle().getProperty("height");
- if (property == null || property.equals("")) {
- tabs.getStyle().setPropertyPx("height", tb.getOffsetHeight());
- }
- /*
- * another hack for webkits. tabscroller sometimes drops without
- * "shaking it" reproducable in
- * com.vaadin.tests.components.tabsheet.TabSheetIcons
- */
- final Style style = scroller.getStyle();
- style.setProperty("whiteSpace", "normal");
- Scheduler.get().scheduleDeferred(new Command() {
- public void execute() {
- style.setProperty("whiteSpace", "");
- }
- });
- }
-
- }
-
- void showAllTabs() {
- scrollerIndex = tb.getFirstVisibleTab();
- for (int i = 0; i < tb.getTabCount(); i++) {
- Tab t = tb.getTab(i);
- if (!t.isHiddenOnServer()) {
- t.setVisible(true);
- }
- }
- }
-
- private boolean isScrolledTabs() {
- return scrollerIndex > tb.getFirstVisibleTab();
- }
-
- private boolean isClippedTabs() {
- return (tb.getOffsetWidth() - DOM.getElementPropertyInt((Element) tb
- .getContainerElement().getLastChild().cast(), "offsetWidth")) > getOffsetWidth()
- - (isScrolledTabs() ? scroller.getOffsetWidth() : 0);
- }
-
- @Override
- protected void clearPaintables() {
-
- int i = tb.getTabCount();
- while (i > 0) {
- tb.removeTab(--i);
- }
- tp.clear();
-
- }
-
- @Override
- protected Iterator<Widget> getWidgetIterator() {
- return tp.iterator();
- }
-
- private int borderW = -1;
-
- int getContentAreaBorderWidth() {
- if (borderW < 0) {
- borderW = Util.measureHorizontalBorder(contentNode);
- }
- return borderW;
- }
-
- @Override
- protected int getTabCount() {
- return tb.getTabCount();
- }
-
- @Override
- protected ComponentConnector getTab(int index) {
- if (tp.getWidgetCount() > index) {
- Widget widget = tp.getWidget(index);
- return ConnectorMap.get(client).getConnector(widget);
- }
- return null;
- }
-
- @Override
- protected void removeTab(int index) {
- tb.removeTab(index);
- /*
- * This must be checked because renderTab automatically removes the
- * active tab content when it changes
- */
- if (tp.getWidgetCount() > index) {
- tp.remove(index);
- }
- }
-
- public void onBlur(BlurEvent event) {
- if (focusedTab != null && event.getSource() instanceof Tab) {
- focusedTab = null;
- if (client.hasEventListeners(this, EventId.BLUR)) {
- client.updateVariable(id, EventId.BLUR, "", true);
- }
- }
- }
-
- public void onFocus(FocusEvent event) {
- if (focusedTab == null && event.getSource() instanceof Tab) {
- focusedTab = (Tab) event.getSource();
- if (client.hasEventListeners(this, EventId.FOCUS)) {
- client.updateVariable(id, EventId.FOCUS, "", true);
- }
- }
- }
-
- public void focus() {
- tb.getTab(activeTabIndex).focus();
- }
-
- public void blur() {
- tb.getTab(activeTabIndex).blur();
- }
-
- public void onKeyDown(KeyDownEvent event) {
- if (event.getSource() instanceof Tab) {
- int keycode = event.getNativeEvent().getKeyCode();
-
- if (keycode == getPreviousTabKey()) {
- int newTabIndex = activeTabIndex;
- // Find the previous non-disabled tab with wraparound.
- do {
- newTabIndex = (newTabIndex != 0) ? newTabIndex - 1 : tb
- .getTabCount() - 1;
- } while (newTabIndex != activeTabIndex
- && !onTabSelected(newTabIndex));
- activeTabIndex = newTabIndex;
-
- // Tab scrolling
- if (isScrolledTabs()) {
- int newFirstIndex = tb.scrollLeft(scrollerIndex);
- if (newFirstIndex != -1) {
- scrollerIndex = newFirstIndex;
- updateTabScroller();
- }
- }
-
- } else if (keycode == getNextTabKey()) {
- int newTabIndex = activeTabIndex;
- // Find the next non-disabled tab with wraparound.
- do {
- newTabIndex = (newTabIndex + 1) % tb.getTabCount();
- } while (newTabIndex != activeTabIndex
- && !onTabSelected(newTabIndex));
- activeTabIndex = newTabIndex;
-
- if (isClippedTabs()) {
- int newFirstIndex = tb.scrollRight(scrollerIndex);
- if (newFirstIndex != -1) {
- scrollerIndex = newFirstIndex;
- updateTabScroller();
- }
- }
-
- } else if (keycode == getCloseTabKey()) {
- Tab tab = tb.getTab(activeTabIndex);
- if (tab.isClosable()) {
- tab.onClose();
- removeTab(activeTabIndex);
- }
- }
- }
- }
-
- protected int getPreviousTabKey() {
- return KeyCodes.KEY_LEFT;
- }
-
- protected int getNextTabKey() {
- return KeyCodes.KEY_RIGHT;
- }
-
- protected int getCloseTabKey() {
- return KeyCodes.KEY_DELETE;
- }
- }
|