package com.onaro.sanscreen.client.view; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; import org.apache.commons.lang3.StringUtils; import org.eclipse.core.runtime.IAdaptable; import com.onaro.client.swing.table.functional.FunctionalTableModel; import com.onaro.client.swing.table.functional.IFunction; import com.onaro.sanscreen.client.view.tabular.AbstractTabularTableModel; import com.onaro.util.jfc.ExportUtils; import com.onaro.util.jfc.grouping.GroupingTable; import com.onaro.util.jfc.tables.ColumnAdapter; public class GroupingDirectorUtils { protected GroupingDirectorUtils() { // do nothing } /** * Create a view on the GroupingDirector that is a simplified representation of the data in the GroupingTable. This * view contains the flattened (ungrouped) rows that are currently shown in the table (with filtering in effect and * in the sorted order shown in the table). The columns in the view are in the order that is currently shown in the * table. The data included in the view can be customized via setting the selectedOnly and allColumns flags. * * NOTE: This view is directly accessing the underlying table and is not thread-safe. Any actions that change the * table (data changes, filtering, sorting, etc) will invalidate this table model, with unpredictable results. * * @param groupingDirector * the input grouping director * @param selectedOnly * flag to indicate the resulting view should only contain the selected rows in the original table * @param allColumns * flag to indicate the resulting view should only contain the visible columns in the original table * @return a simplified version of the Grouping Director's table data */ private static TableModel getTableModelView(GroupingDirector groupingDirector, boolean selectedOnly, boolean allColumns) { GroupingTable groupingTable = groupingDirector.getGroupingTable(); ColumnAdapter columnAdapter = groupingDirector.getColumnAdapter(); int columnCount = columnAdapter.getColumnCount(); final Map columnsMap = new HashMap(columnCount); Map columnNames = new HashMap(columnCount); for (int modelIndex = 0; modelIndex < columnCount; modelIndex++) { // Skip system columns if (columnAdapter.isSystem(modelIndex)) { continue; } // Skip hidden columns unless allColumns flag is true if (!allColumns && !columnAdapter.isVisible(modelIndex)) { continue; } String columnName = columnAdapter.getName(modelIndex); if (StringUtils.isBlank(columnName)) { columnName = columnAdapter.getShortDescription(modelIndex); } Integer viewIndex = Integer.valueOf(groupingTable.convertColumnIndexToView(modelIndex + 1)); columnsMap.put(viewIndex, Integer.valueOf(modelIndex)); columnNames.put(viewIndex, columnName); } final List columnsList = new ArrayList(columnsMap.keySet()); Collections.sort(columnsList); final List columnNamesList = new ArrayList(columnsList.size()); for (Integer columnIndex : columnsList) { String columnName = columnNames.get(columnIndex); columnNamesList.add(columnName); } final List rowsInEncapsulatedModel = new ArrayList(groupingTable.getRowCount()); int[] selectedRows = null; if (selectedOnly) { selectedRows = groupingTable.getSelectedRows(); } else { int rowCount = groupingTable.getRowCount(); selectedRows = new int[rowCount]; for (int i = 0; i < rowCount; i++) { selectedRows[i] = i; } } for (int rowIndex : selectedRows) { // Only include the children of group nodes if the node is collapsed (double-counted otherwise): if (groupingTable.getTree().isCollapsed(rowIndex)) { rowsInEncapsulatedModel.addAll(groupingTable.getChildRowsInEncapsulatedModel(rowIndex)); } else if (groupingTable.isLeaf(rowIndex)) { rowsInEncapsulatedModel.add(groupingTable.getRowInEncapsulatedModel(rowIndex)); } } final TableModel encapsulatedModel = groupingTable.getEncapsulatedTableModel(); return new AbstractTableModel() { private static final long serialVersionUID = 1L; @Override public String getColumnName(int column) { return columnNamesList.get(column); } public int getColumnCount() { return columnsList.size(); } public int getRowCount() { return rowsInEncapsulatedModel.size(); } public Object getValueAt(int rowIndex, int columnIndex) { Integer rowInModel = rowsInEncapsulatedModel.get(rowIndex); Integer columnInModel = columnsMap.get(columnsList.get(columnIndex)); return encapsulatedModel.getValueAt(rowInModel, columnInModel); } }; } public static String exportGroupingTableToCSV(GroupingDirector groupingDirector, boolean includeHeader, boolean selectedOnly, boolean allColumns) { TableModel exportableTableModel = getTableModelView(groupingDirector, selectedOnly, allColumns); return ExportUtils.exportTableToCSV(exportableTableModel, includeHeader); } public static String exportGroupingTableToHTML(GroupingDirector groupingDirector, boolean includeHeader, boolean selectedOnly, boolean allColumns) { TableModel exportableTableModel = getTableModelView(groupingDirector, selectedOnly, allColumns); return ExportUtils.exportTableToHTML(exportableTableModel, includeHeader); } /** * Evaluate a given function for a given row with the grouping director's current data. * @param The type of the grouping director row, usually {@link IAdaptable} * @param The output type returned by the function evaluation * @param The type of the function to evaluate * @param groupingDirector the target grouping director * @param functionClass the function to evaluate * @param row the input row for the function * @return the function output for the input row * @throws IllegalArgumentException if the grouping director's table model is not a FunctionalTableModel * @throws IllegalArgumentException if the function to evaluate is not registered with the grouping director's table model */ public static > O evaluateFunction(GroupingDirector groupingDirector, Class functionClass, R row) { F function = getFunction(groupingDirector, functionClass); O output = function.evaluate(row); return output; } /** * Evaluate a given function for a given rows with the grouping director's current data. * @param The type of the grouping director row, usually {@link IAdaptable} * @param The output type returned by the function evaluation * @param The type of the function to evaluate * @param groupingDirector the target grouping director * @param functionClass the function to evaluate * @param rows the input rows for the function * @return a map of the input row to the function output for the input row * @throws IllegalArgumentException if the grouping director's table model is not a FunctionalTableModel * @throws IllegalArgumentException if the function to evaluate is not registered with the grouping director's table model */ public static > Map evaluateFunction(GroupingDirector groupingDirector, Class functionClass, Collection rows) { F function = getFunction(groupingDirector, functionClass); Map results = new HashMap(rows.size()); for (R row : rows) { O output = function.evaluate(row); results.put(row, output); } return results; } /** * Retrieve a given function with the grouping director's current data. * @param The type of the grouping director row, usually {@link IAdaptable} * @param The output type returned by the function evaluation * @param The type of the function * @param groupingDirector the target grouping director * @param functionClass the function interface * @return the function instance * @throws IllegalArgumentException if the grouping director's table model is not a FunctionalTableModel * @throws IllegalArgumentException if the function to evaluate is not registered with the grouping director's table model */ public static > F getFunction(GroupingDirector groupingDirector, Class functionClass) { AbstractTabularTableModel tableModel = groupingDirector.getTableModel(); if (tableModel == null) { throw new IllegalArgumentException("GroupingDirector's table model is not a functional table model"); //$NON-NLS-1$ } @SuppressWarnings("unchecked") FunctionalTableModel functionalTableModel = (FunctionalTableModel)tableModel; F function = functionalTableModel.getFunction(functionClass); if (function == null) { throw new IllegalArgumentException("Function not registered with table model: " + functionClass.getName()); //$NON-NLS-1$ } return function; } }