package pt.ist.vaadinframework.ui; import java.lang.reflect.Method; import com.vaadin.data.Buffered; import com.vaadin.data.Container; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Component; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.themes.BaseTheme; /** * Creates a panel that view and manage a collection of items. * * @author David Martinho (davidmartinho@ist.utl.pt) */ public abstract class CollectionPanel extends CustomComponent implements Container.Viewer, Container.Editor, Container.ItemSetChangeListener, Container.ItemSetChangeNotifier { private static final long serialVersionUID = -8342680039386201881L; private static final String CSS_COLLECTION_PANEL = "v-collectionpanel"; private static final String CSS_COLLECTION_LABEL = "v-collectionpanel-label"; private static final String CSS_COLLECTION_ADD_BUTTON = "v-collectionpanel-add-button"; private static final String CSS_COLLECTION_REMOVE_BUTTON = "v-collectionpanel-remove-button"; private static final String CSS_COLLECTION_CONTAINER = "v-collectionpanel-container"; private GridLayout container; private boolean isRemovable = false; private Button addButton; private Button removeButton; private Label nameLabel; private Panel itemLayoutContainer; private Container itemContainer; public CollectionPanel(boolean isRemovable) { this.isRemovable = isRemovable; bindUi(); } private void bindUi() { container = new GridLayout(3, 3); container.addStyleName(CSS_COLLECTION_PANEL); container.setSizeFull(); bindAddButton(); bindRemoveButton(); bindCollectionNameLabel(); bindContainer(); setCompositionRoot(container); } private void bindAddButton() { addButton = new Button("+"); addButton.addStyleName(BaseTheme.BUTTON_LINK); addButton.addStyleName(CSS_COLLECTION_ADD_BUTTON); addButton.setSizeUndefined(); container.addComponent(addButton, 0, 1, 0, 1); container.setComponentAlignment(addButton, Alignment.TOP_RIGHT); } private void bindRemoveButton() { if (isRemovable) { removeButton = new Button("X"); removeButton.addStyleName(BaseTheme.BUTTON_LINK); removeButton.addStyleName(CSS_COLLECTION_REMOVE_BUTTON); removeButton.setSizeUndefined(); container.addComponent(removeButton, 2, 0, 2, 0); } } private void bindCollectionNameLabel() { nameLabel = new Label(); nameLabel.addStyleName(CSS_COLLECTION_LABEL); nameLabel.setSizeUndefined(); container.addComponent(nameLabel, 1, 0, 1, 0); container.setComponentAlignment(nameLabel, Alignment.BOTTOM_LEFT); } private void bindContainer() { itemLayoutContainer = new Panel(); VerticalLayout wrapper = new VerticalLayout(); wrapper.setMargin(true); wrapper.setSpacing(true); itemLayoutContainer.setContent(wrapper); itemLayoutContainer.addStyleName(CSS_COLLECTION_CONTAINER); container.addComponent(itemLayoutContainer, 1, 1, 2, 2); container.setColumnExpandRatio(1, 1f); } public Label getNameLabel() { return nameLabel; } public Button getAddButton() { return addButton; } public Button getRemoveButton() { return removeButton; } public Panel getItemLayoutContainer() { return itemLayoutContainer; } public void setWriteThrough(boolean state) { if (itemContainer != null) { ((Buffered) itemContainer).setWriteThrough(state); } } @Override public void setContainerDataSource(Container newDataSource) { if (itemContainer != newDataSource) { if (itemContainer != null) { if (itemContainer instanceof Container.ItemSetChangeNotifier) { ((Container.ItemSetChangeNotifier) itemContainer).removeListener(this); } } // Assigns new data source itemContainer = newDataSource; refreshComponents(itemContainer); // Adds listeners if (itemContainer != null) { if (itemContainer instanceof Container.ItemSetChangeNotifier) { ((Container.ItemSetChangeNotifier) itemContainer).addListener(this); } } } } public void refreshComponents() { refreshComponents(getContainerDataSource()); } protected abstract void refreshComponents(Container itemContainer); @Override public Container getContainerDataSource() { return itemContainer; } public void setNameLabel(String newValue) { this.nameLabel.setValue(newValue); } @Override public void containerItemSetChange(com.vaadin.data.Container.ItemSetChangeEvent event) { fireItemSetChangeEvent(); } private void fireItemSetChangeEvent() { fireEvent(new CollectionPanel.ItemSetChangeEvent(this)); requestRepaint(); } public class ItemSetChangeEvent extends Component.Event implements Container.ItemSetChangeEvent { private static final long serialVersionUID = -6054196818392240334L; public ItemSetChangeEvent(CollectionPanel source) { super(source); } @Override public Container getContainer() { return (Container) getSource(); } } @Override public void addListener(Container.ItemSetChangeListener listener) { addListener(CollectionPanel.ItemSetChangeEvent.class, listener, ITEM_SET_CHANGE_METHOD); } @Override public void removeListener(Container.ItemSetChangeListener listener) { removeListener(CollectionPanel.ItemSetChangeEvent.class, listener, ITEM_SET_CHANGE_METHOD); } private static final Method ITEM_SET_CHANGE_METHOD; static { try { ITEM_SET_CHANGE_METHOD = Container.ItemSetChangeListener.class.getDeclaredMethod("containerItemSetChange", new Class[] { Container.ItemSetChangeEvent.class }); } catch (final java.lang.NoSuchMethodException e) { // This should never happen throw new java.lang.RuntimeException("Internal error finding methods in CollectionPanel"); } } }