package com.constellio.app.ui.framework.components; import static com.constellio.app.ui.i18n.i18n.$; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import com.constellio.app.modules.rm.ui.components.RMMetadataDisplayFactory; import com.constellio.app.modules.rm.wrappers.Document; import com.constellio.app.modules.rm.wrappers.Folder; import com.constellio.app.ui.application.ConstellioUI; import com.constellio.app.ui.entities.RecordVO; import com.constellio.app.ui.framework.buttons.BaseButton; import com.constellio.app.ui.framework.components.fields.number.BaseIntegerField; import com.constellio.app.ui.framework.components.table.RecordVOTable; import com.constellio.app.ui.framework.components.table.SelectionTableAdapter; import com.constellio.app.ui.framework.containers.RecordVOLazyContainer; import com.constellio.app.ui.framework.containers.SearchResultContainer; import com.constellio.app.ui.pages.base.BaseViewImpl; import com.constellio.app.ui.pages.search.AdvancedSearchPresenter; import com.vaadin.data.Validator; import com.vaadin.event.ItemClickEvent; import com.vaadin.event.ItemClickEvent.ItemClickListener; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Component; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; import com.vaadin.ui.themes.ValoTheme; public class SearchResultSimpleTable extends SelectionTableAdapter implements SearchResultTable { public static final String TABLE_STYLE = "search-result-table"; public static final String CHECKBOX_PROPERTY = "checkbox"; private static final int MAX_SELECTION_RANGE = 100; private int lastSelectedItemIndex = -1; private Set<Object> selectedItemIds; private Set<Object> deselectedItemIds; private Set<SelectionChangeListener> listeners; private RecordVOLazyContainer recordVOContainer; private boolean allItemsSelected; public SearchResultSimpleTable(RecordVOLazyContainer container, final AdvancedSearchPresenter presenter) { super(); this.recordVOContainer = container; RecordVOTable adaptee = new RecordVOTable(container); adaptee.setWidth("100%"); adaptee.setColumnCollapsingAllowed(true); adaptee.setColumnReorderingAllowed(true); adaptee.addItemClickListener(new ItemClickListener() { @Override public void itemClick(ItemClickEvent event) { // if (event.isDoubleClick()) { Object itemId = event.getItemId(); RecordVO recordVO = recordVOContainer.getRecordVO((int) itemId); Window recordWindow = new BaseWindow(); recordWindow.setWidth("90%"); recordWindow.setHeight("90%"); String typeCode = recordVO.getSchema().getTypeCode(); //TODO add event if(typeCode.equals(Document.SCHEMA_TYPE) || typeCode.equals(Folder.SCHEMA_TYPE)) { recordWindow.setContent(new RecordDisplay(recordVO, new RMMetadataDisplayFactory())); } else { recordWindow.setContent(new RecordDisplay(recordVO)); } presenter.logRecordView(recordVO); UI.getCurrent().addWindow(recordWindow); // } } }); // TODO Make header visible // TODO Make all columns appear (DataProvider in AdvancedSearchPresenter listeners = new HashSet<>(); selectedItemIds = new HashSet<>(); deselectedItemIds = new HashSet<>(); adaptee.setColumnExpandRatio(SearchResultContainer.SEARCH_RESULT_PROPERTY, 1); // addStyleName(TABLE_STYLE); setTable(adaptee); getToggleButton().setVisible(false); } public List<String> getSelectedRecordIds() { List<String> result = new ArrayList<>(); for (Object itemId : selectedItemIds) { RecordVO record = recordVOContainer.getRecordVO((int) itemId); result.add(record.getId()); } return result; } public List<String> getUnselectedRecordIds() { List<String> result = new ArrayList<>(); for (Object itemId : deselectedItemIds) { RecordVO record = recordVOContainer.getRecordVO((int) itemId); result.add(record.getId()); } return result; } public boolean isSelectAll() { return allItemsSelected; } public void addSelectionChangeListener(SelectionChangeListener listener) { listeners.add(listener); } public VerticalLayout createSummary(Component alwaysActive, final Component... extra) { return createSummary(Arrays.asList(alwaysActive), extra); } public VerticalLayout createSummary(List<Component> alwaysActive, final Component... extra) { return createSummary(alwaysActive, Arrays.asList(extra)); } public VerticalLayout createSummary(List<Component> alwaysActive, final List<Component> extra) { Label totalCount = new Label($("SearchResultTable.count", recordVOContainer.size())); totalCount.addStyleName(ValoTheme.LABEL_BOLD); HorizontalLayout count = new HorizontalLayout(totalCount); count.setComponentAlignment(totalCount, Alignment.MIDDLE_LEFT); count.setSizeUndefined(); count.setSpacing(true); for (Component component : alwaysActive) { count.addComponent(component); count.setComponentAlignment(component, Alignment.MIDDLE_LEFT); } final HorizontalLayout selection = new HorizontalLayout(); selection.setSizeUndefined(); selection.setSpacing(true); for (Component component : extra) { component.setEnabled(selectedItemIds.size() > 0); selection.addComponent(component); selection.setComponentAlignment(component, Alignment.MIDDLE_LEFT); } VerticalLayout summaryBar = new VerticalLayout(count, selection); summaryBar.setWidth("100%"); addSelectionChangeListener(new SelectionChangeListener() { @Override public void selectionChanged(SelectionChangeEvent event) { boolean somethingSelected = event.isSelectAll() || !event.getSelected().isEmpty(); for (Component component : extra) { component.setEnabled(somethingSelected); } } }); return summaryBar; } private void fireSelectionChangeEvent() { recordVOContainer.refresh(); SelectionChangeEvent event = new SelectionChangeEvent(this, selectedItemIds, deselectedItemIds, allItemsSelected); for (SelectionChangeListener listener : listeners) { listener.selectionChanged(event); } updateVisibleCheckBoxes(); } public static class SelectionChangeEvent implements Serializable { private final SearchResultSimpleTable table; private final Set<Object> selected; private final Set<Object> deselected; private final boolean selectAll; public SelectionChangeEvent(SearchResultSimpleTable table, Set<Object> selected, Set<Object> deselected, boolean selectAll) { this.table = table; this.selected = selected; this.deselected = deselected; this.selectAll = selectAll; } public SearchResultSimpleTable getTable() { return table; } public Set<Object> getSelected() { return selected; } public Set<Object> getDeselected() { return deselected; } public boolean isSelectAll() { return selectAll; } } public interface SelectionChangeListener extends Serializable { void selectionChanged(SelectionChangeEvent event); } @Override public void selectAll() { lastSelectedItemIndex = recordVOContainer.size() - 1; allItemsSelected = true; selectedItemIds.clear(); deselectedItemIds.clear(); updateVisibleCheckBoxes(); fireSelectionChangeEvent(); } @Override public void deselectAll() { lastSelectedItemIndex = -1; allItemsSelected = false; selectedItemIds.clear(); deselectedItemIds.clear(); updateVisibleCheckBoxes(); fireSelectionChangeEvent(); } @Override public boolean isAllItemsSelected() { return allItemsSelected; } @Override public boolean isAllItemsDeselected() { return !allItemsSelected && deselectedItemIds.isEmpty(); } @Override public boolean isSelected(Object itemId) { boolean selectedItem; if (allItemsSelected) { selectedItem = !this.deselectedItemIds.contains(itemId); } else { selectedItem = this.selectedItemIds.contains(itemId); } return selectedItem; } @Override public void setSelected(Object itemId, boolean selected) { setSelected(itemId, selected, true); } private void setSelected(Object itemId, boolean selected, boolean fireSelectionChangeEvent) { if (selected) { this.selectedItemIds.add(itemId); deselectedItemIds.remove(itemId); } else { this.selectedItemIds.remove(itemId); deselectedItemIds.add(itemId); } if (fireSelectionChangeEvent) { fireSelectionChangeEvent(); } } public void askSelectionRange() { final Window window = new Window(); Label windowTitleLabel = new Label($("SearchResultSimpleTable.selectionWindowTitle")); Label fromLabel = new Label($("SearchResultSimpleTable.selectionFrom")); final BaseIntegerField fromField = new BaseIntegerField(); Label toLabel = new Label($("SearchResultSimpleTable.selectionTo")); final BaseIntegerField toField = new BaseIntegerField(); Button selectButton = new BaseButton($("SearchResultSimpleTable.selectButton")) { @Override protected void buttonClick(ClickEvent event) { if (fromField.isValid() && toField.isValid()) { int start = (Integer) fromField.getConvertedValue() - 1; int end = (Integer) toField.getConvertedValue(); List<?> itemIds = recordVOContainer.getItemIds(start, Math.min(MAX_SELECTION_RANGE, (end - start))); for (Object itemId : itemIds) { setSelected(itemId, true, false); } lastSelectedItemIndex = Math.max(0, end - 1); window.close(); fireSelectionChangeEvent(); } } }; fromField.addValidator(new Validator() { @Override public void validate(Object value) throws InvalidValueException { boolean invalidValue; int start = (Integer) fromField.getConvertedValue() - 1; if (start < 0) { invalidValue = true; } else if (start > recordVOContainer.size() + 1) { invalidValue = true; } else { invalidValue = false; } if (invalidValue) { int maxValue = Math.min(MAX_SELECTION_RANGE, recordVOContainer.size()); String errorMessage = $("SearchResultSimpleTable.invalidSelection", maxValue, 1, recordVOContainer.size()); showErrorMessage(errorMessage); throw new InvalidValueException(errorMessage); } } }); toField.addValidator(new Validator() { @Override public void validate(Object value) throws InvalidValueException { boolean invalidValue; int start = (Integer) fromField.getConvertedValue() - 1; int end = ((Integer) value); if (end < 0 || end < start) { invalidValue = true; } else if (end - start > MAX_SELECTION_RANGE) { invalidValue = true; } else if (end > recordVOContainer.size()) { invalidValue = true; } else { invalidValue = false; } if (invalidValue) { int maxValue = Math.min(MAX_SELECTION_RANGE, recordVOContainer.size()); String errorMessage = $("SearchResultSimpleTable.invalidSelection", maxValue, 1, recordVOContainer.size()); showErrorMessage(errorMessage); throw new InvalidValueException(errorMessage); } } }); int nextSelectionStartIndex = computeNextSelectionStartIndex() + 1; if (nextSelectionStartIndex > recordVOContainer.size()) { nextSelectionStartIndex = recordVOContainer.size(); } int nextSelectionEndIndex = computeNextSelectionEndIndex(); fromField.setRequired(true); fromField.setImmediate(true); fromField.setWidth("80px"); fromField.setValue("" + nextSelectionStartIndex); toField.setRequired(true); toField.setImmediate(true); toField.setWidth("80px"); toField.setValue("" + nextSelectionEndIndex); Button deselectAllButton = new BaseButton($("deselectAll")) { @Override protected void buttonClick(ClickEvent event) { deselectAll(); window.close(); } }; if (selectedItemIds.isEmpty()) { deselectAllButton.setVisible(false); window.setHeight("120px"); } else { window.setHeight("180px"); } HorizontalLayout formLayout = new HorizontalLayout(fromLabel, fromField, toLabel, toField, selectButton); formLayout.setSpacing(true); VerticalLayout mainLayout = new VerticalLayout(windowTitleLabel, formLayout, deselectAllButton); mainLayout.setSizeFull(); mainLayout.setSpacing(true); mainLayout.setComponentAlignment(deselectAllButton, Alignment.MIDDLE_CENTER); window.setContent(mainLayout); window.setWidth("450px"); window.center(); UI.getCurrent().addWindow(window); } private int computeNextSelectionStartIndex() { int nextSelectionStartIndex; if (lastSelectedItemIndex == -1) { nextSelectionStartIndex = 0; } else { nextSelectionStartIndex = lastSelectedItemIndex + 1; } return nextSelectionStartIndex; } private int computeNextSelectionEndIndex() { int nextSelectionEndIndex; if (lastSelectedItemIndex == -1) { nextSelectionEndIndex = Math.min(recordVOContainer.size(), MAX_SELECTION_RANGE); } else { nextSelectionEndIndex = Math.min(recordVOContainer.size(), lastSelectedItemIndex + MAX_SELECTION_RANGE); } return nextSelectionEndIndex; } private void showErrorMessage(String errorMessage) { BaseViewImpl view = (BaseViewImpl) ConstellioUI.getCurrent().getCurrentView(); view.showErrorMessage(errorMessage); } }