aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelype Santiago Ferreira <felype@vaadin.com>2014-02-26 16:05:37 +0200
committerVaadin Code Review <review@vaadin.com>2014-04-08 06:34:55 +0000
commitf32e3535c6ef73bca33f274e9906f57aa178d22a (patch)
treeba2453a82f97a2c68f35d363ed2c553d84d5bae9
parentef8920661cc9d958c69cfedd0a74ce580a2a84ed (diff)
downloadvaadin-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
-rw-r--r--client/src/com/vaadin/client/ui/VAccordion.java162
-rw-r--r--client/src/com/vaadin/client/ui/VTabsheet.java316
-rw-r--r--client/src/com/vaadin/client/ui/VTabsheetBase.java100
-rw-r--r--client/src/com/vaadin/client/ui/accordion/AccordionConnector.java59
-rw-r--r--client/src/com/vaadin/client/ui/tabsheet/TabsheetBaseConnector.java69
-rw-r--r--client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java74
-rw-r--r--server/src/com/vaadin/ui/Accordion.java12
-rw-r--r--server/src/com/vaadin/ui/TabSheet.java385
-rw-r--r--shared/src/com/vaadin/shared/ui/accordion/AccordionState.java28
-rw-r--r--shared/src/com/vaadin/shared/ui/tabsheet/TabState.java39
-rw-r--r--shared/src/com/vaadin/shared/ui/tabsheet/TabsheetClientRpc.java35
-rw-r--r--shared/src/com/vaadin/shared/ui/tabsheet/TabsheetServerRpc.java44
-rw-r--r--shared/src/com/vaadin/shared/ui/tabsheet/TabsheetState.java21
-rw-r--r--uitest/src/com/vaadin/tests/components/accordion/RemoveTabs.java19
-rw-r--r--uitest/src/com/vaadin/tests/components/tabsheet/EmptyTabSheet.java27
-rw-r--r--uitest/src/com/vaadin/tests/components/tabsheet/EmptyTabSheetTest.java30
-rw-r--r--uitest/src/com/vaadin/tests/components/tabsheet/PreventTabChange.html77
-rw-r--r--uitest/src/com/vaadin/tests/components/tabsheet/PreventTabChange.java6
-rw-r--r--uitest/src/com/vaadin/tests/components/tabsheet/PreventTabChangeTest.java62
19 files changed, 953 insertions, 612 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);
+ }
}
+
}
diff --git a/server/src/com/vaadin/ui/Accordion.java b/server/src/com/vaadin/ui/Accordion.java
index e3c654751c..cca0a7efb8 100644
--- a/server/src/com/vaadin/ui/Accordion.java
+++ b/server/src/com/vaadin/ui/Accordion.java
@@ -15,6 +15,8 @@
*/
package com.vaadin.ui;
+import com.vaadin.shared.ui.accordion.AccordionState;
+
/**
* An accordion is a component similar to a {@link TabSheet}, but with a
* vertical orientation and the selected component presented between tabs.
@@ -46,4 +48,14 @@ public class Accordion extends TabSheet {
addComponents(components);
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.TabSheet#getState()
+ */
+ @Override
+ protected AccordionState getState() {
+ return (AccordionState) super.getState();
+ }
+
}
diff --git a/server/src/com/vaadin/ui/TabSheet.java b/server/src/com/vaadin/ui/TabSheet.java
index a1f9e9dd26..8e2c40fc0f 100644
--- a/server/src/com/vaadin/ui/TabSheet.java
+++ b/server/src/com/vaadin/ui/TabSheet.java
@@ -27,17 +27,18 @@ import java.util.Map;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.BlurNotifier;
+import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.event.FieldEvents.FocusNotifier;
import com.vaadin.server.ErrorMessage;
import com.vaadin.server.KeyMapper;
-import com.vaadin.server.LegacyPaint;
-import com.vaadin.server.PaintException;
-import com.vaadin.server.PaintTarget;
import com.vaadin.server.Resource;
-import com.vaadin.shared.ui.tabsheet.TabsheetBaseConstants;
-import com.vaadin.shared.ui.tabsheet.TabsheetConstants;
+import com.vaadin.shared.ComponentConstants;
+import com.vaadin.shared.ui.tabsheet.TabState;
+import com.vaadin.shared.ui.tabsheet.TabsheetClientRpc;
+import com.vaadin.shared.ui.tabsheet.TabsheetServerRpc;
+import com.vaadin.shared.ui.tabsheet.TabsheetState;
import com.vaadin.ui.Component.Focusable;
import com.vaadin.ui.themes.Reindeer;
import com.vaadin.ui.themes.Runo;
@@ -70,7 +71,28 @@ import com.vaadin.ui.themes.Runo;
* @since 3.0
*/
public class TabSheet extends AbstractComponentContainer implements Focusable,
- FocusNotifier, BlurNotifier, LegacyComponent, SelectiveRenderer {
+ FocusNotifier, BlurNotifier, SelectiveRenderer {
+
+ /**
+ * Client to server RPC implementation for TabSheet.
+ *
+ * @since 7.2
+ */
+ protected class TabsheetServerRpcImpl implements TabsheetServerRpc {
+
+ @Override
+ public void setSelected(String key) {
+ setSelectedTab(keyMapper.get(key));
+ }
+
+ @Override
+ public void closeTab(String key) {
+ final Component tab = keyMapper.get(key);
+ if (tab != null) {
+ closeHandler.onTabClose(TabSheet.this, tab);
+ }
+ }
+ }
/**
* List of component tabs (tab contents). In addition to being on this list,
@@ -96,23 +118,20 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
private final KeyMapper<Component> keyMapper = new KeyMapper<Component>();
/**
- * When true, the tab selection area is not displayed to the user.
- */
- private boolean tabsHidden;
-
- /**
* Handler to be called when a tab is closed.
*/
private CloseHandler closeHandler;
- private int tabIndex;
-
/**
* Constructs a new TabSheet. A TabSheet is immediate by default, and the
* default close handler removes the tab being closed.
*/
public TabSheet() {
super();
+
+ registerRpc(rpc);
+ registerRpc(focusBlurRpc);
+
// expand horizontally by default
setWidth(100, UNITS_PERCENTAGE);
setImmediate(true);
@@ -167,18 +186,23 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
* If the tab was selected, the first eligible (visible and enabled)
* remaining tab is selected.
*
- * @param c
+ * @param component
* the component to be removed.
*/
@Override
- public void removeComponent(Component c) {
- if (c != null && components.contains(c)) {
- super.removeComponent(c);
- keyMapper.remove(c);
- components.remove(c);
- tabs.remove(c);
- if (c.equals(selected)) {
+ public void removeComponent(Component component) {
+ if (component != null && components.contains(component)) {
+ super.removeComponent(component);
+ keyMapper.remove(component);
+ components.remove(component);
+
+ Tab removedTab = tabs.remove(component);
+
+ getState().tabs
+ .remove(((TabSheetTabImpl) removedTab).getTabState());
+
+ if (component.equals(selected)) {
if (components.isEmpty()) {
setSelected(null);
} else {
@@ -308,7 +332,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
* and icon and returns the corresponding (old) tab, preserving other tab
* metadata like the position.
*
- * @param c
+ * @param tabComponent
* the component to be added onto tab - should not be null.
* @param caption
* the caption to be set for the component and used rendered in
@@ -334,7 +358,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
* and icon and icon alternate text and returns the corresponding (old) tab,
* preserving other tab metadata like the position.
*
- * @param c
+ * @param tabComponent
* the component to be added onto tab - should not be null.
* @param caption
* the caption to be set for the component and used rendered in
@@ -348,26 +372,30 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
* the position at where the the tab should be added.
* @return the created {@link Tab}
*/
- public Tab addTab(Component c, String caption, Resource icon,
+ public Tab addTab(Component tabComponent, String caption, Resource icon,
String iconAltText, int position) {
- if (c == null) {
+
+ if (tabComponent == null) {
return null;
- } else if (tabs.containsKey(c)) {
- Tab tab = tabs.get(c);
+ } else if (tabs.containsKey(tabComponent)) {
+ Tab tab = tabs.get(tabComponent);
tab.setCaption(caption);
tab.setIcon(icon, iconAltText);
return tab;
} else {
- components.add(position, c);
+ components.add(position, tabComponent);
+
+ TabSheetTabImpl tab = new TabSheetTabImpl(
+ keyMapper.key(tabComponent), caption, icon);
- Tab tab = new TabSheetTabImpl(caption, icon);
+ getState().tabs.add(position, tab.getTabState());
+ tabs.put(tabComponent, tab);
- tabs.put(c, tab);
if (selected == null) {
- setSelected(c);
+ setSelected(tabComponent);
fireSelectedTabChange();
}
- super.addComponent(c);
+ super.addComponent(tabComponent);
markAsDirty();
return tab;
}
@@ -393,20 +421,21 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
*
* If the tab sheet already contains the component, its tab is returned.
*
- * @param c
+ * @param component
* the component to be added onto tab - should not be null.
* @param position
* The position where the tab should be added
* @return the created {@link Tab}
*/
- public Tab addTab(Component c, int position) {
- if (c == null) {
- return null;
- } else if (tabs.containsKey(c)) {
- return tabs.get(c);
- } else {
- return addTab(c, c.getCaption(), c.getIcon(), position);
+ public Tab addTab(Component component, int position) {
+ Tab result = tabs.get(component);
+
+ if (result == null) {
+ result = addTab(component, component.getCaption(),
+ component.getIcon(), position);
}
+
+ return result;
}
/**
@@ -441,107 +470,12 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
}
/**
- * Paints the content of this component.
- *
- * @param target
- * the paint target
- * @throws PaintException
- * if the paint operation failed.
- */
-
- @Override
- public void paintContent(PaintTarget target) throws PaintException {
-
- if (areTabsHidden()) {
- target.addAttribute("hidetabs", true);
- }
-
- if (tabIndex != 0) {
- target.addAttribute("tabindex", tabIndex);
- }
-
- target.startTag("tabs");
-
- for (final Iterator<Component> i = getComponentIterator(); i.hasNext();) {
- final Component component = i.next();
-
- Tab tab = tabs.get(component);
-
- target.startTag("tab");
- if (!tab.isEnabled() && tab.isVisible()) {
- target.addAttribute(
- TabsheetBaseConstants.ATTRIBUTE_TAB_DISABLED, true);
- }
-
- if (!tab.isVisible()) {
- target.addAttribute("hidden", true);
- }
-
- if (tab.isClosable()) {
- target.addAttribute("closable", true);
- }
-
- // tab icon, caption and description, but used via
- // VCaption.updateCaption(uidl)
- final Resource icon = tab.getIcon();
- if (icon != null) {
- target.addAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_ICON,
- icon);
- target.addAttribute(
- TabsheetBaseConstants.ATTRIBUTE_TAB_ICON_ALT,
- tab.getIconAltText());
- }
- final String caption = tab.getCaption();
- if (caption != null && !caption.isEmpty()) {
- target.addAttribute(
- TabsheetBaseConstants.ATTRIBUTE_TAB_CAPTION, caption);
- }
- ErrorMessage tabError = tab.getComponentError();
- if (tabError != null) {
- target.addAttribute(
- TabsheetBaseConstants.ATTRIBUTE_TAB_ERROR_MESSAGE,
- tabError.getFormattedHtmlMessage());
- }
- final String description = tab.getDescription();
- if (description != null) {
- target.addAttribute(
- TabsheetBaseConstants.ATTRIBUTE_TAB_DESCRIPTION,
- description);
- }
-
- final String styleName = tab.getStyleName();
- if (styleName != null && !styleName.isEmpty()) {
- target.addAttribute(TabsheetConstants.TAB_STYLE_NAME, styleName);
- }
-
- final String id = tab.getId();
- if (id != null && !id.isEmpty()) {
- target.addAttribute("id", id);
- }
-
- target.addAttribute("key", keyMapper.key(component));
- if (component.equals(selected)) {
- target.addAttribute("selected", true);
- LegacyPaint.paint(component, target);
- }
- target.endTag("tab");
- }
-
- target.endTag("tabs");
-
- if (selected != null) {
- target.addVariable(this, "selected", keyMapper.key(selected));
- }
-
- }
-
- /**
* Are the tab selection parts ("tabs") hidden.
*
* @return true if the tabs are hidden in the UI
*/
public boolean areTabsHidden() {
- return tabsHidden;
+ return !getState(false).tabsVisible;
}
/**
@@ -551,8 +485,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
* true if the tabs should be hidden
*/
public void hideTabs(boolean tabsHidden) {
- this.tabsHidden = tabsHidden;
- markAsDirty();
+ getState().tabsVisible = !tabsHidden;
}
/**
@@ -597,6 +530,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
updateSelection();
fireSelectedTabChange();
markAsDirty();
+ getRpcProxy(TabsheetClientRpc.class).revertToSharedStateSelection();
}
}
@@ -604,22 +538,29 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
* Sets the selected tab in the TabSheet. Ensures that the selected tab is
* repainted if needed.
*
- * @param c
+ * @param component
* The new selection or null for no selection
*/
- private void setSelected(Component c) {
- selected = c;
+ private void setSelected(Component component) {
+ Tab tab = tabs.get(selected);
+
+ selected = component;
// Repaint of the selected component is needed as only the selected
// component is communicated to the client. Otherwise this will be a
// "cached" update even though the client knows nothing about the
// connector
if (selected != null) {
- selected.markAsDirtyRecursive();
+ tab = getTab(component);
- Tab tab = getTab(c);
if (tab != null && tab.getDefaultFocusComponent() != null) {
tab.getDefaultFocusComponent().focus();
}
+
+ getState().selected = keyMapper.key(selected);
+
+ selected.markAsDirtyRecursive();
+ } else {
+ getState().selected = null;
}
}
@@ -703,27 +644,16 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
return selected;
}
- // inherits javadoc
+ private TabsheetServerRpcImpl rpc = new TabsheetServerRpcImpl();
- @Override
- public void changeVariables(Object source, Map<String, Object> variables) {
- if (variables.containsKey("selected")) {
- setSelectedTab(keyMapper.get((String) variables.get("selected")));
- }
- if (variables.containsKey("close")) {
- final Component tab = keyMapper
- .get((String) variables.get("close"));
- if (tab != null) {
- closeHandler.onTabClose(this, tab);
- }
- }
- if (variables.containsKey(FocusEvent.EVENT_ID)) {
- fireEvent(new FocusEvent(this));
- }
- if (variables.containsKey(BlurEvent.EVENT_ID)) {
- fireEvent(new BlurEvent(this));
+ private FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(
+ this) {
+
+ @Override
+ protected void fireEvent(Event event) {
+ TabSheet.this.fireEvent(event);
}
- }
+ };
/**
* Replaces a component (tab content) with another. This can be used to
@@ -745,10 +675,10 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
@Override
public void replaceComponent(Component oldComponent, Component newComponent) {
+ boolean selectAfterInserting = false;
if (selected == oldComponent) {
- // keep selection w/o selectedTabChange event
- setSelected(newComponent);
+ selectAfterInserting = true;
}
Tab newTab = tabs.get(newComponent);
@@ -758,6 +688,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
int oldLocation = -1;
int newLocation = -1;
int location = 0;
+
for (final Iterator<Component> i = components.iterator(); i.hasNext();) {
final Component component = i.next();
@@ -776,6 +707,11 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
} else if (newLocation == -1) {
removeComponent(oldComponent);
newTab = addTab(newComponent, oldLocation);
+
+ if (selectAfterInserting) {
+ setSelected(newComponent);
+ }
+
// Copy all relevant metadata to the new tab (#8793)
// TODO Should reuse the old tab instance instead?
copyTabMetadata(oldTab, newTab);
@@ -783,17 +719,20 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
components.set(oldLocation, newComponent);
components.set(newLocation, oldComponent);
+ if (selectAfterInserting) {
+ setSelected(newComponent);
+ }
+
// Tab associations are not changed, but metadata is swapped between
// the instances
// TODO Should reassociate the instances instead?
- Tab tmp = new TabSheetTabImpl(null, null);
+ Tab tmp = new TabSheetTabImpl(null, null, null);
copyTabMetadata(newTab, tmp);
copyTabMetadata(oldTab, newTab);
copyTabMetadata(tmp, oldTab);
markAsDirty();
}
-
}
/* Click event */
@@ -953,7 +892,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
* Note! Currently only supported by TabSheet, not Accordion.
* </p>
*
- * @param visible
+ * @param closable
* true if the end user is allowed to close the tab, false
* for not allowing to close. Should default to false.
*/
@@ -1148,24 +1087,23 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
*/
public class TabSheetTabImpl implements Tab {
- private String caption = "";
- private Resource icon = null;
- private boolean enabled = true;
- private boolean visible = true;
- private boolean closable = false;
- private String description = null;
- private ErrorMessage componentError = null;
- private String styleName;
- private String id;
- private String iconAltText = "";
+ private TabState tabState;
+
private Focusable defaultFocus;
- public TabSheetTabImpl(String caption, Resource icon) {
+ private ErrorMessage componentError;
+
+ public TabSheetTabImpl(String key, String caption, Resource icon) {
+ tabState = new TabState();
+
if (caption == null) {
caption = "";
}
- this.caption = caption;
- this.icon = icon;
+
+ tabState.key = key;
+ tabState.caption = caption;
+
+ setIcon(icon);
}
/**
@@ -1174,40 +1112,36 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
@Override
public String getCaption() {
- return caption;
+ return tabState.caption;
}
@Override
public void setCaption(String caption) {
- this.caption = caption;
+ tabState.caption = caption;
markAsDirty();
}
@Override
public Resource getIcon() {
- return icon;
+ return getResource(ComponentConstants.ICON_RESOURCE
+ + tabState.key);
}
@Override
public void setIcon(Resource icon) {
+ // this might not be ideal (resetting icon altText), but matches
+ // previous semantics
setIcon(icon, "");
}
@Override
- public void setIcon(Resource icon, String iconAltText) {
- this.icon = icon;
- this.iconAltText = iconAltText;
- markAsDirty();
- }
-
- @Override
public String getIconAltText() {
- return iconAltText;
+ return tabState.iconAltText;
}
@Override
public void setIconAltText(String iconAltText) {
- this.iconAltText = iconAltText;
+ tabState.iconAltText = iconAltText;
markAsDirty();
}
@@ -1223,12 +1157,13 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
@Override
public boolean isEnabled() {
- return enabled;
+ return tabState.enabled;
}
@Override
public void setEnabled(boolean enabled) {
- this.enabled = enabled;
+ tabState.enabled = enabled;
+
if (updateSelection()) {
fireSelectedTabChange();
}
@@ -1237,12 +1172,13 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
@Override
public boolean isVisible() {
- return visible;
+ return tabState.visible;
}
@Override
public void setVisible(boolean visible) {
- this.visible = visible;
+ tabState.visible = visible;
+
if (updateSelection()) {
fireSelectedTabChange();
}
@@ -1251,27 +1187,24 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
@Override
public boolean isClosable() {
- return closable;
+ return tabState.closable;
}
@Override
public void setClosable(boolean closable) {
- this.closable = closable;
- markAsDirty();
- }
-
- public void close() {
+ tabState.closable = closable;
+ markAsDirty();
}
@Override
public String getDescription() {
- return description;
+ return tabState.description;
}
@Override
public void setDescription(String description) {
- this.description = description;
+ tabState.description = description;
markAsDirty();
}
@@ -1283,6 +1216,11 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
@Override
public void setComponentError(ErrorMessage componentError) {
this.componentError = componentError;
+
+ String formattedHtmlMessage = componentError != null ? componentError
+ .getFormattedHtmlMessage() : null;
+ tabState.componentError = formattedHtmlMessage;
+
markAsDirty();
}
@@ -1298,25 +1236,37 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
@Override
public void setStyleName(String styleName) {
- this.styleName = styleName;
+ tabState.styleName = styleName;
+
markAsDirty();
}
@Override
public String getStyleName() {
- return styleName;
+ return tabState.styleName;
+ }
+
+ protected TabState getTabState() {
+ return tabState;
}
@Override
public void setId(String id) {
- this.id = id;
+ tabState.id = id;
markAsDirty();
}
@Override
public String getId() {
- return id;
+ return tabState.id;
+ }
+
+ @Override
+ public void setIcon(Resource icon, String iconAltText) {
+ setResource(ComponentConstants.ICON_RESOURCE + tabState.key,
+ icon);
+ tabState.iconAltText = iconAltText;
}
}
@@ -1371,7 +1321,9 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
int oldPosition = getTabPosition(tab);
components.remove(oldPosition);
components.add(position, tab.getComponent());
- markAsDirty();
+
+ getState().tabs.remove(oldPosition);
+ getState().tabs.add(position, ((TabSheetTabImpl) tab).getTabState());
}
/**
@@ -1392,13 +1344,12 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
@Override
public int getTabIndex() {
- return tabIndex;
+ return getState(false).tabIndex;
}
@Override
public void setTabIndex(int tabIndex) {
- this.tabIndex = tabIndex;
- markAsDirty();
+ getState().tabIndex = tabIndex;
}
@Override
@@ -1485,4 +1436,14 @@ public class TabSheet extends AbstractComponentContainer implements Focusable,
to.setStyleName(from.getStyleName());
to.setComponentError(from.getComponentError());
}
+
+ @Override
+ protected TabsheetState getState(boolean markAsDirty) {
+ return (TabsheetState) super.getState(markAsDirty);
+ }
+
+ @Override
+ protected TabsheetState getState() {
+ return (TabsheetState) super.getState();
+ }
}
diff --git a/shared/src/com/vaadin/shared/ui/accordion/AccordionState.java b/shared/src/com/vaadin/shared/ui/accordion/AccordionState.java
new file mode 100644
index 0000000000..67b20fc040
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/accordion/AccordionState.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.accordion;
+
+import com.vaadin.shared.ui.tabsheet.TabsheetState;
+
+public class AccordionState extends TabsheetState {
+
+ public static final String PRIMARY_STYLE_NAME = "v-accordion";
+
+ {
+ primaryStyleName = PRIMARY_STYLE_NAME;
+ }
+
+}
diff --git a/shared/src/com/vaadin/shared/ui/tabsheet/TabState.java b/shared/src/com/vaadin/shared/ui/tabsheet/TabState.java
new file mode 100644
index 0000000000..9620a61c9a
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/tabsheet/TabState.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.tabsheet;
+
+import java.io.Serializable;
+
+/**
+ * Shared state of a single tab in a Tabsheet or an Accordion.
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public class TabState implements Serializable {
+
+ public String caption = "";
+ public boolean enabled = true;
+ public boolean visible = true;
+ public boolean closable = false;
+ public String description = null;
+ public String styleName;
+ public String key;
+ public String componentError;
+ public String id;
+ public String iconAltText;
+
+} \ No newline at end of file
diff --git a/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetClientRpc.java b/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetClientRpc.java
new file mode 100644
index 0000000000..780e0f1ac5
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetClientRpc.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.tabsheet;
+
+import com.vaadin.shared.communication.ClientRpc;
+
+/**
+ * Server to client RPC methods for the TabSheet.
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public interface TabsheetClientRpc extends ClientRpc {
+
+ /**
+ * Forces the client to switch to the tab that is selected by the server.
+ *
+ * This is required e.g. for reverting tab selection change on the server
+ * side (shared state does not change).
+ */
+ public void revertToSharedStateSelection();
+}
diff --git a/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetServerRpc.java b/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetServerRpc.java
new file mode 100644
index 0000000000..996525151c
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetServerRpc.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.tabsheet;
+
+import com.vaadin.shared.communication.ServerRpc;
+
+/**
+ * Client to server RPC methods for the TabSheet.
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public interface TabsheetServerRpc extends ServerRpc {
+
+ /**
+ * Tell server that a tab has been selected by the user.
+ *
+ * @param key
+ * internal key of the tab
+ */
+ void setSelected(String key);
+
+ /**
+ * Tell server that a tab has been closed by the user.
+ *
+ * @param key
+ * internal key of the tab
+ */
+ void closeTab(String key);
+
+}
diff --git a/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetState.java b/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetState.java
index dbb91b8b3d..77e9e15400 100644
--- a/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetState.java
+++ b/shared/src/com/vaadin/shared/ui/tabsheet/TabsheetState.java
@@ -15,10 +15,29 @@
*/
package com.vaadin.shared.ui.tabsheet;
+import java.util.ArrayList;
+
import com.vaadin.shared.AbstractComponentState;
public class TabsheetState extends AbstractComponentState {
+ public static final String PRIMARY_STYLE_NAME = "v-tabsheet";
+
{
- primaryStyleName = "v-tabsheet";
+ primaryStyleName = PRIMARY_STYLE_NAME;
}
+
+ /**
+ * Index of the component when switching focus - not related to Tabsheet
+ * tabs.
+ */
+ public int tabIndex;
+
+ public ArrayList<TabState> tabs = new ArrayList<TabState>();
+
+ /** true to show the tab bar, false to only show the contained component */
+ public boolean tabsVisible = true;
+
+ /** the key of the currently selected tab */
+ public String selected;
+
}
diff --git a/uitest/src/com/vaadin/tests/components/accordion/RemoveTabs.java b/uitest/src/com/vaadin/tests/components/accordion/RemoveTabs.java
index d24def22dd..e82336c1e8 100644
--- a/uitest/src/com/vaadin/tests/components/accordion/RemoveTabs.java
+++ b/uitest/src/com/vaadin/tests/components/accordion/RemoveTabs.java
@@ -46,38 +46,34 @@ public class RemoveTabs extends TestBase {
getLayout().addComponent(accordion);
closeCurrent = new Button("Close current tab");
- closeCurrent.addListener(new Button.ClickListener() {
+ closeCurrent.addClickListener(new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
closeCurrentTab();
-
}
});
closeFirst = new Button("close first tab");
- closeFirst.addListener(new Button.ClickListener() {
+ closeFirst.addClickListener(new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
closeFirstTab();
-
}
});
closeLast = new Button("close last tab");
- closeLast.addListener(new Button.ClickListener() {
+ closeLast.addClickListener(new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
closeLastTab();
-
}
});
reorderTabs = new Button("reorder");
- reorderTabs.addListener(new Button.ClickListener() {
+ reorderTabs.addClickListener(new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
reorder();
-
}
});
@@ -96,11 +92,11 @@ public class RemoveTabs extends TestBase {
}
private void closeFirstTab() {
- accordion.removeComponent(accordion.getComponentIterator().next());
+ accordion.removeComponent(accordion.iterator().next());
}
private void closeLastTab() {
- Iterator<Component> i = accordion.getComponentIterator();
+ Iterator<Component> i = accordion.iterator();
Component last = null;
while (i.hasNext()) {
last = i.next();
@@ -114,7 +110,7 @@ public class RemoveTabs extends TestBase {
if (container != null) {
List<Component> c = new ArrayList<Component>();
- Iterator<Component> i = container.getComponentIterator();
+ Iterator<Component> i = container.iterator();
while (i.hasNext()) {
Component comp = i.next();
c.add(comp);
@@ -124,7 +120,6 @@ public class RemoveTabs extends TestBase {
for (int j = c.size() - 1; j >= 0; j--) {
container.addComponent(c.get(j));
}
-
}
}
diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/EmptyTabSheet.java b/uitest/src/com/vaadin/tests/components/tabsheet/EmptyTabSheet.java
new file mode 100644
index 0000000000..3cbe624ee0
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/tabsheet/EmptyTabSheet.java
@@ -0,0 +1,27 @@
+package com.vaadin.tests.components.tabsheet;
+
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.TabSheet;
+
+public class EmptyTabSheet extends TestBase {
+
+ private TabSheet tabSheet;
+
+ @Override
+ protected String getDescription() {
+ return "Test a TabSheet without any tabs.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return null;
+ }
+
+ @Override
+ protected void setup() {
+ tabSheet = new TabSheet();
+ tabSheet.setId("tabsheet");
+ addComponent(tabSheet);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/EmptyTabSheetTest.java b/uitest/src/com/vaadin/tests/components/tabsheet/EmptyTabSheetTest.java
new file mode 100644
index 0000000000..dabc9c8e0b
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/tabsheet/EmptyTabSheetTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.tabsheet;
+
+import org.junit.Test;
+
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class EmptyTabSheetTest extends MultiBrowserTest {
+ @Test
+ public void emptyTabSheet() throws Exception {
+ openTestURL();
+
+ compareScreen("empty");
+ }
+
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/PreventTabChange.html b/uitest/src/com/vaadin/tests/components/tabsheet/PreventTabChange.html
deleted file mode 100644
index c4f5998f47..0000000000
--- a/uitest/src/com/vaadin/tests/components/tabsheet/PreventTabChange.html
+++ /dev/null
@@ -1,77 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="selenium.base" href="http://localhost:8080/" />
-<title>PreventTabChange</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
-<thead>
-<tr><td rowspan="1" colspan="3">PreventTabChange</td></tr>
-</thead><tbody>
-<tr>
- <td>open</td>
- <td>/run/com.vaadin.tests.components.tabsheet.PreventTabChange</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runcomvaadintestscomponentstabsheetPreventTabChange::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runcomvaadintestscomponentstabsheetPreventTabChange::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2]/domChild[0]/domChild[0]/domChild[0]</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runcomvaadintestscomponentstabsheetPreventTabChange::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runcomvaadintestscomponentstabsheetPreventTabChange::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2]/domChild[0]/domChild[0]/domChild[0]</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td></td>
-</tr>
-
-</tbody></table>
-</body>
-</html>
diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/PreventTabChange.java b/uitest/src/com/vaadin/tests/components/tabsheet/PreventTabChange.java
index 434c73f778..fddb036728 100644
--- a/uitest/src/com/vaadin/tests/components/tabsheet/PreventTabChange.java
+++ b/uitest/src/com/vaadin/tests/components/tabsheet/PreventTabChange.java
@@ -31,7 +31,8 @@ public class PreventTabChange extends TestBase implements
@Override
protected void setup() {
tabSheet = new TabSheet();
- tabSheet.addListener(this);
+ tabSheet.setId("tabsheet");
+ tabSheet.addSelectedTabChangeListener(this);
tab1 = new Label("Tab 1 contents");
tab2 = new Label("Tab 2 contents");
tab3 = new Label("Tab 3 contents");
@@ -48,8 +49,8 @@ public class PreventTabChange extends TestBase implements
@Override
public void selectedTabChange(SelectedTabChangeEvent event) {
-
TabSheet tabsheet = event.getTabSheet();
+
if (lastTab == tab1) {
if (tabsheet.getSelectedTab() != tab2) {
tabsheet.setSelectedTab(lastTab);
@@ -63,6 +64,7 @@ public class PreventTabChange extends TestBase implements
tabsheet.setSelectedTab(lastTab);
}
}
+
lastTab = tabsheet.getSelectedTab();
}
}
diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/PreventTabChangeTest.java b/uitest/src/com/vaadin/tests/components/tabsheet/PreventTabChangeTest.java
new file mode 100644
index 0000000000..31a59aaed6
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/tabsheet/PreventTabChangeTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.tabsheet;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class PreventTabChangeTest extends MultiBrowserTest {
+ @Test
+ public void preventTabChange() throws Exception {
+ openTestURL();
+
+ clickTab(1);
+ clickTab(2);
+ Thread.sleep(2000);
+ assertTabSelected(2);
+ Assert.assertEquals("Tab 3 contents", getSelectedTabContent().getText());
+ clickTab(0);
+ clickTab(2);
+ assertTabSelected(0);
+ Assert.assertEquals("Tab 1 contents", getSelectedTabContent().getText());
+ }
+
+ private void assertTabSelected(int i) throws NoSuchElementException {
+ WebElement tabItem = findTab(i).findElement(By.xpath(".."));
+ Assert.assertTrue("Tab " + i + " should be selected but isn't", tabItem
+ .getAttribute("class").contains("v-tabsheet-tabitem-selected"));
+ }
+
+ private void clickTab(int i) {
+ findTab(i).click();
+ }
+
+ private WebElement findTab(int i) {
+ return driver.findElement(com.vaadin.testbench.By
+ .vaadin("//TabSheet#tab[" + i + "]"));
+ }
+
+ private WebElement getSelectedTabContent() {
+ return driver.findElement(com.vaadin.testbench.By
+ .vaadin("//TabSheet#tabpanel"));
+ }
+
+} \ No newline at end of file