diff options
author | Felype Santiago Ferreira <felype@vaadin.com> | 2014-02-26 16:05:37 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2014-04-08 06:34:55 +0000 |
commit | f32e3535c6ef73bca33f274e9906f57aa178d22a (patch) | |
tree | ba2453a82f97a2c68f35d363ed2c553d84d5bae9 /client | |
parent | ef8920661cc9d958c69cfedd0a74ce580a2a84ed (diff) | |
download | vaadin-framework-f32e3535c6ef73bca33f274e9906f57aa178d22a.tar.gz vaadin-framework-f32e3535c6ef73bca33f274e9906f57aa178d22a.zip |
Update Accordion and TabSheet to use Vaadin 7 style. (#13402).
This change also adds subpart support for TabSheet and
converts a test to TB3.
Change-Id: I23b6c81686ea6587470d8019e89a85149ec0b068
Diffstat (limited to 'client')
6 files changed, 472 insertions, 308 deletions
diff --git a/client/src/com/vaadin/client/ui/VAccordion.java b/client/src/com/vaadin/client/ui/VAccordion.java index eb8cb8b2ed..cba08d8e6b 100644 --- a/client/src/com/vaadin/client/ui/VAccordion.java +++ b/client/src/com/vaadin/client/ui/VAccordion.java @@ -15,7 +15,6 @@ */ package com.vaadin.client.ui; -import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Set; @@ -28,43 +27,41 @@ import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ComponentConnector; -import com.vaadin.client.ConnectorMap; -import com.vaadin.client.UIDL; import com.vaadin.client.Util; import com.vaadin.client.VCaption; import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler; -import com.vaadin.shared.ui.tabsheet.TabsheetBaseConstants; -import com.vaadin.shared.ui.tabsheet.TabsheetConstants; +import com.vaadin.shared.ComponentConstants; +import com.vaadin.shared.ui.accordion.AccordionState; +import com.vaadin.shared.ui.tabsheet.TabState; +import com.vaadin.shared.ui.tabsheet.TabsheetServerRpc; public class VAccordion extends VTabsheetBase { - public static final String CLASSNAME = "v-accordion"; + public static final String CLASSNAME = AccordionState.PRIMARY_STYLE_NAME; private Set<Widget> widgets = new HashSet<Widget>(); - /** For internal use only. May be removed or replaced in the future. */ - public HashMap<StackItem, UIDL> lazyUpdateMap = new HashMap<StackItem, UIDL>(); - - private StackItem openTab = null; + private StackItem openTab; /** For internal use only. May be removed or replaced in the future. */ - public int selectedUIDLItemIndex = -1; + public int selectedItemIndex = -1; private final TouchScrollHandler touchScrollHandler; public VAccordion() { super(CLASSNAME); + touchScrollHandler = TouchScrollDelegate.enableTouchScrolling(this); } @Override - public void renderTab(UIDL tabUidl, int index, boolean selected, - boolean hidden) { + public void renderTab(TabState tabState, int index) { StackItem item; int itemIndex; + if (getWidgetCount() <= index) { // Create stackItem and render caption - item = new StackItem(tabUidl); + item = new StackItem(); if (getWidgetCount() == 0) { item.addStyleDependentName("first"); } @@ -72,23 +69,19 @@ public class VAccordion extends VTabsheetBase { add(item, getElement()); } else { item = getStackItem(index); - item = moveStackItemIfNeeded(item, index, tabUidl); + itemIndex = index; } - item.updateCaption(tabUidl); + item.updateCaption(tabState); - item.updateTabStyleName(tabUidl - .getStringAttribute(TabsheetConstants.TAB_STYLE_NAME)); + item.updateTabStyleName(tabState.styleName); - item.setVisible(!hidden); - - if (selected) { - selectedUIDLItemIndex = itemIndex; - } + item.setVisible(tabState.visible); + } - if (tabUidl.getChildCount() > 0) { - lazyUpdateMap.put(item, tabUidl.getChildUIDL(0)); - } + @Override + public void selectTab(int index) { + selectedItemIndex = index; } @Override @@ -112,69 +105,6 @@ public class VAccordion extends VTabsheetBase { } } - /** - * This method tries to find out if a tab has been rendered with a different - * index previously. If this is the case it re-orders the children so the - * same StackItem is used for rendering this time. E.g. if the first tab has - * been removed all tabs which contain cached content must be moved 1 step - * up to preserve the cached content. - * - * @param item - * @param newIndex - * @param tabUidl - * @return - */ - private StackItem moveStackItemIfNeeded(StackItem item, int newIndex, - UIDL tabUidl) { - UIDL tabContentUIDL = null; - ComponentConnector tabContent = null; - if (tabUidl.getChildCount() > 0) { - tabContentUIDL = tabUidl.getChildUIDL(0); - tabContent = client.getPaintable(tabContentUIDL); - } - - Widget itemWidget = item.getComponent(); - if (tabContent != null) { - if (tabContent.getWidget() != itemWidget) { - /* - * This is not the same widget as before, find out if it has - * been moved - */ - int oldIndex = -1; - StackItem oldItem = null; - for (int i = 0; i < getWidgetCount(); i++) { - Widget w = getWidget(i); - oldItem = (StackItem) w; - if (tabContent == oldItem.getComponent()) { - oldIndex = i; - break; - } - } - - if (oldIndex != -1 && oldIndex > newIndex) { - /* - * The tab has previously been rendered in another position - * so we must move the cached content to correct position. - * We move only items with oldIndex > newIndex to prevent - * moving items already rendered in this update. If for - * instance tabs 1,2,3 are removed and added as 3,2,1 we - * cannot re-use "1" when we get to the third tab. - */ - insert(oldItem, getElement(), newIndex, true); - return oldItem; - } - } - } else { - // Tab which has never been loaded. Must assure we use an empty - // StackItem - Widget oldWidget = item.getComponent(); - if (oldWidget != null) { - oldWidget.removeFromParent(); - } - } - return item; - } - /** For internal use only. May be removed or replaced in the future. */ public void open(int itemIndex) { StackItem item = (StackItem) getWidget(itemIndex); @@ -210,10 +140,14 @@ public class VAccordion extends VTabsheetBase { public void onSelectTab(StackItem item) { final int index = getWidgetIndex(item); + if (index != activeTabIndex && !disabled && !readonly && !disabledTabKeys.contains(tabKeys.get(index))) { + addStyleDependentName("loading"); - client.updateVariable(id, "selected", "" + tabKeys.get(index), true); + + connector.getRpcProxy(TabsheetServerRpc.class).setSelected( + tabKeys.get(index).toString()); } } @@ -296,7 +230,7 @@ public class VAccordion extends VTabsheetBase { private Element captionNode = DOM.createDiv(); private String styleName; - public StackItem(UIDL tabUidl) { + public StackItem() { setElement(DOM.createDiv()); caption = new VCaption(client); caption.addClickHandler(this); @@ -375,10 +309,17 @@ public class VAccordion extends VTabsheetBase { return open; } - public void setContent(UIDL contentUidl) { - final ComponentConnector newPntbl = client - .getPaintable(contentUidl); - Widget newWidget = newPntbl.getWidget(); + /** + * Updates the content of the open tab of the accordion. + * + * This method is mostly for internal use and may change in future + * versions. + * + * @since 7.2 + * @param newWidget + * new content + */ + public void setContent(Widget newWidget) { if (getChildWidget() == null) { add(newWidget, content); widgets.add(newWidget); @@ -395,14 +336,19 @@ public class VAccordion extends VTabsheetBase { onSelectTab(this); } - public void updateCaption(UIDL uidl) { + public void updateCaption(TabState tabState) { // TODO need to call this because the caption does not have an owner caption.updateCaptionWithoutOwner( - uidl.getStringAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_CAPTION), - uidl.hasAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_DISABLED), - uidl.hasAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_DESCRIPTION), - uidl.hasAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_ERROR_MESSAGE), - uidl.getStringAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_ICON)); + tabState.caption, + !tabState.enabled, + hasAttribute(tabState.description), + hasAttribute(tabState.componentError), + connector.getResourceUrl(ComponentConstants.ICON_RESOURCE + + tabState.key)); + } + + private boolean hasAttribute(String string) { + return string != null && !string.trim().isEmpty(); } /** @@ -450,18 +396,6 @@ public class VAccordion extends VTabsheetBase { clear(); } - boolean isDynamicWidth() { - ComponentConnector paintable = ConnectorMap.get(client).getConnector( - this); - return paintable.isUndefinedWidth(); - } - - boolean isDynamicHeight() { - ComponentConnector paintable = ConnectorMap.get(client).getConnector( - this); - return paintable.isUndefinedHeight(); - } - @Override public Iterator<Widget> getWidgetIterator() { return widgets.iterator(); @@ -488,7 +422,7 @@ public class VAccordion extends VTabsheetBase { } Widget w = stackItem.getChildWidget(); if (w != null) { - return ConnectorMap.get(client).getConnector(w); + return getConnectorForWidget(w); } } diff --git a/client/src/com/vaadin/client/ui/VTabsheet.java b/client/src/com/vaadin/client/ui/VTabsheet.java index 4da5e4bfe0..f2e4003e7f 100644 --- a/client/src/com/vaadin/client/ui/VTabsheet.java +++ b/client/src/com/vaadin/client/ui/VTabsheet.java @@ -43,6 +43,8 @@ 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.regexp.shared.MatchResult; +import com.google.gwt.regexp.shared.RegExp; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; @@ -53,21 +55,23 @@ import com.google.gwt.user.client.ui.impl.FocusImpl; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.BrowserInfo; import com.vaadin.client.ComponentConnector; -import com.vaadin.client.ConnectorMap; import com.vaadin.client.Focusable; import com.vaadin.client.TooltipInfo; -import com.vaadin.client.UIDL; import com.vaadin.client.Util; import com.vaadin.client.VCaption; +import com.vaadin.client.VTooltip; import com.vaadin.client.ui.aria.AriaHelper; import com.vaadin.shared.AbstractComponentState; +import com.vaadin.shared.ComponentConstants; import com.vaadin.shared.EventId; +import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc; import com.vaadin.shared.ui.ComponentStateUtil; -import com.vaadin.shared.ui.tabsheet.TabsheetBaseConstants; -import com.vaadin.shared.ui.tabsheet.TabsheetConstants; +import com.vaadin.shared.ui.tabsheet.TabState; +import com.vaadin.shared.ui.tabsheet.TabsheetServerRpc; +import com.vaadin.shared.ui.tabsheet.TabsheetState; public class VTabsheet extends VTabsheetBase implements Focusable, - FocusHandler, BlurHandler, KeyDownHandler { + FocusHandler, BlurHandler, KeyDownHandler, SubPartAware { private static class VCloseEvent { private Tab tab; @@ -140,8 +144,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, DOM.appendChild(td, div); - tabCaption = new TabCaption(this, getTabsheet() - .getApplicationConnection()); + tabCaption = new TabCaption(this); add(tabCaption); Roles.getTabRole().setAriaLabelledbyProperty(getElement(), @@ -228,12 +231,10 @@ public class VTabsheet extends VTabsheetBase implements Focusable, return tabBar.getTabsheet(); } - public void updateFromUIDL(UIDL tabUidl) { - tabCaption.updateCaption(tabUidl); - + private void updateFromState(TabState tabState) { + tabCaption.update(tabState); // Apply the styleName set for the tab - String newStyleName = tabUidl - .getStringAttribute(TabsheetConstants.TAB_STYLE_NAME); + String newStyleName = tabState.styleName; // Find the nth td element if (newStyleName != null && !newStyleName.isEmpty()) { if (!newStyleName.equals(styleName)) { @@ -253,7 +254,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, styleName = null; } - String newId = tabUidl.getStringAttribute("id"); + String newId = tabState.id; if (newId != null && !newId.isEmpty()) { td.setId(newId); id = newId; @@ -315,38 +316,45 @@ public class VTabsheet extends VTabsheetBase implements Focusable, private Element closeButton; private Tab tab; - TabCaption(Tab tab, ApplicationConnection client) { - super(client); + TabCaption(Tab tab) { + super(tab.getTabsheet().connector.getConnection()); this.tab = tab; AriaHelper.ensureHasId(getElement()); } - public boolean updateCaption(UIDL uidl) { - if (uidl.hasAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_DESCRIPTION) - || uidl.hasAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_ERROR_MESSAGE)) { - setTooltipInfo(new TooltipInfo( - uidl.getStringAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_DESCRIPTION), - uidl.getStringAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_ERROR_MESSAGE))); + private boolean update(TabState tabState) { + if (tabState.description != null + || tabState.componentError != null) { + setTooltipInfo(new TooltipInfo(tabState.description, + tabState.componentError)); } else { setTooltipInfo(null); } // TODO need to call this instead of super because the caption does // not have an owner - boolean ret = updateCaptionWithoutOwner( - uidl.getStringAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_CAPTION), - uidl.hasAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_DISABLED), - uidl.hasAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_DESCRIPTION), - uidl.hasAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_ERROR_MESSAGE), - uidl.getStringAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_ICON), - uidl.getStringAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_ICON_ALT)); - - setClosable(uidl.hasAttribute("closable")); + String captionString = tabState.caption.isEmpty() ? null + : tabState.caption; + boolean ret = updateCaptionWithoutOwner(captionString, + !tabState.enabled, + hasAttribute(tabState.description), + hasAttribute(tabState.componentError), + tab.getTabsheet().connector + .getResourceUrl(ComponentConstants.ICON_RESOURCE + + tabState.key), + tabState.iconAltText + ); + + setClosable(tabState.closable); return ret; } + private boolean hasAttribute(String string) { + return string != null && !string.trim().isEmpty(); + } + private VTabsheet getTabsheet() { return tab.getTabsheet(); } @@ -637,12 +645,21 @@ public class VTabsheet extends VTabsheetBase implements Focusable, currentFirst.recalculateCaptionWidth(); return nextVisible; } + + private void recalculateCaptionWidths() { + for (int i = 0; i < getTabCount(); ++i) { + getTab(i).recalculateCaptionWidth(); + } + } } - public static final String CLASSNAME = "v-tabsheet"; + // TODO using the CLASSNAME directly makes primaryStyleName for TabSheet of + // very limited use - all use of style names should be refactored in the + // future + public static final String CLASSNAME = TabsheetState.PRIMARY_STYLE_NAME; - public static final String TABS_CLASSNAME = "v-tabsheet-tabcontainer"; - public static final String SCROLLER_CLASSNAME = "v-tabsheet-scroller"; + public static final String TABS_CLASSNAME = CLASSNAME + "-tabcontainer"; + public static final String SCROLLER_CLASSNAME = CLASSNAME + "-scroller"; /** For internal use only. May be removed or replaced in the future. */ // tabbar and 'scroller' container @@ -670,7 +687,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, final TabBar tb = new TabBar(this); /** For internal use only. May be removed or replaced in the future. */ - public final VTabsheetPanel tp = new VTabsheetPanel(); + protected final VTabsheetPanel tabPanel = new VTabsheetPanel(); /** For internal use only. May be removed or replaced in the future. */ public final Element contentNode; @@ -681,12 +698,16 @@ public class VTabsheet extends VTabsheetBase implements Focusable, private String currentStyle; + /** For internal use only. May be removed or replaced in the future. */ + private int focusedTabIndex = 0; + /** * @return Whether the tab could be selected or not. */ private boolean canSelectTab(final int tabIndex) { Tab tab = tb.getTab(tabIndex); - if (client == null || disabled || waitingForResponse) { + if (getApplicationConnection() == null || disabled + || waitingForResponse) { return false; } if (!tab.isEnabledOnServer() || tab.isHiddenOnServer()) { @@ -713,22 +734,56 @@ public class VTabsheet extends VTabsheetBase implements Focusable, 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); + getCurrentlyDisplayedWidget().getElement().getParentElement() + .getStyle().setVisibility(Visibility.HIDDEN); + + getRpcProxy().setSelected(tabKeys.get(tabIndex).toString()); + waitingForResponse = true; tb.getTab(tabIndex).focus(); // move keyboard focus to active tab } } + /** + * Returns the currently displayed widget in the tab panel. + * + * @since 7.2 + * @return currently displayed content widget + */ + public Widget getCurrentlyDisplayedWidget() { + return tabPanel.getWidget(tabPanel.getVisibleWidget()); + } + + /** + * Returns the client to server RPC proxy for the tabsheet. + * + * @since 7.2 + * @return RPC proxy + */ + protected TabsheetServerRpc getRpcProxy() { + return connector.getRpcProxy(TabsheetServerRpc.class); + } + + /** + * For internal use only. + * + * Avoid using this method directly and use appropriate superclass methods + * where applicable. + * + * @deprecated since 7.2 - use more specific methods instead (getRpcProxy(), + * getConnectorForWidget(Widget) etc.) + * @return ApplicationConnection + */ + @Deprecated public ApplicationConnection getApplicationConnection() { return client; } + private VTooltip getVTooltip() { + return getApplicationConnection().getVTooltip(); + } + public void tabSizeMightHaveChanged(Tab tab) { // icon onloads may change total width of tabsheet if (isDynamicWidth()) { @@ -739,19 +794,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } 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(); + getRpcProxy().closeTab(tabKeys.get(tabIndex)); } public VTabsheet() { @@ -785,7 +828,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, DOM.appendChild(getElement(), tabs); // Tabs - tp.setStyleName(CLASSNAME + "-tabsheetpanel"); + tabPanel.setStyleName(CLASSNAME + "-tabsheetpanel"); contentNode = DOM.createDiv(); Roles.getTabpanelRole().set(contentNode); @@ -801,7 +844,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, DOM.appendChild(scroller, scrollerNext); DOM.appendChild(getElement(), contentNode); - add(tp, contentNode); + add(tabPanel, contentNode); DOM.appendChild(getElement(), deco); DOM.appendChild(tabs, scroller); @@ -851,7 +894,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } /** For internal use only. May be removed or replaced in the future. */ - public void handleStyleNames(UIDL uidl, AbstractComponentState state) { + public void handleStyleNames(AbstractComponentState state) { // Add proper stylenames for all elements (easier to prevent unwanted // style inheritance) if (ComponentStateUtil.hasStyles(state)) { @@ -882,14 +925,6 @@ public class VTabsheet extends VTabsheetBase implements Focusable, + "-content"); DOM.setElementProperty(deco, "className", CLASSNAME + "-deco"); } - - if (uidl.hasAttribute("hidetabs")) { - tb.setVisible(false); - addStyleName(CLASSNAME + "-hidetabs"); - } else { - tb.setVisible(true); - removeStyleName(CLASSNAME + "-hidetabs"); - } } /** For internal use only. May be removed or replaced in the future. */ @@ -906,16 +941,16 @@ public class VTabsheet extends VTabsheetBase implements Focusable, int tabsWidth = tb.getOffsetWidth() - spacerWidth + spacerMinWidth; // Find content width - Style style = tp.getElement().getStyle(); + Style style = tabPanel.getElement().getStyle(); String overflow = style.getProperty("overflow"); style.setProperty("overflow", "hidden"); style.setPropertyPx("width", tabsWidth); - boolean hasTabs = tp.getWidgetCount() > 0; + boolean hasTabs = tabPanel.getWidgetCount() > 0; Style wrapperstyle = null; if (hasTabs) { - wrapperstyle = tp.getWidget(tp.getVisibleWidget()).getElement() + wrapperstyle = getCurrentlyDisplayedWidget().getElement() .getParentElement().getStyle(); wrapperstyle.setPropertyPx("width", tabsWidth); } @@ -923,7 +958,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, int contentWidth = 0; if (hasTabs) { - contentWidth = tp.getWidget(tp.getVisibleWidget()).getOffsetWidth(); + contentWidth = getCurrentlyDisplayedWidget().getOffsetWidth(); } style.setProperty("overflow", overflow); @@ -946,26 +981,22 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } @Override - public void renderTab(final UIDL tabUidl, int index, boolean selected, - boolean hidden) { + public void renderTab(final TabState tabState, int index) { Tab tab = tb.getTab(index); if (tab == null) { tab = tb.addTab(); } - if (selected) { - tb.selectTab(index); - renderContent(tabUidl.getChildUIDL(0)); - } - tab.updateFromUIDL(tabUidl); + + tab.updateFromState(tabState); tab.setEnabledOnServer((!disabledTabKeys.contains(tabKeys.get(index)))); - tab.setHiddenOnServer(hidden); + tab.setHiddenOnServer(!tabState.visible); if (scrolledOutOfView(index)) { // Should not set tabs visible if they are scrolled out of view - hidden = true; + tabState.visible = false; } // Set the current visibility of the tab (in the browser) - tab.setVisible(!hidden); + tab.setVisible(tabState.visible); /* * Force the width of the caption container so the content will not wrap @@ -985,23 +1016,29 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } } - private void renderContent(final UIDL contentUIDL) { - final ComponentConnector content = client.getPaintable(contentUIDL); - Widget newWidget = content.getWidget(); + /** + * Renders the widget content for a tab sheet. + * + * @param newWidget + */ + public void renderContent(Widget newWidget) { + assert tabPanel.getWidgetCount() <= 1; - assert tp.getWidgetCount() <= 1; + if (null == newWidget) { + newWidget = new SimplePanel(); + } - if (tp.getWidgetCount() == 0) { - tp.add(newWidget); - } else if (tp.getWidget(0) != newWidget) { - tp.remove(0); - tp.add(newWidget); + if (tabPanel.getWidgetCount() == 0) { + tabPanel.add(newWidget); + } else if (tabPanel.getWidget(0) != newWidget) { + tabPanel.remove(0); + tabPanel.add(newWidget); } - assert tp.getWidgetCount() <= 1; + assert tabPanel.getWidgetCount() <= 1; // There's never any other index than 0, but maintaining API for now - tp.showWidget(0); + tabPanel.showWidget(0); VTabsheet.this.iLayout(); updateOpenTabSize(); @@ -1058,7 +1095,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, */ minWidth = tb.getOffsetWidth() - getContentAreaBorderWidth(); } - tp.fixVisibleTabSize(width, height, minWidth); + tabPanel.fixVisibleTabSize(width, height, minWidth); } @@ -1149,13 +1186,13 @@ public class VTabsheet extends VTabsheetBase implements Focusable, while (i > 0) { tb.removeTab(--i); } - tp.clear(); + tabPanel.clear(); } @Override public Iterator<Widget> getWidgetIterator() { - return tp.iterator(); + return tabPanel.iterator(); } private int borderW = -1; @@ -1175,9 +1212,9 @@ public class VTabsheet extends VTabsheetBase implements Focusable, @Override public ComponentConnector getTab(int index) { - if (tp.getWidgetCount() > index) { - Widget widget = tp.getWidget(index); - return ConnectorMap.get(client).getConnector(widget); + if (tabPanel.getWidgetCount() > index) { + Widget widget = tabPanel.getWidget(index); + return getConnectorForWidget(widget); } return null; } @@ -1190,14 +1227,19 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } @Override + public void selectTab(int index) { + tb.selectTab(index); + } + + @Override public void onBlur(BlurEvent event) { - getApplicationConnection().getVTooltip().hideTooltip(); + getVTooltip().hideTooltip(); if (focusedTab != null && focusedTab == event.getSource()) { focusedTab.removeAssistiveDescription(); focusedTab = null; - if (client.hasEventListeners(this, EventId.BLUR)) { - client.updateVariable(id, EventId.BLUR, "", true); + if (connector.hasEventListener(EventId.BLUR)) { + connector.getRpcProxy(FocusAndBlurServerRpc.class).blur(); } } } @@ -1206,15 +1248,13 @@ public class VTabsheet extends VTabsheetBase implements Focusable, 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); + if (connector.hasEventListener(EventId.FOCUS)) { + connector.getRpcProxy(FocusAndBlurServerRpc.class).focus(); } if (focusedTab.hasTooltip()) { - focusedTab.setAssistiveDescription(getApplicationConnection() - .getVTooltip().getUniqueId()); - getApplicationConnection().getVTooltip().showAssistive( - focusedTab.getTooltipInfo()); + focusedTab.setAssistiveDescription(getVTooltip().getUniqueId()); + getVTooltip().showAssistive(focusedTab.getTooltipInfo()); } } } @@ -1336,4 +1376,70 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } } } + + /** + * Makes tab bar visible. + * + * @since 7.2 + */ + public void showTabs() { + tb.setVisible(true); + removeStyleName(CLASSNAME + "-hidetabs"); + tb.recalculateCaptionWidths(); + } + + /** + * Makes tab bar invisible. + * + * @since 7.2 + */ + public void hideTabs() { + tb.setVisible(false); + addStyleName(CLASSNAME + "-hidetabs"); + } + + /** Matches tab[ix] - used for extracting the index of the targeted tab */ + private static final RegExp SUBPART_TAB_REGEXP = RegExp + .compile("tab\\[(\\d+)](.*)"); + + @Override + public com.google.gwt.user.client.Element getSubPartElement(String subPart) { + if ("tabpanel".equals(subPart)) { + return DOM.asOld(tabPanel.getElement().getFirstChildElement()); + } else if (SUBPART_TAB_REGEXP.test(subPart)) { + MatchResult result = SUBPART_TAB_REGEXP.exec(subPart); + int tabIx = Integer.valueOf(result.getGroup(1)); + Tab tab = tb.getTab(tabIx); + if (tab != null) { + if ("/close".equals(result.getGroup(2))) { + if (tab.isClosable()) { + return tab.tabCaption.getCloseButton(); + } + } else { + return tab.tabCaption.getElement(); + } + } + } + return null; + } + + @Override + public String getSubPartName(com.google.gwt.user.client.Element subElement) { + if (tabPanel.getElement().equals(subElement.getParentElement()) + || tabPanel.getElement().equals(subElement)) { + return "tabpanel"; + } else { + for (int i = 0; i < tb.getTabCount(); ++i) { + Tab tab = tb.getTab(i); + if (tab.isClosable() + && tab.tabCaption.getCloseButton().isOrHasChild( + subElement)) { + return "tab[" + i + "]/close"; + } else if (tab.getElement().isOrHasChild(subElement)) { + return "tab[" + i + "]"; + } + } + } + return null; + } } diff --git a/client/src/com/vaadin/client/ui/VTabsheetBase.java b/client/src/com/vaadin/client/ui/VTabsheetBase.java index bcd8811c7d..6d9f78e87f 100644 --- a/client/src/com/vaadin/client/ui/VTabsheetBase.java +++ b/client/src/com/vaadin/client/ui/VTabsheetBase.java @@ -25,28 +25,28 @@ import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ComponentConnector; -import com.vaadin.client.UIDL; +import com.vaadin.client.ConnectorMap; +import com.vaadin.shared.ui.tabsheet.TabState; public abstract class VTabsheetBase extends ComplexPanel { /** For internal use only. May be removed or replaced in the future. */ - public String id; - /** For internal use only. May be removed or replaced in the future. */ - public ApplicationConnection client; + protected ApplicationConnection client; /** For internal use only. May be removed or replaced in the future. */ - public final ArrayList<String> tabKeys = new ArrayList<String>(); + protected final ArrayList<String> tabKeys = new ArrayList<String>(); /** For internal use only. May be removed or replaced in the future. */ - public Set<String> disabledTabKeys = new HashSet<String>(); + protected Set<String> disabledTabKeys = new HashSet<String>(); /** For internal use only. May be removed or replaced in the future. */ - public int activeTabIndex = 0; + protected int activeTabIndex = 0; /** For internal use only. May be removed or replaced in the future. */ - public int focusedTabIndex = 0; + protected boolean disabled; /** For internal use only. May be removed or replaced in the future. */ - public boolean disabled; + protected boolean readonly; + /** For internal use only. May be removed or replaced in the future. */ - public boolean readonly; + protected AbstractComponentConnector connector; public VTabsheetBase(String classname) { setElement(DOM.createDiv()); @@ -61,14 +61,13 @@ public abstract class VTabsheetBase extends ComplexPanel { /** * Clears current tabs and contents */ - abstract protected void clearPaintables(); + protected abstract void clearPaintables(); /** * Implement in extending classes. This method should render needed elements * and set the visibility of the tab according to the 'selected' parameter. */ - public abstract void renderTab(final UIDL tabUidl, int index, - boolean selected, boolean hidden); + public abstract void renderTab(TabState tabState, int index); /** * Implement in extending classes. This method should return the number of @@ -87,4 +86,79 @@ public abstract class VTabsheetBase extends ComplexPanel { * tab with the specified index. */ public abstract void removeTab(int index); + + /** + * Returns true if the width of the widget is undefined, false otherwise. + * + * @since 7.2 + * @return true if width of the widget is determined by its content + */ + protected boolean isDynamicWidth() { + return getConnectorForWidget(this).isUndefinedWidth(); + } + + /** + * Returns true if the height of the widget is undefined, false otherwise. + * + * @since 7.2 + * @return true if width of the height is determined by its content + */ + protected boolean isDynamicHeight() { + return getConnectorForWidget(this).isUndefinedHeight(); + } + + /** + * Sets the connector that should be notified of events etc. + * + * For internal use only. This method may be removed or replaced in the + * future. + * + * @since 7.2 + * @param connector + */ + public void setConnector(AbstractComponentConnector connector) { + this.connector = connector; + } + + /** For internal use only. May be removed or replaced in the future. */ + public void clearTabKeys() { + tabKeys.clear(); + disabledTabKeys.clear(); + } + + /** For internal use only. May be removed or replaced in the future. */ + public void addTabKey(String key, boolean disabled) { + tabKeys.add(key); + if (disabled) { + disabledTabKeys.add(key); + } + } + + /** For internal use only. May be removed or replaced in the future. */ + public void setClient(ApplicationConnection client) { + this.client = client; + } + + /** For internal use only. May be removed or replaced in the future. */ + public void setActiveTabIndex(int activeTabIndex) { + this.activeTabIndex = activeTabIndex; + } + + /** For internal use only. May be removed or replaced in the future. */ + public void setEnabled(boolean enabled) { + disabled = !enabled; + } + + /** For internal use only. May be removed or replaced in the future. */ + public void setReadonly(boolean readonly) { + this.readonly = readonly; + } + + /** For internal use only. May be removed or replaced in the future. */ + protected ComponentConnector getConnectorForWidget(Widget widget) { + return ConnectorMap.get(client).getConnector(widget); + } + + /** For internal use only. May be removed or replaced in the future. */ + public abstract void selectTab(int index); } diff --git a/client/src/com/vaadin/client/ui/accordion/AccordionConnector.java b/client/src/com/vaadin/client/ui/accordion/AccordionConnector.java index 99fbd07f9b..ce843dc22f 100644 --- a/client/src/com/vaadin/client/ui/accordion/AccordionConnector.java +++ b/client/src/com/vaadin/client/ui/accordion/AccordionConnector.java @@ -15,19 +15,17 @@ */ package com.vaadin.client.ui.accordion; -import java.util.Iterator; - -import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; -import com.vaadin.client.UIDL; import com.vaadin.client.Util; +import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.SimpleManagedLayout; import com.vaadin.client.ui.VAccordion; import com.vaadin.client.ui.VAccordion.StackItem; import com.vaadin.client.ui.layout.MayScrollChildren; import com.vaadin.client.ui.tabsheet.TabsheetBaseConnector; import com.vaadin.shared.ui.Connect; +import com.vaadin.shared.ui.accordion.AccordionState; import com.vaadin.ui.Accordion; @Connect(Accordion.class) @@ -35,35 +33,32 @@ public class AccordionConnector extends TabsheetBaseConnector implements SimpleManagedLayout, MayScrollChildren { @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - getWidget().selectedUIDLItemIndex = -1; - super.updateFromUIDL(uidl, client); + protected void init() { + super.init(); + getWidget().setConnector(this); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + /* * Render content after all tabs have been created and we know how large * the content area is */ - if (getWidget().selectedUIDLItemIndex >= 0) { + if (getWidget().selectedItemIndex >= 0) { StackItem selectedItem = getWidget().getStackItem( - getWidget().selectedUIDLItemIndex); - UIDL selectedTabUIDL = getWidget().lazyUpdateMap - .remove(selectedItem); - getWidget().open(getWidget().selectedUIDLItemIndex); + getWidget().selectedItemIndex); - selectedItem.setContent(selectedTabUIDL); - } else if (isRealUpdate(uidl) && getWidget().getOpenStackItem() != null) { - getWidget().close(getWidget().getOpenStackItem()); - } + getWidget().open(getWidget().selectedItemIndex); - // finally render possible hidden tabs - if (getWidget().lazyUpdateMap.size() > 0) { - for (Iterator iterator = getWidget().lazyUpdateMap.keySet() - .iterator(); iterator.hasNext();) { - StackItem item = (StackItem) iterator.next(); - item.setContent(getWidget().lazyUpdateMap.get(item)); + ComponentConnector contentConnector = getChildComponents().get(0); + if (contentConnector != null) { + selectedItem.setContent(contentConnector.getWidget()); } - getWidget().lazyUpdateMap.clear(); + } else if (getWidget().getOpenStackItem() != null) { + getWidget().close(getWidget().getOpenStackItem()); } - } @Override @@ -123,14 +118,24 @@ public class AccordionConnector extends TabsheetBaseConnector implements openTab.setHeight(spaceForOpenItem); } else { openTab.setHeightFromWidget(); - } - } + /* + * (non-Javadoc) + * + * @see com.vaadin.client.ConnectorHierarchyChangeEvent. + * ConnectorHierarchyChangeHandler + * #onConnectorHierarchyChange(com.vaadin.client + * .ConnectorHierarchyChangeEvent) + */ @Override public void onConnectorHierarchyChange( ConnectorHierarchyChangeEvent connectorHierarchyChangeEvent) { - // TODO Move code from updateFromUIDL to this method + } + + @Override + public AccordionState getState() { + return (AccordionState) super.getState(); } } diff --git a/client/src/com/vaadin/client/ui/tabsheet/TabsheetBaseConnector.java b/client/src/com/vaadin/client/ui/tabsheet/TabsheetBaseConnector.java index 283bc1b63b..30c9e47c6e 100644 --- a/client/src/com/vaadin/client/ui/tabsheet/TabsheetBaseConnector.java +++ b/client/src/com/vaadin/client/ui/tabsheet/TabsheetBaseConnector.java @@ -19,31 +19,41 @@ import java.util.ArrayList; import java.util.Iterator; import com.google.gwt.user.client.ui.Widget; -import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ComponentConnector; -import com.vaadin.client.Paintable; -import com.vaadin.client.UIDL; +import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractComponentContainerConnector; import com.vaadin.client.ui.VTabsheetBase; -import com.vaadin.shared.ui.tabsheet.TabsheetBaseConstants; +import com.vaadin.shared.ui.tabsheet.TabState; +import com.vaadin.shared.ui.tabsheet.TabsheetState; public abstract class TabsheetBaseConnector extends - AbstractComponentContainerConnector implements Paintable { + AbstractComponentContainerConnector { + /* + * (non-Javadoc) + * + * @see com.vaadin.client.ui.AbstractConnector#init() + */ @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - getWidget().client = client; + protected void init() { + super.init(); - if (!isRealUpdate(uidl)) { - return; - } + getWidget().setClient(getConnection()); + } - // Update member references - getWidget().id = uidl.getId(); - getWidget().disabled = !isEnabled(); + /* + * (non-Javadoc) + * + * @see + * com.vaadin.client.ui.AbstractComponentConnector#onStateChanged(com.vaadin + * .client.communication.StateChangeEvent) + */ + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); - // Render content - final UIDL tabs = uidl.getChildUIDL(0); + // Update member references + getWidget().setEnabled(isEnabled()); // Widgets in the TabSheet before update ArrayList<Widget> oldWidgets = new ArrayList<Widget>(); @@ -53,26 +63,22 @@ public abstract class TabsheetBaseConnector extends } // Clear previous values - getWidget().tabKeys.clear(); - getWidget().disabledTabKeys.clear(); + getWidget().clearTabKeys(); int index = 0; - for (final Iterator<Object> it = tabs.getChildIterator(); it.hasNext();) { - final UIDL tab = (UIDL) it.next(); - final String key = tab.getStringAttribute("key"); - final boolean selected = tab.getBooleanAttribute("selected"); - final boolean hidden = tab.getBooleanAttribute("hidden"); - - if (tab.getBooleanAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_DISABLED)) { - getWidget().disabledTabKeys.add(key); - } + for (TabState tab : getState().tabs) { + final String key = tab.key; + final boolean selected = key.equals(getState().selected); - getWidget().tabKeys.add(key); + getWidget().addTabKey(key, !tab.enabled && tab.visible); if (selected) { - getWidget().activeTabIndex = index; + getWidget().setActiveTabIndex(index); + } + getWidget().renderTab(tab, index); + if (selected) { + getWidget().selectTab(index); } - getWidget().renderTab(tab, index, selected, hidden); index++; } @@ -104,4 +110,9 @@ public abstract class TabsheetBaseConnector extends return (VTabsheetBase) super.getWidget(); } + @Override + public TabsheetState getState() { + return (TabsheetState) super.getState(); + } + } diff --git a/client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java b/client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java index 608ed1e139..b472300c21 100644 --- a/client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java +++ b/client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java @@ -17,36 +17,62 @@ package com.vaadin.client.ui.tabsheet; import com.google.gwt.dom.client.Element; import com.google.gwt.user.client.DOM; -import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.TooltipInfo; -import com.vaadin.client.UIDL; import com.vaadin.client.Util; +import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.SimpleManagedLayout; import com.vaadin.client.ui.VTabsheet; import com.vaadin.client.ui.layout.MayScrollChildren; import com.vaadin.shared.ui.Connect; -import com.vaadin.shared.ui.tabsheet.TabsheetState; +import com.vaadin.shared.ui.tabsheet.TabsheetClientRpc; import com.vaadin.ui.TabSheet; @Connect(TabSheet.class) public class TabsheetConnector extends TabsheetBaseConnector implements SimpleManagedLayout, MayScrollChildren { - // Can't use "style" as it's already in use + public TabsheetConnector() { + registerRpc(TabsheetClientRpc.class, new TabsheetClientRpc() { + @Override + public void revertToSharedStateSelection() { + for (int i = 0; i < getState().tabs.size(); ++i) { + final String key = getState().tabs.get(i).key; + final boolean selected = key.equals(getState().selected); + if (selected) { + getWidget().selectTab(i); + break; + } + } + renderContent(); + } + }); + } + + @Override + protected void init() { + super.init(); + getWidget().setConnector(this); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.client.ui.AbstractComponentConnector#onStateChanged(com.vaadin + * .client.communication.StateChangeEvent) + */ @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); - if (isRealUpdate(uidl)) { - // Handle stylename changes before generics (might affect size - // calculations) - getWidget().handleStyleNames(uidl, getState()); - } + getWidget().handleStyleNames(getState()); - super.updateFromUIDL(uidl, client); - if (!isRealUpdate(uidl)) { - return; + if (getState().tabsVisible) { + getWidget().showTabs(); + } else { + getWidget().hideTabs(); } // tabs; push or not @@ -76,11 +102,6 @@ public class TabsheetConnector extends TabsheetBaseConnector implements } @Override - public TabsheetState getState() { - return (TabsheetState) super.getState(); - } - - @Override public void updateCaption(ComponentConnector component) { /* Tabsheet does not render its children's captions */ } @@ -147,7 +168,20 @@ public class TabsheetConnector extends TabsheetBaseConnector implements @Override public void onConnectorHierarchyChange( - ConnectorHierarchyChangeEvent connectorHierarchyChangeEvent) { - // TODO Move code from updateFromUIDL to this method + ConnectorHierarchyChangeEvent connector) { + renderContent(); + } + + /** + * (Re-)render the content of the active tab. + */ + protected void renderContent() { + ComponentConnector contentConnector = getChildComponents().get(0); + if (null != contentConnector) { + getWidget().renderContent(contentConnector.getWidget()); + } else { + getWidget().renderContent(null); + } } + } |