| /** |
| * |
| * Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany) |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation |
| * |
| */ |
| package org.eclipse.osbp.xtext.table.common; |
| |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeSet; |
| |
| import com.vaadin.data.Container; |
| import com.vaadin.data.Property; |
| import com.vaadin.ui.AbstractSelect; |
| import com.vaadin.ui.CheckBox; |
| import com.vaadin.ui.Component; |
| import com.vaadin.ui.CustomTable; |
| import com.vaadin.ui.TextField; |
| |
| public class CheckboxSelectionCellSetFilterTable extends CellSetFilterTable { |
| |
| public enum UserSelectionState { |
| SINGLE { |
| @Override |
| protected String headerString() { return ""; } |
| @Override |
| protected UserSelectionState nextState() { return SINGLE; } |
| }, |
| NONE { |
| @Override |
| protected String headerString() { return "[X]"; } |
| @Override |
| protected UserSelectionState nextState() { return ALL; } |
| }, |
| SOME { |
| @Override |
| protected String headerString() { return "[X]"; } |
| @Override |
| protected UserSelectionState nextState() { return ALL; } |
| }, |
| ALL { |
| @Override |
| protected String headerString() { return "[-]"; } |
| @Override |
| protected UserSelectionState nextState() { return NONE; } |
| }; |
| |
| abstract protected String headerString(); |
| abstract protected UserSelectionState nextState(); |
| } |
| |
| private static final long serialVersionUID = -5042607921306226333L; |
| |
| private static final Object CHECKBOX_COLUMN_ID = new Integer(-99999); |
| private static final int CHECKBOX_COLUMN_WIDTH = 64; |
| |
| /** |
| * This map keeps track of all the created and attached checkboxes, by ItemId |
| */ |
| protected Map<Object, CheckBox> itemIdToCheckbox = new HashMap<Object, CheckBox>(); |
| /** |
| * This is the last selection value of the table. We need to keep track of what *was* selected, |
| * so that we can "deselect" the checkboxes. |
| */ |
| private Object lastSelectionValue; |
| private UserSelectionState userSelectionState = UserSelectionState.SOME; |
| /** |
| * A simple flag to stop a circular event |
| */ |
| private boolean ignorePropertyChangeEventInCheckBoxListener; |
| |
| @SuppressWarnings("deprecation") |
| public CheckboxSelectionCellSetFilterTable() { |
| super(); |
| |
| addGeneratedColumn(CHECKBOX_COLUMN_ID, new ColumnGenerator() { |
| private static final long serialVersionUID = -1241374338743135797L; |
| @Override |
| public Object generateCell(final CustomTable source, final Object itemId, Object columnId) { |
| final boolean selected = isItemIdSelected(source, itemId); |
| final CheckBox checkBox = new CheckBox("", selected); |
| checkBox.addValueChangeListener(new Property.ValueChangeListener() { |
| private static final long serialVersionUID = -7317483363411043081L; |
| |
| @Override |
| public void valueChange(Property.ValueChangeEvent valueChangeEvent) { |
| // Don't react to the event if we're being changed from the table-value-change event |
| if (!ignorePropertyChangeEventInCheckBoxListener) { |
| Boolean selected = (Boolean) valueChangeEvent.getProperty().getValue(); |
| if (selected) { |
| source.select(itemId); |
| } |
| else { |
| source.unselect(itemId); |
| } |
| setUserSelectionState(UserSelectionState.SOME); |
| } |
| } |
| }); |
| itemIdToCheckbox.put(itemId, checkBox); |
| if (selected) { |
| source.select(itemId); |
| } |
| |
| // Let's keep track of the checkboxes |
| checkBox.addAttachListener(new AttachListener() { |
| private static final long serialVersionUID = 2477921773100973217L; |
| |
| @Override |
| public void attach(AttachEvent event) { |
| itemIdToCheckbox.put(itemId, checkBox); |
| } |
| }); |
| checkBox.addDetachListener(new DetachListener() { |
| private static final long serialVersionUID = -2093323551404903130L; |
| |
| @Override |
| public void detach(DetachEvent event) { |
| itemIdToCheckbox.remove(itemId); |
| } |
| }); |
| checkBox.setWidth(CHECKBOX_COLUMN_WIDTH+"px"); |
| return checkBox; |
| } |
| }); |
| setFilterFieldVisible(CHECKBOX_COLUMN_ID, true); |
| |
| addListener(new HeaderClickListener() { |
| private static final long serialVersionUID = 1238308428039209109L; |
| |
| @Override |
| public void headerClick(HeaderClickEvent event) { |
| if (CHECKBOX_COLUMN_ID.equals(event.getPropertyId())) { |
| setUserSelectionState(userSelectionState.nextState()); |
| } |
| } |
| }); |
| //setColumnHeader(CHECKBOX_COLUMN_ID, userSelectionState.headerString()); |
| setUserSelectionState(UserSelectionState.SOME); |
| |
| this.lastSelectionValue = getValue(); |
| this.ignorePropertyChangeEventInCheckBoxListener = false; |
| |
| /* |
| * When the table value - i.e. the selection - changes, make sure |
| * any attached checkboxes are updated |
| */ |
| addValueChangeListener(new Property.ValueChangeListener() { |
| private static final long serialVersionUID = 6017328233818014479L; |
| |
| @Override |
| public void valueChange(Property.ValueChangeEvent event) { |
| ignorePropertyChangeEventInCheckBoxListener = true; |
| Object newSelectionValue = event.getProperty().getValue(); |
| /* Deselect all of the old checkboxes, then reselect all of the new ones. |
| If we wanted to be really smart, you could work out which checkboxes you wanted to change. |
| I don't care about being smart right now */ |
| setCheckBoxes(lastSelectionValue, false); |
| setCheckBoxes(newSelectionValue, true); |
| |
| lastSelectionValue = newSelectionValue; |
| ignorePropertyChangeEventInCheckBoxListener = false; |
| } |
| }); |
| try { |
| setColumnWidth(CHECKBOX_COLUMN_ID, CHECKBOX_COLUMN_WIDTH); |
| } |
| catch (Exception e) {} |
| } |
| |
| @Override |
| public void setMultiSelect(boolean multiSelect) { |
| if (multiSelect) { |
| setUserSelectionState(UserSelectionState.SOME); |
| } |
| else { |
| setUserSelectionState(UserSelectionState.SINGLE); |
| } |
| super.setMultiSelect(multiSelect); |
| } |
| |
| private void setUserSelectionState(UserSelectionState nextState) { |
| switch (nextState) { |
| case NONE: |
| setCheckBoxes(itemIdToCheckbox.keySet(), false); |
| break; |
| case ALL: |
| setCheckBoxes(itemIdToCheckbox.keySet(), true); |
| break; |
| case SOME: |
| break; |
| case SINGLE: |
| break; |
| } |
| userSelectionState = nextState; |
| setColumnHeader(CHECKBOX_COLUMN_ID, userSelectionState.headerString()); |
| } |
| |
| @Override |
| public void setContainerDataSource(Container newDataSource, Collection<?> visibleIds) { |
| // force selection column to be the first |
| if ((visibleIds.size() > 1) && (visibleIds.iterator().next() instanceof Integer)) { |
| Set<Integer> sortedVisibleIds = new TreeSet<Integer>(); |
| for (Object item : visibleIds) { |
| sortedVisibleIds.add((Integer) item); |
| } |
| visibleIds = sortedVisibleIds; |
| } |
| super.setContainerDataSource(newDataSource, visibleIds); |
| try { |
| setColumnWidth(CHECKBOX_COLUMN_ID, CHECKBOX_COLUMN_WIDTH); |
| } |
| catch (Exception e) {} |
| updateCheckboxColumnFilterLabel(); |
| } |
| |
| protected void updateCheckboxColumnFilterLabel() { |
| Map<Object, Component> columnIdToFilterMap = getColumnIdToFilterMap(); |
| Component c = null; |
| if (columnIdToFilterMap != null) { |
| c = columnIdToFilterMap.get(CHECKBOX_COLUMN_ID); |
| } |
| if (c instanceof TextField) { |
| String caption = ""; |
| if (getContainerDataSource() instanceof CellSetIndexedContainer) { |
| CellSetIndexedContainer dataSource = (CellSetIndexedContainer) getContainerDataSource(); |
| int allItems = dataSource.getAllItemIds().size(); |
| //int filteredItems = dataSource.getFilteredItemIds() == null ? 0 : dataSource.getFilteredItemIds().size(); |
| int selected = 0; |
| Object value = getValue(); |
| if (value instanceof Collection) { |
| selected = ((Collection) value).size(); |
| } |
| else if (value != null) { |
| selected = 1; |
| } |
| caption = selected+"/"+allItems; |
| } |
| ((TextField) c).setInputPrompt(caption); |
| c.setEnabled(false); |
| setFilterFieldVisible(CHECKBOX_COLUMN_ID, true); |
| } |
| } |
| |
| /** |
| * Set the value of all of the checkboxes |
| * @param itemIdOrIds |
| * @param value |
| */ |
| private void setCheckBoxes(Object itemIdOrIds, boolean value) { |
| if (itemIdOrIds instanceof Collection) { |
| Collection ids = (Collection) itemIdOrIds; |
| for (Object id : ids) { |
| setCheckBox(id, value); |
| } |
| } |
| else { |
| setCheckBox(itemIdOrIds, value); |
| } |
| } |
| |
| /** |
| * Set the value of the given checkbox |
| * @param id |
| * @param value |
| */ |
| public void setCheckBox(Object id, boolean value) { |
| CheckBox checkBox = itemIdToCheckbox.get(id); |
| if (checkBox != null) { |
| checkBox.setValue(value); |
| updateCheckboxColumnFilterLabel(); |
| } |
| } |
| |
| /** |
| * Is the given itemId selected ? |
| * @param select |
| * @param itemId |
| * @return |
| */ |
| protected boolean isItemIdSelected(AbstractSelect select, Object itemId) { |
| switch (userSelectionState) { |
| case NONE: |
| return false; |
| case ALL: |
| return true; |
| case SOME: |
| case SINGLE: |
| Object value = select.getValue(); |
| if (itemId == null || value == null) { |
| return false; |
| } |
| if (select.isMultiSelect()) { |
| return ((Collection) value).contains(itemId); |
| } |
| return itemId.equals(value); |
| } |
| return false; |
| } |
| |
| @Override |
| public String getColumnHeader(Object propertyId) { |
| if (getColumnHeaderMode() == ColumnHeaderMode.HIDDEN) { |
| return null; |
| } |
| if (propertyId == CHECKBOX_COLUMN_ID) { |
| return userSelectionState.headerString(); |
| } |
| return super.getColumnHeader(propertyId); |
| } |
| } |