diff options
author | Artur <artur@vaadin.com> | 2017-06-29 09:06:24 +0300 |
---|---|---|
committer | Henri Sara <henri.sara@gmail.com> | 2017-06-29 09:06:24 +0300 |
commit | e7898f59177e9e7f13f2c26fb2d44e8ae489f6cb (patch) | |
tree | 7c2442f3c93e3e5d4a4b993e419b24aba1db5def | |
parent | 173ac5b1def8785ac5b1c5b1fdd08b8bdf09b936 (diff) | |
download | vaadin-framework-e7898f59177e9e7f13f2c26fb2d44e8ae489f6cb.tar.gz vaadin-framework-e7898f59177e9e7f13f2c26fb2d44e8ae489f6cb.zip |
Add isUserOriginated to SelectedTabChangeEvent (#9580)
Fixes #9545
4 files changed, 174 insertions, 43 deletions
diff --git a/server/src/main/java/com/vaadin/data/HasUserOriginated.java b/server/src/main/java/com/vaadin/data/HasUserOriginated.java new file mode 100644 index 0000000000..e7d6d125b5 --- /dev/null +++ b/server/src/main/java/com/vaadin/data/HasUserOriginated.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2016 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.data; + +import java.io.Serializable; + +/** + * Marker for events which provides information of the event origin. + * + * @since + */ +public interface HasUserOriginated extends Serializable { + /** + * Returns whether this event was triggered by user interaction, on the + * client side, or programmatically, on the server side. + * + * @return {@code true} if this event originates from the client, + * {@code false} otherwise. + */ + public boolean isUserOriginated(); + +} diff --git a/server/src/main/java/com/vaadin/data/HasValue.java b/server/src/main/java/com/vaadin/data/HasValue.java index de2f86550f..b2ce098f6f 100644 --- a/server/src/main/java/com/vaadin/data/HasValue.java +++ b/server/src/main/java/com/vaadin/data/HasValue.java @@ -47,7 +47,8 @@ public interface HasValue<V> extends Serializable { * @param <V> * the value type */ - public class ValueChangeEvent<V> extends EventObject { + public class ValueChangeEvent<V> extends EventObject + implements HasUserOriginated { private final boolean userOriginated; private final Component component; @@ -101,7 +102,7 @@ public interface HasValue<V> extends Serializable { /** * Returns the value of the source before this value change event * occurred. - * + * * @return the value previously held by the source of this event */ public V getOldValue() { @@ -117,13 +118,7 @@ public interface HasValue<V> extends Serializable { return value; } - /** - * Returns whether this event was triggered by user interaction, on the - * client side, or programmatically, on the server side. - * - * @return {@code true} if this event originates from the client, - * {@code false} otherwise. - */ + @Override public boolean isUserOriginated() { return userOriginated; } @@ -224,7 +219,7 @@ public interface HasValue<V> extends Serializable { * Returns the current value of this object, wrapped in an {@code Optional}. * <p> * The {@code Optional} will be empty if the value is {@code null} or - * {@code isEmpty()} returns {@code true}. + * {@code isEmpty()} returns {@code true}. * * @return the current value, wrapped in an {@code Optional} */ diff --git a/server/src/main/java/com/vaadin/ui/TabSheet.java b/server/src/main/java/com/vaadin/ui/TabSheet.java index ec018e5fbf..550c5fc8ca 100644 --- a/server/src/main/java/com/vaadin/ui/TabSheet.java +++ b/server/src/main/java/com/vaadin/ui/TabSheet.java @@ -28,6 +28,7 @@ import java.util.Map; import org.jsoup.nodes.Attributes; import org.jsoup.nodes.Element; +import com.vaadin.data.HasUserOriginated; import com.vaadin.event.FieldEvents.BlurEvent; import com.vaadin.event.FieldEvents.BlurListener; import com.vaadin.event.FieldEvents.BlurNotifier; @@ -87,7 +88,7 @@ public class TabSheet extends AbstractComponentContainer @Override public void setSelected(String key) { - setSelectedTab(keyMapper.get(key)); + setSelectedTab(keyMapper.get(key), true); } @Override @@ -120,7 +121,7 @@ public class TabSheet extends AbstractComponentContainer * Mapper between server-side component instances (tab contents) and keys * given to the client that identify tabs. */ - private final KeyMapper<Component> keyMapper = new KeyMapper<>(); + protected final KeyMapper<Component> keyMapper = new KeyMapper<>(); /** * Handler to be called when a tab is closed. @@ -227,7 +228,7 @@ public class TabSheet extends AbstractComponentContainer // select the first enabled and visible tab, if any updateSelection(); - fireSelectedTabChange(); + fireSelectedTabChange(false); } } } @@ -389,7 +390,7 @@ public class TabSheet extends AbstractComponentContainer if (selected == null) { setSelected(tabComponent); - fireSelectedTabChange(); + fireSelectedTabChange(false); } super.addComponent(tabComponent); @@ -525,17 +526,17 @@ public class TabSheet extends AbstractComponentContainer } /** - * Returns the {@link Tab} (metadata) for a component. The {@link Tab} + * Returns the {@link Tab} (metadata) with the given index. The {@link Tab} * object can be used for setting caption,icon, etc for the tab. * - * @param position - * the position of the tab - * @return The tab in the given position, or null if the position is out of + * @param index + * the index of the tab + * @return The tab with the given index, or null if the index is out of * bounds. */ - public Tab getTab(int position) { - if (position >= 0 && position < getComponentCount()) { - return getTab(components.get(position)); + public Tab getTab(int index) { + if (index >= 0 && index < getComponentCount()) { + return getTab(components.get(index)); } else { return null; } @@ -545,13 +546,29 @@ public class TabSheet extends AbstractComponentContainer * Sets the selected tab. The tab is identified by the tab content * component. Does nothing if the tabsheet doesn't contain the component. * - * @param c + * @param component + * the component of the tab to select */ - public void setSelectedTab(Component c) { - if (c != null && components.contains(c) && !c.equals(selected)) { - setSelected(c); + public void setSelectedTab(Component component) { + setSelectedTab(component, false); + } + + /** + * Sets the selected tab. The tab is identified by the tab content + * component. Does nothing if the tabsheet doesn't contain the component. + * + * @param component + * the component of the tab to select + * @param userOriginated + * <code>true</code> if the event originates from the client + * side, <code>false</code> otherwise + */ + public void setSelectedTab(Component component, boolean userOriginated) { + if (component != null && components.contains(component) + && !component.equals(selected)) { + setSelected(component); updateSelection(); - fireSelectedTabChange(); + fireSelectedTabChange(userOriginated); markAsDirty(); getRpcProxy(TabsheetClientRpc.class).revertToSharedStateSelection(); } @@ -593,21 +610,23 @@ public class TabSheet extends AbstractComponentContainer * the given tab. * * @param tab + * the tab to select */ public void setSelectedTab(Tab tab) { if (tab != null) { - setSelectedTab(tab.getComponent()); + setSelectedTab(tab.getComponent(), false); } } /** - * Sets the selected tab, identified by its position. Does nothing if the + * Sets the selected tab, identified by its index. Does nothing if the * position is out of bounds. * - * @param position + * @param index + * the index of the tab to select */ - public void setSelectedTab(int position) { - setSelectedTab(getTab(position)); + public void setSelectedTab(int index) { + setSelectedTab(getTab(index)); } /** @@ -742,7 +761,7 @@ public class TabSheet extends AbstractComponentContainer // is changed. // Other cases are handled implicitly by removeComponent() and // addComponent()addTab() - fireSelectedTabChange(); + fireSelectedTabChange(false); } // Tab associations are not changed, but metadata is swapped between @@ -779,26 +798,39 @@ public class TabSheet extends AbstractComponentContainer * @author Vaadin Ltd. * @since 3.0 */ - public static class SelectedTabChangeEvent extends Component.Event { + public static class SelectedTabChangeEvent extends Component.Event + implements HasUserOriginated { + + private final boolean userOriginated; /** - * New instance of selected tab change event + * Creates a new instance of the event. * * @param source - * the Source of the event. + * the source of the event + * @param userOriginated + * <code>true</code> if the event originates from the client + * side, <code>false</code> otherwise */ - public SelectedTabChangeEvent(Component source) { + public SelectedTabChangeEvent(Component source, + boolean userOriginated) { super(source); + this.userOriginated = userOriginated; } /** - * TabSheet where the event occurred. + * The TabSheet where the event occurred. * - * @return the Source of the event. + * @return the TabSheet where the event occurred */ public TabSheet getTabSheet() { return (TabSheet) getSource(); } + + @Override + public boolean isUserOriginated() { + return userOriginated; + } } /** @@ -857,10 +889,27 @@ public class TabSheet extends AbstractComponentContainer } /** - * Sends an event that the currently selected tab has changed. + * Sends an event originating from the server, telling that the currently + * selected tab has changed. + * + * @deprecated use {@link #fireSelectedTabChange(boolean)} to indicate the + * origin of the event */ + @Deprecated protected void fireSelectedTabChange() { - fireEvent(new SelectedTabChangeEvent(this)); + fireSelectedTabChange(false); + } + + /** + * Sends an event that the currently selected tab has changed. + * + * @param userOriginated + * <code>true</code> if the event originates from the client + * side, <code>false</code> otherwise + * @since + */ + protected void fireSelectedTabChange(boolean userOriginated) { + fireEvent(new SelectedTabChangeEvent(this, userOriginated)); } /** @@ -1200,7 +1249,7 @@ public class TabSheet extends AbstractComponentContainer tabState.enabled = enabled; if (updateSelection()) { - fireSelectedTabChange(); + fireSelectedTabChange(false); } markAsDirty(); } @@ -1215,7 +1264,7 @@ public class TabSheet extends AbstractComponentContainer tabState.visible = visible; if (updateSelection()) { - fireSelectedTabChange(); + fireSelectedTabChange(false); } markAsDirty(); } @@ -1519,7 +1568,7 @@ public class TabSheet extends AbstractComponentContainer boolean selected = DesignAttributeHandler.readAttribute("selected", attr, Boolean.class); if (selected) { - this.setSelectedTab(tab.getComponent()); + this.setSelectedTab(tab.getComponent(), false); } } } diff --git a/server/src/test/java/com/vaadin/tests/server/component/tabsheet/TabSheetTest.java b/server/src/test/java/com/vaadin/tests/server/component/tabsheet/TabSheetTest.java index b48a3477ab..91cfe7712a 100644 --- a/server/src/test/java/com/vaadin/tests/server/component/tabsheet/TabSheetTest.java +++ b/server/src/test/java/com/vaadin/tests/server/component/tabsheet/TabSheetTest.java @@ -6,11 +6,17 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import java.util.Iterator; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import org.junit.Assert; import org.junit.Test; +import com.vaadin.shared.ui.tabsheet.TabsheetServerRpc; +import com.vaadin.shared.ui.tabsheet.TabsheetState; +import com.vaadin.ui.Button; import com.vaadin.ui.Component; +import com.vaadin.ui.ComponentTest; import com.vaadin.ui.Label; import com.vaadin.ui.TabSheet; import com.vaadin.ui.TabSheet.SelectedTabChangeEvent; @@ -284,4 +290,50 @@ public class TabSheetTest { listener.assertActualComponentIs(lbl3); assertEquals(lbl3, tabSheet.getSelectedTab()); } + + public static class TestTabsheet extends TabSheet { + public TestTabsheet(Component... components) { + super(components); + } + + public String getKey(Component c) { + return keyMapper.key(c); + } + + @Override + public TabsheetState getState() { + return super.getState(); + } + } + + @Test + public void userOriginatedForSelectionEvent() { + AtomicBoolean userOriginated = new AtomicBoolean(false); + AtomicReference<Component> selected = new AtomicReference<>(); + + Button b1 = new Button("b1"); + Button b2 = new Button("b2"); + Button b3 = new Button("b3"); + Button b4 = new Button("b4"); + TestTabsheet tabsheet = new TestTabsheet(b1, b2, b3, b4); + tabsheet.addSelectedTabChangeListener(e -> { + userOriginated.set(e.isUserOriginated()); + selected.set(e.getTabSheet().getSelectedTab()); + }); + + tabsheet.setSelectedTab(b2); + Assert.assertFalse(userOriginated.get()); + Assert.assertEquals(b2, selected.get()); + + TabsheetServerRpc rpc = ComponentTest.getRpcProxy(tabsheet, + TabsheetServerRpc.class); + rpc.setSelected(tabsheet.getKey(b1)); + Assert.assertTrue(userOriginated.get()); + Assert.assertEquals(b1, selected.get()); + + tabsheet.setSelectedTab(tabsheet.getTab(b4)); + Assert.assertFalse(userOriginated.get()); + Assert.assertEquals(b4, selected.get()); + + } } |