Java tutorial
/* * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt */ package edu.caltech.ipac.firefly.ui.table; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.gen2.table.client.CellRenderer; import com.google.gwt.gen2.table.client.ColumnDefinition; import com.google.gwt.gen2.table.event.client.PageLoadEvent; import com.google.gwt.gen2.table.event.client.RowCountChangeEvent; import com.google.gwt.gen2.table.event.client.RowCountChangeHandler; import com.google.gwt.gen2.table.override.client.FlexTable; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; import edu.caltech.ipac.firefly.data.table.SelectionInfo; import edu.caltech.ipac.firefly.data.table.TableData; import edu.caltech.ipac.firefly.data.table.TableDataView; import edu.caltech.ipac.firefly.resbundle.images.TableImages; import edu.caltech.ipac.firefly.rpc.SearchServices; import edu.caltech.ipac.firefly.ui.GwtUtil; import edu.caltech.ipac.firefly.ui.PopupUtil; import edu.caltech.ipac.firefly.ui.ServerTask; import edu.caltech.ipac.firefly.ui.table.renderer.AlignRenderer; import edu.caltech.ipac.firefly.util.ListenerSupport; import edu.caltech.ipac.util.StringUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.SortedSet; /** * An customized version of the {@link com.google.gwt.gen2.table.client.PagingScrollTable} that updated the header and * footer tables to reflect the currently visible rows. */ public class SelectionTable extends BasicPagingTable { private static final String NOT_SELECTED = "<i><font color='red'>No rows selected</font></i>"; /** * The previous list of visible column definitions. */ private List<ColumnDefinition<TableData.Row, ?>> lastColDefs = null; /** * The {@link com.google.gwt.user.client.ui.CheckBox} used to select all rows. */ private CheckBox selectAllCheckBox = new CheckBox(); private SelectionInfo selectInfo = new SelectionInfo(); private ListenerSupport<SelectListener> listeners = new ListenerSupport<SelectListener>(); private int totalRows; private int lastPageSize; private SelectionTableDef tableDef; /** * Construct a new {@link SelectionTable}. * * @param tableModel the underlying table model * @param tableDataView the column definitions */ public SelectionTable(String name, DataSetTableModel tableModel, TableDataView tableDataView) { this(name, tableModel, new SelectionTableDef(tableDataView), tableDataView.getTotalRows()); } public SelectionTable(String name, DataSetTableModel tableModel, DatasetTableDef dsTableDef, int totalRows) { super(name, tableModel, new DataTable(), dsTableDef); tableDef = (SelectionTableDef) this.getTableDefinition(); ((DataTable) getDataTable()).setTable(this); this.totalRows = totalRows; // Setup the selectAll checkbox selectAllCheckBox.addClickHandler(new ClickHandler() { public void onClick(ClickEvent ev) { if (selectAllCheckBox.getValue() && selectInfo.getSelectedCount() == 0) { selectAll(); } else { deselectAll(); } } }); selectInfo.setRowCount(getTableModel().getRowCount()); this.getTableModel().addRowCountChangeHandler(new RowCountChangeHandler() { public void onRowCountChange(RowCountChangeEvent event) { selectInfo.setRowCount(event.getNewRowCount()); } }); } //==================================================================== // selection support //==================================================================== public void addSelectionTableListener(SelectListener listener) { listeners.addListener(listener); } public boolean removeSelectionTableListener(SelectListener listener) { return listeners.removeListener(listener); } public void select(Integer... rowIdx) { if (rowIdx != null && rowIdx.length > 0) { for (int i : rowIdx) { int tblIdx = getTableIdx(i); selectInfo.select(i); setSelected(tblIdx, true); } fireSelectedEvent(); } } public boolean isSelected(int rowIdx) { return selectInfo.isSelected(rowIdx); } public boolean isSelectAll() { return selectInfo.isSelectAll(); } public void selectAll() { selectInfo.selectAll(); boolean singlePage = this.getRowCount() == totalRows; ArrayList<Integer> noaccessRows = singlePage ? new ArrayList<Integer>() : null; for (int i = 0; i < getRowCount(); i++) { TableData.Row row = getRowValue(i); setSelected(i, true); if (singlePage && !row.hasAccess()) { noaccessRows.add(i); } } if (noaccessRows != null && noaccessRows.size() > 0) { // if it's single page.. unselect the rows without access. deselect(noaccessRows.toArray(new Integer[noaccessRows.size()])); } fireSelectedEvent(); } public void deselect(final Integer... rowIdx) { if (rowIdx != null && rowIdx.length > 0) { for (int i : rowIdx) { int tblIdx = getTableIdx(i); selectInfo.deselect(i); setSelected(tblIdx, false); } fireSelectedEvent(); } } public SortedSet<Integer> getSelectedRows() { return selectInfo.getSelected(); } public void deselectAll() { selectInfo.deselectAll(); for (int i = 0; i <= getRowCount(); i++) { setSelected(i, false); } fireSelectedEvent(); } SelectionInfo getSelectInfo() { return selectInfo; } void setSelectionInfo(SelectionInfo selInfo) { selectInfo = selInfo; for (int i = 0; i <= getRowCount(); i++) { int absIdx = getAbsIdx(i); setSelected(i, isSelected(absIdx)); } fireSelectedEvent(); } //==================================================================== // //==================================================================== static interface SelectListener { void onRowSelectChange(SelectionTable table, SelectionInfo selectedIndices); } //==================================================================== // //==================================================================== protected void fireSelectedEvent() { selectAllCheckBox.setValue(isSelectAll()); listeners.fireEvent(new ListenerSupport.Function<SelectListener>() { public void execute(SelectListener sl) { sl.onRowSelectChange(SelectionTable.this, selectInfo); } }); } private static String getCheckboxHtml(Object value) { boolean selected = Boolean.parseBoolean(String.valueOf(value)); return "<input type='checkbox' " + (selected ? "checked " : "") + "/>"; } /** * @param viewIdx relative index to the current page. * @param isSelected */ private void setSelected(int viewIdx, boolean isSelected) { if (viewIdx >= 0 && viewIdx < getRowCount()) { TableData.Row row = getRowValue(viewIdx); if (row != null) { boolean hasAccess = row.hasAccess(); getDataTable().setHTML(viewIdx, 0, hasAccess ? getCheckboxHtml(isSelected) : ""); } } } boolean fillWidthPending; @Override protected void onDataTableRendered() { if (getPageSize() > 200) { // large page size: do fast rendering if (!fillWidthPending && isAttached() && getResizePolicy() == ResizePolicy.FILL_WIDTH) { fillWidthPending = true; DeferredCommand.addCommand(new Command() { public void execute() { fillWidthPending = false; fillWidth(); } }); } resizeTablesVertically(); fireEvent(new PageLoadEvent(getCurrentPage())); } else { super.onDataTableRendered(); } } @Override protected void setData(int firstRow, Iterator<TableData.Row> rows) { tableDef.getSelectedRows().clear(); List<TableData.Row> copy = new ArrayList<TableData.Row>(); for (int idx = 0; rows.hasNext(); idx++) { TableData.Row row = rows.next(); copy.add(row); if (selectInfo.isSelected(firstRow + idx)) { tableDef.getSelectedRows().add(row.getRowIdx()); } } // Set the actual data super.setData(firstRow, copy.iterator()); if (lastPageSize != this.getPageSize()) { lastPageSize = this.getPageSize(); recalculateSelectAllBox(); } } /** * Update the header table to match the data table. */ protected void updateHeaderTable(List<ColumnDefinition<TableData.Row, ?>> colDefs, boolean force) { super.updateHeaderTable(colDefs, force); setColumnWidth(0, colDefs.get(0).getPreferredColumnWidth()); recalculateSelectAllBox(); } private void recalculateSelectAllBox() { boolean hasAccess = true; if (this.getRowCount() == totalRows) { hasAccess = false; for (TableData.Row r : this.getRowValues()) { if (r.hasAccess()) { hasAccess = true; break; } } } Widget box = hasAccess ? selectAllCheckBox : new SimplePanel(); FlexTable.FlexCellFormatter formatter = getHeaderTable().getFlexCellFormatter(); getHeaderTable().setWidget(LABEL_IDX, 0, box); formatter.setHorizontalAlignment(LABEL_IDX, 0, HasHorizontalAlignment.ALIGN_CENTER); final Image image = new Image(TableImages.Creator.getInstance().getFilterIn()); GwtUtil.setStyle(image, "marginTop", "2px"); image.setTitle("Filter on selected rows"); image.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { SortedSet<Integer> srows = getSelectedRows(); if (srows != null && srows.size() > 0) { doFilter(); } else { PopupUtil.showMinimalError(image, NOT_SELECTED); } } }); getHeaderTable().setWidget(FILTER_IDX, 0, image); formatter.setHorizontalAlignment(FILTER_IDX, 0, HasHorizontalAlignment.ALIGN_CENTER); } private void doFilter() { if (getDataModel() == null) return; final SortedSet<Integer> srows = getSelectedRows(); final ArrayList<Integer> lrows = new ArrayList<Integer>(srows.size()); lrows.addAll(srows); if (srows != null && srows.size() > 0) { ServerTask<List<String>> t = new ServerTask<List<String>>() { @Override public void onSuccess(List<String> result) { getDataModel() .setFilters(Arrays.asList(TableDataView.ROWID + " IN " + StringUtils.toString(result))); getDataModel().getCurrentData().deselectAll(); getDataModel().fireDataStaleEvent(); } @Override public void doTask(AsyncCallback<List<String>> passAlong) { SearchServices.App.getInstance().getDataFileValues( getDataModel().getCurrentData().getMeta().getSource(), lrows, TableDataView.ROWID, passAlong); } }; t.start(); } } //==================================================================== // //==================================================================== @SuppressWarnings("deprecation") public static class DataTable extends BasicPagingTable.DataTable { private SelectionTable table; public DataTable() { } void setTable(SelectionTable table) { this.table = table; } @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); switch (DOM.eventGetType(event)) { // Prevent native inputs from being checked case Event.ONCLICK: { // Get the target row Element targetCell = getEventTargetCell(event); if (targetCell == null) { return; } if (StringUtils.isEmpty(targetCell.getInnerHTML())) { return; // ignore cell without a checkbox } Element targetRow = DOM.getParent(targetCell); int targetRowIndex = getRowIndex(targetRow); // Select the row if (targetCell == targetRow.getFirstChild()) { int absIdx = table.getAbsIdx(targetRowIndex); if (table.isSelected(absIdx)) { table.deselect(absIdx); } else { table.select(absIdx); } } } break; } } } //==================================================================== // //==================================================================== public static class SelectionTableDef extends DatasetTableDef { static final CellRenderer<TableData.Row, String> alignRenderer = new AlignRenderer( HasHorizontalAlignment.ALIGN_CENTER); private List<Integer> selectedRows = new ArrayList<Integer>(); public SelectionTableDef(TableDataView def) { super(def); addColumnDefinition(0, new ColDef() { { setMinimumColumnWidth(30); setPreferredColumnWidth(30); setMaximumColumnWidth(30); setColumnSortable(false); setImmutable(true); } @Override public CellRenderer<TableData.Row, String> getCellRenderer() { return alignRenderer; } public String getCellValue(TableData.Row rowValue) { return rowValue.hasAccess() ? getCheckboxHtml(selectedRows.contains(rowValue.getRowIdx())) : ""; } public void setCellValue(TableData.Row rowValue, String cellValue) { // not implemented } public String getTitle() { return "selected"; } }); } public List<Integer> getSelectedRows() { return selectedRows; } } }