/* * RapidMiner * * Copyright (C) 2001-2014 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.datatable; import java.io.IOException; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.jfree.data.Range; import com.rapidminer.gui.plotter.charts.AbstractChartPanel.Selection; import com.rapidminer.report.Tableable; import com.rapidminer.tools.Tools; import com.rapidminer.tools.container.Pair; /** * This abstract data table implementation provides some default implementations for data * tables like listener handling. The method {@link #fireEvent()} can be used to promote * changes to all listeners. * * In addition, IO methods are also provided by this abstract implementation. * * @author Ingo Mierswa */ public abstract class AbstractDataTable implements DataTable, Tableable { /** The list of data table listeners. */ private List<WeakReference<DataTableListener>> weakReferencedListeners = new LinkedList<WeakReference<DataTableListener>>(); private List<DataTableListener> listeners = new LinkedList<DataTableListener>(); /** The name of the table. */ private String name; private HashSet<String> deselectionSet = new HashSet<String>(); private int deselectionCount; /** * This is a constructor that will not set any name. It is used for * serialization of subclasses. */ public AbstractDataTable() { this(""); } public AbstractDataTable(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String[] getColumnNames() { String[] result = new String[getNumberOfColumns()]; for (int i = 0; i < result.length; i++) result[i] = getColumnName(i); return result; } public void addDataTableListener(DataTableListener dataTableListener, boolean weakReference) { if (weakReference) { this.weakReferencedListeners.add(new WeakReference<DataTableListener>(dataTableListener)); } else { addDataTableListener(dataTableListener); } } public void addDataTableListener(DataTableListener dataTableListener) { listeners.add(dataTableListener); } public void removeDataTableListener(DataTableListener dataTableListener) { Iterator<WeakReference<DataTableListener>> it = weakReferencedListeners.iterator(); while(it.hasNext()) { DataTableListener l = it.next().get(); if (l == null || l == dataTableListener) { it.remove(); } } listeners.remove(dataTableListener); } protected void fireEvent() { // copy to avoid ConcurrentModification List<WeakReference<DataTableListener>> clone = new LinkedList<WeakReference<DataTableListener>>(weakReferencedListeners); Iterator<WeakReference<DataTableListener>> i = clone.iterator(); while (i.hasNext()) { WeakReference<DataTableListener> reference = i.next(); DataTableListener listener = reference.get(); if (listener != null) { listener.dataTableUpdated(this); } else { weakReferencedListeners.remove(reference); } } for (DataTableListener l : listeners) { l.dataTableUpdated(this); } } public String getValueAsString(DataTableRow row, int column) { final double value = row.getValue(column); if (Double.isNaN(value)) { return null; } else if (isDate(column)) { return Tools.formatDate(new Date((long)value)); } else if (isDateTime(column)) { return Tools.formatDateTime(new Date((long)value)); } else if (isTime(column)) { return Tools.formatTime(new Date((long)value)); } else if (isNominal(column)) { return mapIndex(column, (int)value); } else { return value + ""; } } public void write(PrintWriter out) throws IOException { out.println("# Generated by " + getName() + "[" + getClass().getName() + "]"); for (int j = 0; j < getNumberOfColumns(); j++) { out.print((j != 0 ? "\t" : "# ") + getColumnName(j)); } out.println(); Iterator i = iterator(); while (i.hasNext()) { DataTableRow row = (DataTableRow) i.next(); for (int j = 0; j < getNumberOfColumns(); j++) { out.print((j != 0 ? "\t" : "") + getValueAsString(row, j)); } out.println(); } out.flush(); } public boolean containsMissingValues() { Iterator<DataTableRow> i = iterator(); while (i.hasNext()) { DataTableRow row = i.next(); for (int j = 0; j < getNumberOfColumns(); j++) { if (Double.isNaN(row.getValue(j))) return true; } } return false; } public int getRowNumber() { return getNumberOfRows(); } public int getColumnNumber() { return getNumberOfColumns(); } public String getCell(int row, int column) { double value = getRow(row).getValue(column); if (isDate(column)) { return Tools.formatDate(new Date((long)value)); } else if (isDateTime(column)) { return Tools.formatDateTime(new Date((long)value)); } else if (isTime(column)) { return Tools.formatTime(new Date((long)value)); } else if (isNominal(column)) { return mapIndex(column, (int)value); } else { return Tools.formatIntegerIfPossible(value); } } public void prepareReporting() {} public void finishReporting() {} public boolean isFirstLineHeader() { return false; } public boolean isFirstColumnHeader() { return false; } @Override public boolean isDeselected(String id) { return deselectionSet.contains(id); } @Override public void setSelection(Selection selection) { deselectionCount = 0; Collection<Pair<String, Range>> delimiters = selection.getDelimiters(); Iterator<DataTableRow> i = iterator(); deselectionSet.clear(); while (i.hasNext()) { DataTableRow row = i.next(); boolean rowSelected = true; for (Pair<String, Range> delimiter : delimiters) { int col = getColumnIndex(delimiter.getFirst()); if (col >= 0 && col < this.getNumberOfColumns()) { double value = row.getValue(col); if (Double.isNaN(value)) { continue; } rowSelected &= delimiter.getSecond().contains(value); } } if (!rowSelected) { String id = row.getId(); if (id != null) { deselectionSet.add(id); deselectionCount++; } } } fireEvent(); } @Override public int getSelectionCount() { return getNumberOfRows() - deselectionCount; } }