/* * Copyright (c) 2007 Yahoo! Inc. All rights reserved. * Copyrights licensed under the MIT License. */ package hudson.plugins.plot; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.logging.Logger; import org.jfree.data.category.CategoryDataset; import org.jfree.data.general.AbstractDataset; /** * A {@link CategoryDataset} implementation that stores numeric data points * and corresponding URLs. This data structure is basically a table * with row and column names (keys). * * @author Nigel Daley */ public class PlotCategoryDataset extends AbstractDataset implements CategoryDataset { private static final long serialVersionUID = 9215482265757674967L; private static final Logger LOGGER = Logger.getLogger(PlotCategoryDataset.class.getName()); class DataElement { public final Number number; public final String url; public DataElement(Number n, String u) { this.number = n; this.url = u; } } /** The row keys */ private ArrayList<Comparable> rowKeys; /** The column keys */ private ArrayList<Comparable> columnKeys; /** The row data */ private ArrayList<HashMap<Comparable,DataElement>> data; /** The max number of builds to plot */ private int maxColumns; /** * Creates a new empty instance. */ public PlotCategoryDataset() { this.rowKeys = new ArrayList<Comparable>(); this.columnKeys = new ArrayList<Comparable>(); this.data = new ArrayList<HashMap<Comparable,DataElement>>(); } /** * Truncates the dataset to the <i>last</i> <code>maxColumns</code> * columns. * * @param maxColumns the maximum number columns that will appear to * be in the dataset. */ public void clipDataset(int maxColumns) { this.maxColumns = maxColumns; // Columns are lazily truncated when the data is queried. // Rows that contain no data when the columns are truncated are // removed here so that they don't show up in plot legends. if (getColumnCount() > 0) { Comparable lowColumn = getColumnKey(0); for (int i = data.size() - 1 ; i >= 0 ; i--) { HashMap<Comparable,DataElement> row = data.get(i); boolean removeRow = true; for (Comparable column : row.keySet()) { if (column.compareTo(lowColumn) >= 0) { removeRow = false; break; } } if (removeRow) { //LOGGER.info("Removing row " + data.indexOf(row)); data.remove(i); rowKeys.remove(i); } } } } // Values2D interface method public int getRowCount() { return rowKeys.size(); } // Values2D interface method public int getColumnCount() { int retVal = Math.min(columnKeys.size(),maxColumns); return retVal; } // Values2D interface method public Number getValue(int row, int column) { //LOGGER.info("("+row+","+column+")"); if (data.get(row) == null) return null; // make column relative to maxColumns int newColumn = column; if (columnKeys.size() > maxColumns) { newColumn = columnKeys.size() - maxColumns + column; } Comparable columnKey = columnKeys.get(newColumn); DataElement element = data.get(row).get(columnKey); if (element == null) return null; return element.number; } // KeyedValues2D interface method public Comparable getRowKey(int row) { return rowKeys.get(row); } // KeyedValues2D interface method public int getRowIndex(Comparable key) { return rowKeys.indexOf(key); } // KeyedValues2D interface method public List getRowKeys() { return rowKeys; } // KeyedValues2D interface method public Comparable getColumnKey(int column) { // make column relative to maxColumns int newColumn = column; if (columnKeys.size() > maxColumns) { newColumn = columnKeys.size() - maxColumns + column; } return columnKeys.get(newColumn); } // KeyedValues2D interface method public int getColumnIndex(Comparable key) { return columnKeys.indexOf(key); } // KeyedValues2D interface method public List getColumnKeys() { int firstIndex = Math.max(0, columnKeys.size() - maxColumns); int lastIndex = Math.max(0, columnKeys.size()); return columnKeys.subList(firstIndex, lastIndex); } // KeyedValues2D interface method /** * Gets the value with the given row and column keys. * * @param rowKey the row key * @param columnKey the column key * @return the value with the given row and column keys */ public Number getValue(Comparable rowKey, Comparable columnKey) { //LOGGER.info("("+rowKey+","+columnKey+")"); int rowIndex = rowKeys.indexOf(rowKey); if (rowIndex == -1 || data.get(rowIndex) == null) return null; DataElement element = (DataElement) data.get(rowIndex).get(columnKey); if (element == null) return null; return element.number; } /** * Returns the URL at the given row and column. * * @param row the row index * @param column the column index * @return the URL */ public String getUrl(int row, int column) { //LOGGER.info("("+row+","+column+")"); if (data.get(row) == null) return null; // make column relative to maxColumns int newColumn = column; if (columnKeys.size() > maxColumns) { newColumn = columnKeys.size() - maxColumns + column; } Comparable columnKey = columnKeys.get(newColumn); DataElement element = data.get(row).get(columnKey); if (element == null) return null; return element.url; } /** * Adds or updates a value. * * @param value the value to add * @param url the URL to add and associate with the value * @param rowKey the row key * @param columnKey the column key */ public void setValue(Number value, String url, Comparable rowKey, Comparable columnKey) { //LOGGER.info("Data point:"+value+","+url+","+rowKey+","+columnKey); int rowIndex = rowKeys.indexOf(rowKey); if (rowIndex == -1) { rowKeys.add(rowKey); rowIndex = rowKeys.size() - 1; data.add(new HashMap<Comparable,DataElement>()); } if (!columnKeys.contains(columnKey)) { boolean added = false; for (int i = 0; i < columnKeys.size(); i++) { Comparable key = columnKeys.get(i); if (key.compareTo(columnKey) >= 0) { columnKeys.add(i,columnKey); added = true; break; } } if (!added) columnKeys.add(columnKey); } //LOGGER.info("columnKeys.size():"+columnKeys.size()); DataElement element = new DataElement(value,url); data.get(rowIndex).put(columnKey, element); } }