package com.vaadin.tests.components.table; import java.util.AbstractList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.logging.Logger; import com.vaadin.server.VaadinSession; import com.vaadin.ui.Component; import com.vaadin.ui.Label; import com.vaadin.v7.data.Container; import com.vaadin.v7.data.Item; import com.vaadin.v7.data.Property; import com.vaadin.v7.data.util.AbstractContainer; import com.vaadin.v7.data.util.BeanItem; @SuppressWarnings("serial") public class ExpandingContainer extends AbstractContainer implements Container.Ordered, Container.Indexed, Container.ItemSetChangeNotifier { public static final List<String> PROPERTY_IDS = Arrays.asList("id", "column1", "column2"); private final Label sizeLabel; private final Logger log = Logger.getLogger(this.getClass().getName()); private int currentSize = 300; private boolean loggingEnabled; public ExpandingContainer(Label sizeLabel) { this.sizeLabel = sizeLabel; updateLabel(); } private void log(String message) { if (loggingEnabled) { log.info(message); } } // Expand container if we scroll past 85% public int checkExpand(int index) { log("checkExpand(" + index + ")"); if (index >= currentSize * 0.85) { final int oldsize = currentSize; currentSize = (int) (oldsize * 1.3333); log("*** getSizeWithHint(" + index + "): went past 85% of size=" + oldsize + ", new size=" + currentSize); updateLabel(); } return currentSize; } @Override public void fireItemSetChange() { super.fireItemSetChange(); } private void updateLabel() { sizeLabel.setValue("Container size: " + currentSize); } public void triggerItemSetChange() { log("*** triggerItemSetChange(): scheduling item set change event"); final VaadinSession session = VaadinSession.getCurrent(); new Thread() { @Override public void run() { ExpandingContainer.this.invoke(session, new Runnable() { @Override public void run() { log("*** Firing item set change event"); ExpandingContainer.this.fireItemSetChange(); } }); } }.start(); } private void invoke(VaadinSession session, Runnable action) { session.lock(); VaadinSession previousSession = VaadinSession.getCurrent(); VaadinSession.setCurrent(session); try { action.run(); } finally { session.unlock(); VaadinSession.setCurrent(previousSession); } } // Container @Override public BeanItem<MyBean> getItem(Object itemId) { if (!(itemId instanceof Integer)) { return null; } final int index = ((Integer) itemId).intValue(); return new BeanItem<>(new MyBean(index)); } @Override public Collection<Integer> getItemIds() { return new IntList(size()); } @Override public List<String> getContainerPropertyIds() { return PROPERTY_IDS; } @Override @SuppressWarnings("rawtypes") public Property/* <?> */ getContainerProperty(Object itemId, Object propertyId) { BeanItem<MyBean> item = getItem(itemId); return item != null ? item.getItemProperty(propertyId) : null; } @Override public Class<?> getType(Object propertyId) { return Component.class; } @Override public int size() { return currentSize; } @Override public boolean containsId(Object itemId) { if (!(itemId instanceof Integer)) { return false; } int index = ((Integer) itemId).intValue(); checkExpand(index); return index >= 0 && index < currentSize; } /** * @throws UnsupportedOperationException * always */ @Override public Item addItem(Object itemId) { throw new UnsupportedOperationException(); } /** * @throws UnsupportedOperationException * always */ @Override public Item addItem() { throw new UnsupportedOperationException(); } /** * @throws UnsupportedOperationException * always */ @Override public boolean removeItem(Object itemId) { throw new UnsupportedOperationException(); } /** * @throws UnsupportedOperationException * always */ @Override public boolean addContainerProperty(Object propertyId, Class<?> type, Object defaultValue) { throw new UnsupportedOperationException(); } /** * @throws UnsupportedOperationException * always */ @Override public boolean removeContainerProperty(Object propertyId) { throw new UnsupportedOperationException(); } /** * @throws UnsupportedOperationException * always */ @Override public boolean removeAllItems() { throw new UnsupportedOperationException(); } // Container.Indexed /** * @throws UnsupportedOperationException * always */ @Override public Object addItemAt(int index) { throw new UnsupportedOperationException(); } /** * @throws UnsupportedOperationException * always */ @Override public Item addItemAt(int index, Object newItemId) { throw new UnsupportedOperationException(); } @Override public Integer getIdByIndex(int index) { if (index < 0) { throw new IndexOutOfBoundsException("index < " + index); } final int size = currentSize; if (index >= size) { throw new IndexOutOfBoundsException( "index=" + index + " but size=" + size); } checkExpand(index); return index; } @Override public List<Integer> getItemIds(int startIndex, int numberOfItems) { if (numberOfItems < 0) { throw new IllegalArgumentException("numberOfItems < 0"); } final int size = currentSize; checkExpand(startIndex); if (startIndex < 0 || startIndex > size) { throw new IndexOutOfBoundsException( "startIndex=" + startIndex + " but size=" + size); } if (startIndex + numberOfItems > size) { numberOfItems = size - startIndex; } return new IntList(startIndex, numberOfItems); } @Override public int indexOfId(Object itemId) { if (!(itemId instanceof Integer)) { return -1; } final int index = ((Integer) itemId).intValue(); checkExpand(index); if (index < 0 || index >= currentSize) { return -1; } return index; } // Container.Ordered @Override public Integer nextItemId(Object itemId) { if (!(itemId instanceof Integer)) { return null; } int index = ((Integer) itemId).intValue(); checkExpand(index); if (index < 0 || index + 1 >= currentSize) { return null; } return index + 1; } @Override public Integer prevItemId(Object itemId) { if (!(itemId instanceof Integer)) { return null; } int index = ((Integer) itemId).intValue(); checkExpand(index); if (index - 1 < 0 || index >= currentSize) { return null; } return index - 1; } @Override public Integer firstItemId() { return currentSize == 0 ? null : 0; } @Override public Integer lastItemId() { final int size = currentSize; return size == 0 ? null : size - 1; } @Override public boolean isFirstId(Object itemId) { if (!(itemId instanceof Integer)) { return false; } final int index = ((Integer) itemId).intValue(); checkExpand(index); final int size = currentSize; return size > 0 && index == 0; } @Override public boolean isLastId(Object itemId) { if (!(itemId instanceof Integer)) { return false; } int index = ((Integer) itemId).intValue(); checkExpand(index); int size = currentSize; return size > 0 && index == size - 1; } /** * @throws UnsupportedOperationException * always */ @Override public Item addItemAfter(Object previousItemId) { throw new UnsupportedOperationException(); } /** * @throws UnsupportedOperationException * always */ @Override public Item addItemAfter(Object previousItemId, Object newItemId) { throw new UnsupportedOperationException(); } // Container.ItemSetChangeNotifier @Override @SuppressWarnings("deprecation") public void addListener(Container.ItemSetChangeListener listener) { super.addListener(listener); } @Override public void addItemSetChangeListener( Container.ItemSetChangeListener listener) { super.addItemSetChangeListener(listener); } @Override @SuppressWarnings("deprecation") public void removeListener(Container.ItemSetChangeListener listener) { super.removeListener(listener); } @Override public void removeItemSetChangeListener( Container.ItemSetChangeListener listener) { super.removeItemSetChangeListener(listener); } // IntList private static class IntList extends AbstractList<Integer> { private final int min; private final int size; public IntList(int size) { this(0, size); } public IntList(int min, int size) { if (size < 0) { throw new IllegalArgumentException("size < 0"); } this.min = min; this.size = size; } @Override public int size() { return size; } @Override public Integer get(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException(); } return min + index; } } // MyBean public class MyBean { private final int index; public MyBean(int index) { this.index = index; } public String getId() { return "ROW #" + index; } public String getColumn1() { return genText(); } public String getColumn2() { return genText(); } private String genText() { return "this is a line of text in row #" + index; } } public void logDetails(boolean enabled) { loggingEnabled = enabled; } }