package org.activityinfo.ui.client.component.table; import com.google.common.collect.Lists; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.view.client.MultiSelectionModel; import com.google.gwt.view.client.RangeChangeEvent; import org.activityinfo.core.client.ProjectionKeyProvider; import org.activityinfo.core.client.ResourceLocator; import org.activityinfo.core.shared.Projection; import org.activityinfo.core.shared.criteria.Criteria; import org.activityinfo.core.shared.criteria.CriteriaIntersection; import org.activityinfo.model.form.FormClass; import org.activityinfo.ui.client.component.table.action.*; import org.activityinfo.ui.client.component.table.filter.FilterCellAction; import org.activityinfo.ui.client.component.table.filter.FilterHeader; import org.activityinfo.ui.client.style.table.CellTableResources; import org.activityinfo.ui.client.widget.CellTable; import org.activityinfo.ui.client.widget.loading.TableLoadingIndicator; import java.util.ArrayList; import java.util.List; /** * Reusable component to display Instances in a table */ public class InstanceTable implements IsWidget { // private static final Logger LOGGER = Logger.getLogger(InstanceTable.class.getName()); /** * The default column width, in {@code em} */ public static final int COLUMN_WIDTH = 10; private final ResourceLocator resourceLocator; private final CellTable<Projection> table; private final TableLoadingIndicator loadingIndicator; private final MultiSelectionModel<Projection> selectionModel = new MultiSelectionModel<>(new ProjectionKeyProvider()); private final List<TableHeaderAction> headerActions; private final InstanceTableView tableView; private final InstanceTableDataLoader dataLoader; private Criteria criteria; private FormClass rootFormClass; public InstanceTable(InstanceTableView tableView) { this.tableView = tableView; this.resourceLocator = tableView.getResourceLocator(); CellTableResources.INSTANCE.cellTableStyle().ensureInjected(); final TableHeaderActionBrowserEventHandler headerActionEventHandler = new TableHeaderActionBrowserEventHandler(this); table = new CellTable<Projection>(Integer.MAX_VALUE, CellTableResources.INSTANCE) { @Override protected void onBrowserEvent2(Event event) { super.onBrowserEvent2(event); headerActionEventHandler.onBrowserEvent(event); } }; table.setSkipRowHoverCheck(true); table.setSkipRowHoverFloatElementCheck(true); table.setSkipRowHoverStyleUpdate(true); table.setHeaderBuilder(new InstanceTableHeaderBuilder(this)); // Set the table to fixed width: we will provide explicit // column widths table.setWidth("100%", true); table.setSelectionModel(selectionModel); table.addRangeChangeHandler(new RangeChangeEvent.Handler() { @Override public void onRangeChange(RangeChangeEvent event) { table.redrawHeaders(); } }); dataLoader = new InstanceTableDataLoader(this); // Create our loading indicator which can also show failure loadingIndicator = new TableLoadingIndicator(); loadingIndicator.getRetryButton().addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { reload(); } }); table.setLoadingIndicator(loadingIndicator.asWidget()); headerActions = createHeaderActions(); } private List<TableHeaderAction> createHeaderActions() { final List<TableHeaderAction> actions = new ArrayList<>(); actions.add(new NewHeaderAction(this)); actions.add(new DeleteHeaderAction(this)); actions.add(new EditHeaderAction(this)); actions.add(new ImportHeaderAction(this)); actions.add(new ChooseColumnsHeaderAction(this)); return actions; } public void setCriteria(Criteria criteria) { this.criteria = criteria; } public void setColumns(List<FieldColumn> columns) { removeAllColumns(); for (FieldColumn column : columns) { final FilterCellAction filterAction = new FilterCellAction(this, column); table.addColumn(column, new FilterHeader(column, filterAction)); dataLoader.getFields().addAll(column.getFieldPaths()); } reload(); table.saveColumnWidthInformation(); } private void removeAllColumns() { while (table.getColumnCount() > 0) { table.removeColumn(0); } } public void reload() { dataLoader.reload(); } public Criteria buildQueryCriteria() { // we want the intersection of the base (class) criteria and // each of the column filters: the rows that satisfy the class AND // the Col1 filter AND Col2 filter final List<Criteria> intersection = Lists.newArrayList(criteria); for (int i = 0; i < table.getColumnCount(); i++) { final FieldColumn column = (FieldColumn) table.getColumn(i); final Criteria columnCriteria = column.getCriteria(); if (columnCriteria != null) { intersection.add(columnCriteria); } } return new CriteriaIntersection(intersection); } public MultiSelectionModel<Projection> getSelectionModel() { return selectionModel; } @Override public Widget asWidget() { return table; } public CellTable<Projection> getTable() { return table; } public ResourceLocator getResourceLocator() { return resourceLocator; } public void setRootFormClass(FormClass rootFormClass) { this.rootFormClass = rootFormClass; } public FormClass getRootFormClass() { return rootFormClass; } public List<TableHeaderAction> getHeaderActions() { return headerActions; } public InstanceTableView getTableView() { return tableView; } public TableLoadingIndicator getLoadingIndicator() { return loadingIndicator; } public void loadMore() { dataLoader.loadMore(); } }