summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java357
-rw-r--r--client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java178
2 files changed, 535 insertions, 0 deletions
diff --git a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java
new file mode 100644
index 0000000000..0a3edbd349
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java
@@ -0,0 +1,357 @@
+/*
+ * 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.client.ui.grid.datasources;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import com.vaadin.client.data.DataChangeHandler;
+import com.vaadin.client.data.DataSource;
+
+/**
+ * A simple list based on an in-memory data source for simply adding a list of
+ * row pojos to the grid. Based on a wrapped list instance which supports adding
+ * and removing of items.
+ *
+ * <p>
+ * Usage:
+ *
+ * <pre>
+ * ListDataSource&lt;Integer&gt; ds = new ListDataSource&lt;Integer&gt;(1, 2, 3, 4);
+ *
+ * // Add item to the data source
+ * ds.asList().add(5);
+ *
+ * // Remove item from the data source
+ * ds.asList().remove(3);
+ *
+ * // Add multiple items
+ * ds.asList().addAll(Arrays.asList(5, 6, 7));
+ * </pre>
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public class ListDataSource<T> implements DataSource<T> {
+
+ /**
+ * Wraps the datasource list and notifies the change handler of changing to
+ * the list
+ */
+ private class ListWrapper implements List<T> {
+
+ @Override
+ public int size() {
+ return ds.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return ds.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return contains(o);
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return new ListWrapperIterator(ds.iterator());
+ }
+
+ @Override
+ public Object[] toArray() {
+ return ds.toArray();
+ }
+
+ @Override
+ public <T> T[] toArray(T[] a) {
+ return toArray(a);
+ }
+
+ @Override
+ public boolean add(T e) {
+ if (ds.add(e)) {
+ if (changeHandler != null) {
+ changeHandler.dataAdded(ds.size() - 1, 1);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ int index = ds.indexOf(o);
+ if (ds.remove(o)) {
+ if (changeHandler != null) {
+ changeHandler.dataRemoved(index, 1);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ return ds.containsAll(c);
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends T> c) {
+ int idx = ds.size();
+ if (ds.addAll(c)) {
+ if (changeHandler != null) {
+ changeHandler.dataAdded(idx, c.size());
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends T> c) {
+ if (ds.addAll(index, c)) {
+ if (changeHandler != null) {
+ changeHandler.dataAdded(index, c.size());
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ if (ds.removeAll(c)) {
+ if (changeHandler != null) {
+ // Have to update the whole list as the removal does not
+ // have to be a continuous range
+ changeHandler.dataUpdated(0, ds.size());
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ if (ds.retainAll(c)) {
+ if (changeHandler != null) {
+ // Have to update the whole list as the retain does not
+ // have to be a continuous range
+ changeHandler.dataUpdated(0, ds.size());
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void clear() {
+ int size = ds.size();
+ ds.clear();
+ if (changeHandler != null) {
+ changeHandler.dataRemoved(0, size);
+ }
+ }
+
+ @Override
+ public T get(int index) {
+ return ds.get(index);
+ }
+
+ @Override
+ public T set(int index, T element) {
+ T prev = ds.set(index, element);
+ if (changeHandler != null) {
+ changeHandler.dataUpdated(index, 1);
+ }
+ return prev;
+ }
+
+ @Override
+ public void add(int index, T element) {
+ ds.add(index, element);
+ if (changeHandler != null) {
+ changeHandler.dataAdded(index, 1);
+ }
+ }
+
+ @Override
+ public T remove(int index) {
+ T removed = ds.remove(index);
+ if (changeHandler != null) {
+ changeHandler.dataRemoved(index, 1);
+ }
+ return removed;
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ return ds.indexOf(o);
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ return ds.lastIndexOf(o);
+ }
+
+ @Override
+ public ListIterator<T> listIterator() {
+ // TODO could be implemented by a custom iterator.
+ throw new UnsupportedOperationException(
+ "List iterators not supported at this time.");
+ }
+
+ @Override
+ public ListIterator<T> listIterator(int index) {
+ // TODO could be implemented by a custom iterator.
+ throw new UnsupportedOperationException(
+ "List iterators not supported at this time.");
+ }
+
+ @Override
+ public List<T> subList(int fromIndex, int toIndex) {
+ throw new UnsupportedOperationException("Sub lists not supported.");
+ }
+ }
+
+ /**
+ * Iterator returned by {@link ListWrapper}
+ */
+ private class ListWrapperIterator implements Iterator<T> {
+
+ private final Iterator<T> iterator;
+
+ /**
+ * Constructs a new iterator
+ */
+ public ListWrapperIterator(Iterator<T> iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public T next() {
+ return iterator.next();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException(
+ "Iterator.remove() is not supported by this iterator.");
+ }
+ }
+
+ /**
+ * Datasource for providing row pojo's
+ */
+ private final List<T> ds;
+
+ /**
+ * Wrapper that wraps the data source
+ */
+ private final ListWrapper wrapper;
+
+ /**
+ * Handler for listening to changes in the underlying list.
+ */
+ private DataChangeHandler changeHandler;
+
+ /**
+ * Constructs a new list data source.
+ * <p>
+ * Note: Modifications to the original list will not be reflected in the
+ * data source after the data source has been constructed. To add or remove
+ * items to the data source after it has been constructed use
+ * {@link ListDataSource#asList()}.
+ *
+ *
+ * @param datasource
+ * The list to use for providing the data to the grid
+ */
+ public ListDataSource(List<T> datasource) {
+ if (datasource == null) {
+ throw new IllegalArgumentException("datasource cannot be null");
+ }
+ ds = new ArrayList<T>(datasource);
+ wrapper = new ListWrapper();
+ }
+
+ /**
+ * Constructs a data source with a set of rows. You can dynamically add and
+ * remove rows from the data source via the list you get from
+ * {@link ListDataSource#asList()}
+ *
+ * @param rows
+ * The rows to initially add to the data source
+ */
+ public ListDataSource(T... rows) {
+ if (rows == null) {
+ ds = new ArrayList<T>();
+ } else {
+ ds = new ArrayList<T>(Arrays.asList(rows));
+ }
+ wrapper = new ListWrapper();
+ }
+
+ @Override
+ public void ensureAvailability(int firstRowIndex, int numberOfRows) {
+ if (firstRowIndex >= ds.size()) {
+ throw new IllegalStateException(
+ "Trying to fetch rows outside of array");
+ }
+ }
+
+ @Override
+ public T getRow(int rowIndex) {
+ return ds.get(rowIndex);
+ }
+
+ @Override
+ public int getEstimatedSize() {
+ return ds.size();
+ }
+
+ @Override
+ public void setDataChangeHandler(DataChangeHandler dataChangeHandler) {
+ this.changeHandler = dataChangeHandler;
+ }
+
+ /**
+ * Gets the list that backs this datasource. Any changes made to this list
+ * will be reflected in the datasource.
+ * <p>
+ * Note: The list is not the same list as passed into the data source via
+ * the constructor.
+ *
+ * @return Returns a list implementation that wraps the real list that backs
+ * the data source and provides events for the data source
+ * listeners.
+ */
+ public List<T> asList() {
+ return wrapper;
+ }
+}
diff --git a/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java b/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java
new file mode 100644
index 0000000000..5c5e88bf69
--- /dev/null
+++ b/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.client.ui.grid;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+import com.vaadin.client.data.DataChangeHandler;
+import com.vaadin.client.ui.grid.datasources.ListDataSource;
+
+/**
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public class ListDataSourceTest {
+
+ @Test
+ public void testDataSourceConstruction() throws Exception {
+
+ ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
+
+ assertEquals(4, ds.getEstimatedSize());
+ assertEquals(0, (int) ds.getRow(0));
+ assertEquals(1, (int) ds.getRow(1));
+ assertEquals(2, (int) ds.getRow(2));
+ assertEquals(3, (int) ds.getRow(3));
+
+ ds = new ListDataSource<Integer>(Arrays.asList(0, 1, 2, 3));
+
+ assertEquals(4, ds.getEstimatedSize());
+ assertEquals(0, (int) ds.getRow(0));
+ assertEquals(1, (int) ds.getRow(1));
+ assertEquals(2, (int) ds.getRow(2));
+ assertEquals(3, (int) ds.getRow(3));
+ }
+
+ @Test
+ public void testListAddOperation() throws Exception {
+
+ ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
+
+ DataChangeHandler handler = EasyMock
+ .createNiceMock(DataChangeHandler.class);
+ ds.setDataChangeHandler(handler);
+
+ handler.dataAdded(4, 1);
+ EasyMock.expectLastCall();
+
+ EasyMock.replay(handler);
+
+ ds.asList().add(4);
+
+ assertEquals(5, ds.getEstimatedSize());
+ assertEquals(0, (int) ds.getRow(0));
+ assertEquals(1, (int) ds.getRow(1));
+ assertEquals(2, (int) ds.getRow(2));
+ assertEquals(3, (int) ds.getRow(3));
+ assertEquals(4, (int) ds.getRow(4));
+ }
+
+ @Test
+ public void testListAddAllOperation() throws Exception {
+
+ ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
+
+ DataChangeHandler handler = EasyMock
+ .createNiceMock(DataChangeHandler.class);
+ ds.setDataChangeHandler(handler);
+
+ handler.dataAdded(4, 3);
+ EasyMock.expectLastCall();
+
+ EasyMock.replay(handler);
+
+ ds.asList().addAll(Arrays.asList(4, 5, 6));
+
+ assertEquals(7, ds.getEstimatedSize());
+ assertEquals(0, (int) ds.getRow(0));
+ assertEquals(1, (int) ds.getRow(1));
+ assertEquals(2, (int) ds.getRow(2));
+ assertEquals(3, (int) ds.getRow(3));
+ assertEquals(4, (int) ds.getRow(4));
+ assertEquals(5, (int) ds.getRow(5));
+ assertEquals(6, (int) ds.getRow(6));
+ }
+
+ @Test
+ public void testListRemoveOperation() throws Exception {
+
+ ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
+
+ DataChangeHandler handler = EasyMock
+ .createNiceMock(DataChangeHandler.class);
+ ds.setDataChangeHandler(handler);
+
+ handler.dataRemoved(3, 1);
+ EasyMock.expectLastCall();
+
+ EasyMock.replay(handler);
+
+ ds.asList().remove(2);
+
+ assertEquals(3, ds.getEstimatedSize());
+ assertEquals(0, (int) ds.getRow(0));
+ assertEquals(1, (int) ds.getRow(1));
+ assertEquals(3, (int) ds.getRow(2));
+ }
+
+ @Test
+ public void testListRemoveAllOperation() throws Exception {
+
+ ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
+
+ DataChangeHandler handler = EasyMock
+ .createNiceMock(DataChangeHandler.class);
+ ds.setDataChangeHandler(handler);
+
+ handler.dataRemoved(0, 3);
+ EasyMock.expectLastCall();
+
+ EasyMock.replay(handler);
+
+ ds.asList().removeAll(Arrays.asList(0, 2, 3));
+
+ assertEquals(1, ds.getEstimatedSize());
+ assertEquals(1, (int) ds.getRow(0));
+ }
+
+ @Test
+ public void testListClearOperation() throws Exception {
+
+ ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
+
+ DataChangeHandler handler = EasyMock
+ .createNiceMock(DataChangeHandler.class);
+ ds.setDataChangeHandler(handler);
+
+ handler.dataRemoved(0, 4);
+ EasyMock.expectLastCall();
+
+ EasyMock.replay(handler);
+
+ ds.asList().clear();
+
+ assertEquals(0, ds.getEstimatedSize());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testFetchingNonExistantItem() {
+ ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
+ ds.ensureAvailability(5, 1);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testUnsupportedIteratorRemove() {
+ ListDataSource<Integer> ds = new ListDataSource<Integer>(0, 1, 2, 3);
+ ds.asList().iterator().remove();
+ }
+
+}