/******************************************************************************* * Copyright (c) 2008 Dennis Schenk, Peter Siska. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Dennis Schenk - initial implementation * Peter Siska - initial implementation *******************************************************************************/ package ch.unibe.iam.scg.archie.model; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * <p> * Holds objects (which implement the comparable interface) in tabular form. A * List of Strings serves as table headings. Cells are denoted by their x and y * coordinates. Headings have to be set before content. * </p> * * <p> * <strong>IMPORTANT</strong>: The dataset's content has to be composed out of data types * that implement the Comparable interface. This is to ensure that the contents * of the dataset can be sorted properly. * </p> * * Example Structure of a DataSet: * * <pre> * | Heading1| Heading2 | * ==================== * | Column0 | Column1 | * -------------------- * Row0 | 0,0 | 0,1 | * Row1 | 1,0 | 1,1 | * </pre> * * $Id: DataSet.java 747 2009-07-23 09:14:53Z peschehimself $ * * @author Peter Siska * @author Dennis Schenk * @version $Rev: 747 $ */ public class DataSet implements Iterable<Comparable<?>[]>, Cloneable { /** * Content of the DataSet: ArrayList with Comparable implementing objects * array. */ private List<Comparable<?>[]> content; /** Description of the columns */ private List<String> headings; /** The number of columns currently existing. */ private int width = 0; /** * Constructs an empty DataSet. Needs to be filled before it can be used. */ public DataSet() { this.content = new ArrayList<Comparable<?>[]>(); this.headings = new ArrayList<String>(); } /** * Constructs a <code>DataSet</code> with a list of objects arrays and a * heading list. * * @param content * @param headings * @throws IllegalArgumentException */ public DataSet(final List<Comparable<?>[]> content, final List<String> headings) throws IllegalArgumentException { // Checking Preconditions if (content == null || headings == null || content.isEmpty() || headings.isEmpty()) { throw new IllegalArgumentException("Argument lists and headings must not be null and not empty!"); } // Columns and headings length must match. if (content.get(0).length != headings.size()) { throw new IllegalArgumentException("Number of columns has to match provided number of headings!"); } this.content = content; this.headings = headings; this.width = this.content.get(0).length; } /** * @param x * Row index. * @param y * Column index. * @param value * Content. */ public void setCell(final int x, final int y, final Comparable<?> value) { // Checking Preconditions if (x > this.content.size() || y > this.content.get(x).length - 1) { throw new IllegalArgumentException( "Your trying to update a dataset element at a position that is greater than the dataset's boundaries."); } this.content.get(x)[y] = value; } /** * @param x * Row index. * @param y * Column index. * @return Comparable<?> at specified location, null if list is empty. */ public Comparable<?> getCell(final int x, final int y) { return this.content.get(x)[y]; } /** * @param x * Row index. * @return Comparable<?> Array of specified row. */ public Comparable<?>[] getRow(final int x) { return this.content.get(x); } /** * @param x * Row index. * @param obj * content. */ public void setRow(final int x, final Comparable<?>[] obj) { // Checking Preconditions if (x > this.content.size()) { throw new IllegalArgumentException( "Your trying to access a row in the dataset that is greater than the dataset's boundaries."); } this.content.set(x, obj); } /** * @param y * Column index. * @return Comparable<?> Array of specified column. */ public Comparable<?>[] getColumn(final int y) { ArrayList<Comparable<?>> column = new ArrayList<Comparable<?>>(this.content.size()); for (Comparable<?>[] objects : this.content) { column.add(objects[y]); } return column.toArray(new Comparable<?>[column.size()]); } /** * Adds an additional row to the dataSet and fills it with the provided row * content. * * @param row * Comparable<?> Array */ public void addRow(final Comparable<?>[] row) { // Checking Preconditions if (row.length != this.width) { throw new IllegalArgumentException( "The number of columns of a row being added to the dataset hat so equal the number of columns in the dataset."); } this.content.add(row); } /** * @return Iterator over content. */ public Iterator<Comparable<?>[]> iterator() { return this.content.iterator(); } /** * @return Content */ public List<Comparable<?>[]> getContent() { return this.content; } /** * DataSet can be empty, but not null. * * @param content */ public void setContent(final List<Comparable<?>[]> content) { // Checking Preconditions if (content == null) { throw new IllegalArgumentException("Content of a dataset can not be null!"); } if (this.headings.isEmpty()) { throw new IllegalArgumentException( "Can not set content before headings are set, also headings can not be empty!"); } if (!content.isEmpty() && content.get(0).length != this.headings.size()) { throw new IllegalArgumentException("Provided number of content does not match the number of headings!"); } this.content = content; this.width = this.headings.size(); } /** * @return List of table headings. */ public List<String> getHeadings() { return this.headings; } /** * Set headings. We assume that headings get set before content. * Precondition checking for same row length gets done by * <code>setContent</code>. * * @param headings * List */ public void setHeadings(final List<String> headings) { // Checking Preconditions if (headings == null || headings.isEmpty()) { throw new IllegalArgumentException("Provided table headings can not be null or empty!"); } this.headings = headings; } /** * Creates a string representation of this DataSet. This method is expensive * and should only be used for debugging purposes. * * @return String representation of this DataSet. */ @Override public String toString() { int[] columnWidths = new int[this.headings.size()]; int totalWidth = 0; // get the maximum width of the contents for each column for (int i = 0; i < columnWidths.length; i++) { // check headings lengths for (String heading : this.headings) { if (heading.toString().length() > columnWidths[i]) { columnWidths[i] = heading.toString().length(); } } // check columns lengths Comparable<?>[] column = this.getColumn(i); for (Comparable<?> length : column) { if (length.toString().length() > columnWidths[i]) { columnWidths[i] = length.toString().length(); } } } // compute total length for (int width : columnWidths) { totalWidth += width; } StringBuilder output = new StringBuilder(); // headings string for (int i = 0; i < this.headings.size(); i++) { String heading = this.headings.get(i); output.append("| "); output.append(heading); // heading is smaller than the maximum column width if (heading.length() < columnWidths[i]) { // fill up with blanks int difference = columnWidths[i] - heading.length(); for (int j = 0; j < difference; j++) { output.append(" "); } } // append a blank an the end of each heading output.append(" "); } output.append("\n"); // append heading separator for (int i = 0; i < totalWidth; i++) { output.append("-"); } // and three spaces plus for each column for (int i = 0; i < this.headings.size(); i++) { output.append("---"); } output.append("\n"); // print out rows for (int x = 0; x < this.content.size(); x++) { Comparable<?>[] row = this.getRow(x); // get columns for (int y = 0; y < row.length; y++) { String cellValue = this.getCell(x, y).toString(); output.append("| "); output.append(cellValue); if (cellValue.length() < columnWidths[y]) { // fill up with blanks int difference = columnWidths[y] - cellValue.length(); for (int j = 0; j < difference; j++) { output.append(" "); } } // append a blank at the end of each column output.append(" "); } output.append("\n"); } return output.toString(); } /** * Checks if the dataset contains any real data or is empty. * * @return True if the dataset's content is empty, false else. */ public boolean isEmpty() { return this.content.isEmpty(); } /** * @return a clone of this dataSet. */ @Override public DataSet clone() { DataSet cloneSet = null; try { cloneSet = (DataSet) super.clone(); cloneSet.content = new ArrayList<Comparable<?>[]>(cloneSet.content); cloneSet.headings = new ArrayList<String>(cloneSet.headings); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return cloneSet; } }