diff options
author | Leif Åstrand <leif@vaadin.com> | 2014-12-09 21:05:22 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2014-12-09 19:25:47 +0000 |
commit | d8c47250a2a8a47fd75e9f48f21aac1ff6aa2170 (patch) | |
tree | c9cae6bb22e5cb7cf556dd31cb59befab3531173 /server | |
parent | 4157a770fd0df18f6f57b9b9cb017985251f4d0b (diff) | |
download | vaadin-framework-d8c47250a2a8a47fd75e9f48f21aac1ff6aa2170.tar.gz vaadin-framework-d8c47250a2a8a47fd75e9f48f21aac1ff6aa2170.zip |
Add Grid.addRow (#13334)
Change-Id: I2c317b920d29ca8a74658ef3b980c6bc2a7622ac
Diffstat (limited to 'server')
4 files changed, 344 insertions, 14 deletions
diff --git a/server/src/com/vaadin/data/util/IndexedContainer.java b/server/src/com/vaadin/data/util/IndexedContainer.java index f9cc4c482a..b851baf674 100644 --- a/server/src/com/vaadin/data/util/IndexedContainer.java +++ b/server/src/com/vaadin/data/util/IndexedContainer.java @@ -242,10 +242,11 @@ public class IndexedContainer extends return true; } - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#addItem() + /** + * {@inheritDoc} + * <p> + * The item ID is generated from a sequence of Integers. The id of the first + * added item is 1. */ @Override public Object addItem() { @@ -363,10 +364,11 @@ public class IndexedContainer extends new IndexedContainerItem(newItemId), true); } - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object) + /** + * {@inheritDoc} + * <p> + * The item ID is generated from a sequence of Integers. The id of the first + * added item is 1. */ @Override public Object addItemAfter(Object previousItemId) { @@ -392,10 +394,11 @@ public class IndexedContainer extends newItemId), true); } - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Indexed#addItemAt(int) + /** + * {@inheritDoc} + * <p> + * The item ID is generated from a sequence of Integers. The id of the first + * added item is 1. */ @Override public Object addItemAt(int index) { diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index 1fad4d2304..5f3bea98ca 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -31,6 +31,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; import com.google.gwt.thirdparty.guava.common.collect.Sets; import com.google.gwt.thirdparty.guava.common.collect.Sets.SetView; @@ -3592,4 +3594,79 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, public CellStyleGenerator getCellStyleGenerator() { return cellStyleGenerator; } + + /** + * Adds a row to the underlying container. The order of the parameters + * should match the current visible column order. + * <p> + * Please note that it's generally only safe to use this method during + * initialization. After Grid has been initialized and the visible column + * order might have been changed, it's better to instead add items directly + * to the underlying container and use {@link Item#getItemProperty(Object)} + * to make sure each value is assigned to the intended property. + * + * @param values + * the cell values of the new row, in the same order as the + * visible column order, not <code>null</code>. + * @return the item id of the new row + * @throws IllegalArgumentException + * if values is null + * @throws IllegalArgumentException + * if its length does not match the number of visible columns + * @throws IllegalArgumentException + * if a parameter value is not an instance of the corresponding + * property type + * @throws UnsupportedOperationException + * if the container does not support adding new items + */ + public Object addRow(Object... values) { + if (values == null) { + throw new IllegalArgumentException("Values cannot be null"); + } + + Indexed dataSource = getContainerDataSource(); + List<String> columnOrder = getState(false).columnOrder; + + if (values.length != columnOrder.size()) { + throw new IllegalArgumentException("There are " + + columnOrder.size() + " visible columns, but " + + values.length + " cell values were provided."); + } + + // First verify all parameter types + for (int i = 0; i < columnOrder.size(); i++) { + Object propertyId = getPropertyIdByColumnId(columnOrder.get(i)); + + Class<?> propertyType = dataSource.getType(propertyId); + if (values[i] != null && !propertyType.isInstance(values[i])) { + throw new IllegalArgumentException("Parameter " + i + "(" + + values[i] + ") is not an instance of " + + propertyType.getCanonicalName()); + } + } + + Object itemId = dataSource.addItem(); + try { + Item item = dataSource.getItem(itemId); + for (int i = 0; i < columnOrder.size(); i++) { + Object propertyId = getPropertyIdByColumnId(columnOrder.get(i)); + Property<Object> property = item.getItemProperty(propertyId); + property.setValue(values[i]); + } + } catch (RuntimeException e) { + try { + dataSource.removeItem(itemId); + } catch (Exception e2) { + getLogger().log(Level.SEVERE, + "Error recovering from exception in addRow", e); + } + throw e; + } + + return itemId; + } + + private static Logger getLogger() { + return Logger.getLogger(Grid.class.getName()); + } } diff --git a/server/tests/src/com/vaadin/data/util/TestIndexedContainer.java b/server/tests/src/com/vaadin/data/util/TestIndexedContainer.java index ddfee103c3..91e222af77 100644 --- a/server/tests/src/com/vaadin/data/util/TestIndexedContainer.java +++ b/server/tests/src/com/vaadin/data/util/TestIndexedContainer.java @@ -2,10 +2,9 @@ package com.vaadin.data.util; import java.util.List; -import org.junit.Assert; - import org.easymock.Capture; import org.easymock.EasyMock; +import org.junit.Assert; import com.vaadin.data.Container.Indexed.ItemAddEvent; import com.vaadin.data.Container.Indexed.ItemRemoveEvent; @@ -277,6 +276,38 @@ public class TestIndexedContainer extends AbstractInMemoryContainerTest { counter.assertNone(); } + public void testItemAdd_idSequence() { + IndexedContainer container = new IndexedContainer(); + Object itemId; + + itemId = container.addItem(); + assertEquals(Integer.valueOf(1), itemId); + + itemId = container.addItem(); + assertEquals(Integer.valueOf(2), itemId); + + itemId = container.addItemAfter(null); + assertEquals(Integer.valueOf(3), itemId); + + itemId = container.addItemAt(2); + assertEquals(Integer.valueOf(4), itemId); + } + + public void testItemAddRemove_idSequence() { + IndexedContainer container = new IndexedContainer(); + Object itemId; + + itemId = container.addItem(); + assertEquals(Integer.valueOf(1), itemId); + + container.removeItem(itemId); + + itemId = container.addItem(); + assertEquals( + "Id sequence should continue from the previous value even if an item is removed", + Integer.valueOf(2), itemId); + } + public void testItemAddedEvent() { IndexedContainer container = new IndexedContainer(); ItemSetChangeListener addListener = createListenerMockFor(container); diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridAddRowBuiltinContainerTest.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridAddRowBuiltinContainerTest.java new file mode 100644 index 0000000000..70c73eb516 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/grid/GridAddRowBuiltinContainerTest.java @@ -0,0 +1,219 @@ +/* + * Copyright 2000-2014 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.server.component.grid; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.data.Container; +import com.vaadin.data.Item; +import com.vaadin.data.util.BeanItem; +import com.vaadin.data.util.BeanItemContainer; +import com.vaadin.data.util.MethodProperty.MethodException; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.ui.Grid; + +public class GridAddRowBuiltinContainerTest { + Grid grid = new Grid(); + Container.Indexed container; + + @Before + public void setUp() { + container = grid.getContainerDataSource(); + + grid.addColumn("myColumn"); + } + + @Test + public void testSimpleCase() { + Object itemId = grid.addRow("Hello"); + + Assert.assertEquals(Integer.valueOf(1), itemId); + + Assert.assertEquals("There should be one item in the container", 1, + container.size()); + + Assert.assertEquals("Hello", + container.getItem(itemId).getItemProperty("myColumn") + .getValue()); + } + + @Test(expected = IllegalArgumentException.class) + public void testNullParameter() { + // cast to Object[] to distinguish from one null varargs value + grid.addRow((Object[]) null); + } + + @Test + public void testNullValue() { + // cast to Object to distinguish from a null varargs array + Object itemId = grid.addRow((Object) null); + + Assert.assertEquals(null, + container.getItem(itemId).getItemProperty("myColumn") + .getValue()); + } + + @Test(expected = IllegalArgumentException.class) + public void testAddInvalidType() { + grid.addRow(Integer.valueOf(5)); + } + + @Test + public void testMultipleProperties() { + grid.addColumn("myOther", Integer.class); + + Object itemId = grid.addRow("Hello", Integer.valueOf(3)); + + Item item = container.getItem(itemId); + Assert.assertEquals("Hello", item.getItemProperty("myColumn") + .getValue()); + Assert.assertEquals(Integer.valueOf(3), item.getItemProperty("myOther") + .getValue()); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidPropertyAmount() { + grid.addRow("Hello", Integer.valueOf(3)); + } + + @Test + public void testRemovedColumn() { + grid.addColumn("myOther", Integer.class); + grid.removeColumn("myColumn"); + + grid.addRow(Integer.valueOf(3)); + + Item item = container.getItem(Integer.valueOf(1)); + Assert.assertEquals("Default value should be used for removed column", + "", item.getItemProperty("myColumn").getValue()); + Assert.assertEquals(Integer.valueOf(3), item.getItemProperty("myOther") + .getValue()); + } + + @Test + public void testMultiplePropertiesAfterReorder() { + grid.addColumn("myOther", Integer.class); + + grid.setColumnOrder("myOther", "myColumn"); + + grid.addRow(Integer.valueOf(3), "Hello"); + + Item item = container.getItem(Integer.valueOf(1)); + Assert.assertEquals("Hello", item.getItemProperty("myColumn") + .getValue()); + Assert.assertEquals(Integer.valueOf(3), item.getItemProperty("myOther") + .getValue()); + } + + @Test + public void testInvalidType_NothingAdded() { + try { + grid.addRow(Integer.valueOf(5)); + + // Can't use @Test(expect = Foo.class) since we also want to verify + // state after exception was thrown + Assert.fail("Adding wrong type should throw ClassCastException"); + } catch (IllegalArgumentException e) { + Assert.assertEquals("No row should have been added", 0, + container.size()); + } + } + + @Test + public void testUnsupportingContainer() { + setContainerRemoveColumns(new BeanItemContainer<Person>(Person.class)); + try { + + grid.addRow("name"); + + // Can't use @Test(expect = Foo.class) since we also want to verify + // state after exception was thrown + Assert.fail("Adding to BeanItemContainer container should throw UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + Assert.assertEquals("No row should have been added", 0, + container.size()); + } + } + + @Test + public void testCustomContainer() { + BeanItemContainer<Person> container = new BeanItemContainer<Person>( + Person.class) { + @Override + public Object addItem() { + BeanItem<Person> item = addBean(new Person()); + return getBeanIdResolver().getIdForBean(item.getBean()); + } + }; + + setContainerRemoveColumns(container); + + grid.addRow("name"); + + Assert.assertEquals(1, container.size()); + + Assert.assertEquals("name", container.getIdByIndex(0).getFirstName()); + } + + @Test + public void testSetterThrowing() { + BeanItemContainer<Person> container = new BeanItemContainer<Person>( + Person.class) { + @Override + public Object addItem() { + BeanItem<Person> item = addBean(new Person() { + @Override + public void setFirstName(String firstName) { + if ("name".equals(firstName)) { + throw new RuntimeException(firstName); + } else { + super.setFirstName(firstName); + } + } + }); + return getBeanIdResolver().getIdForBean(item.getBean()); + } + }; + + setContainerRemoveColumns(container); + + try { + + grid.addRow("name"); + + // Can't use @Test(expect = Foo.class) since we also want to verify + // state after exception was thrown + Assert.fail("Adding row should throw MethodException"); + } catch (MethodException e) { + Assert.assertEquals("Got the wrong exception", "name", e.getCause() + .getMessage()); + + Assert.assertEquals("There should be no rows in the container", 0, + container.size()); + } + } + + private void setContainerRemoveColumns(BeanItemContainer<Person> container) { + // Remove predefined column so we can change container + grid.removeAllColumns(); + grid.setContainerDataSource(container); + grid.removeAllColumns(); + grid.addColumn("firstName"); + } + +} |