/** * Copyright (C) 2001-2017 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.gui.viewer.metadata.model; import com.rapidminer.example.Attribute; import com.rapidminer.example.AttributeRole; import com.rapidminer.example.ExampleSet; import com.rapidminer.gui.viewer.metadata.AttributeStatisticsPanel; import com.rapidminer.gui.viewer.metadata.event.AttributeStatisticsEvent; import com.rapidminer.gui.viewer.metadata.event.AttributeStatisticsEvent.EventType; import com.rapidminer.gui.viewer.metadata.event.AttributeStatisticsEventListener; import java.awt.Font; import java.lang.ref.WeakReference; import javax.swing.event.EventListenerList; import org.jfree.chart.ChartTheme; import org.jfree.chart.JFreeChart; import org.jfree.chart.StandardChartTheme; /** * Abstract model for the {@link AttributeStatisticsPanel}. See implementations for details. * * @author Marco Boeck * */ public abstract class AbstractAttributeStatisticsModel { /** the {@link Attribute} for this model */ private final Attribute attribute; /** stores the {@link ExampleSet} as a {@link WeakReference} */ private final WeakReference<ExampleSet> weakExampleSet; /** if not <code>null</code>, the attribute is a special attribute */ private final String specialAttName; /** if true, the panel should be drawn in an alternating color scheme */ private boolean alternating; /** if true, the display should be enlarged */ private boolean enlarged; /** if true, the construction value will be displayed */ private boolean showConstruction; /** the number of missing values */ protected double missing; /** the construction value for the attribute */ private final String construction; /** event listener for this model */ private final EventListenerList eventListener; /** * Inits the * * @param exampleSet * @param attribute */ protected AbstractAttributeStatisticsModel(final ExampleSet exampleSet, final Attribute attribute) { this.attribute = attribute; this.weakExampleSet = new WeakReference<>(exampleSet); this.specialAttName = exampleSet.getAttributes().findRoleByName(attribute.getName()).getSpecialName(); this.construction = attribute.getConstruction(); this.eventListener = new EventListenerList(); } /** * Adds a {@link AttributeStatisticsEventListener} which will be informed of all changes to this * model. * * @param listener */ public void registerEventListener(final AttributeStatisticsEventListener listener) { eventListener.add(AttributeStatisticsEventListener.class, listener); } /** * Removes the {@link AttributeStatisticsEventListener} from this model. * * @param listener */ public void removeEventListener(final AttributeStatisticsEventListener listener) { eventListener.remove(AttributeStatisticsEventListener.class, listener); } /** * Sets if this panel should be drawn in an alternating color scheme (slightly darker) to make * reading of many rows easier. * * @param alternating */ public void setAlternating(final boolean alternating) { if (this.alternating != alternating) { this.alternating = alternating; fireAlternatingChangedEvent(); } } /** * Returns <code>true</code> if this is an alternating attribute statistics model. * * @return */ public boolean isAlternating() { return alternating; } /** * Gets the enlarged status which determines how many information to display. * * @return */ public boolean isEnlarged() { return enlarged; } /** * Sets the enlarged status. * * @param enlarged */ public void setEnlarged(final boolean enlarged) { this.enlarged = enlarged; if (enlarged && getExampleSetOrNull() != null) { prepareCharts(); } fireEnlargedChangedEvent(); } /** * Gets the show construction status which determines if the construction value is shown. * * @return */ public boolean isShowConstruction() { return showConstruction; } /** * Sets the show construction status. * * @param showConstruction */ public void setShowConstruction(final boolean showConstruction) { this.showConstruction = showConstruction; fireShowConstructionChangedEvent(); } /** * Returns <code>true</code> if this attribute has a special {@link AttributeRole}; * <code>false</code> otherwise. * * @return */ public boolean isSpecialAtt() { return specialAttName != null; } /** * Returns the name of the special {@link AttributeRole} for this {@link Attribute}. If this is * not a special attribute, returns <code>null</code> . * * @return */ public String getSpecialAttName() { return specialAttName; } /** * Gets the {@link Attribute} backing this model. * * @return */ public Attribute getAttribute() { return attribute; } /** * Gets the {@link ExampleSet} backing this model or <code>null</code> if the * {@link WeakReference} to it was removed. * * @return */ public ExampleSet getExampleSetOrNull() { return weakExampleSet.get(); } /** * Fire when the show construction status has changed. */ protected void fireShowConstructionChangedEvent() { fireEvent(EventType.SHOW_CONSTRUCTION_CHANGED); } /** * Fire when the enlarged status has changed. */ protected void fireEnlargedChangedEvent() { fireEvent(EventType.ENLARGED_CHANGED); } /** * Fire when the statistics of an attribute have changed. */ protected void fireStatisticsChangedEvent() { fireEvent(EventType.STATISTICS_CHANGED); } /** * Fire when alternation has changed. */ protected void fireAlternatingChangedEvent() { fireEvent(EventType.ALTERNATING_CHANGED); } /** * Fires the given {@link EventType}. * * @param type */ protected void fireEvent(final EventType type) { Object[] listeners = eventListener.getListenerList(); // Process the listeners last to first for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == AttributeStatisticsEventListener.class) { AttributeStatisticsEvent e = new AttributeStatisticsEvent(type); ((AttributeStatisticsEventListener) listeners[i + 1]).modelChanged(e); } } } /** * Updates the statistics of this model via the given {@link ExampleSet}. * * @param exampleSet * the {@link ExampleSet} for which the attribute statistics should be updated. No * reference to it is stored to prevent memory leaks. */ public abstract void updateStatistics(ExampleSet exampleSet); /** * Returns the number of missing values. * * @return */ public double getNumberOfMissingValues() { return missing; } /** * Returns the construction value for this attribute. * * @return */ public String getConstruction() { return construction; } /** * Returns the given {@link JFreeChart} for the given index. If the given index is invalid, * returns <code>null</code>. * * @param index * @return */ public abstract JFreeChart getChartOrNull(int index); /** * Prepares the charts if needed. */ protected abstract void prepareCharts(); /** * Changes the font of {@link JFreeChart}s to Sans Serif. This method uses a * {@link StandardChartTheme} to do so, so any changes to the look of the chart must be done * after calling this method. * * @param chart * the chart to change fonts for */ protected static void setDefaultChartFonts(JFreeChart chart) { final ChartTheme chartTheme = StandardChartTheme.createJFreeTheme(); if (StandardChartTheme.class.isAssignableFrom(chartTheme.getClass())) { StandardChartTheme standardTheme = (StandardChartTheme) chartTheme; // The default font used by JFreeChart cannot render japanese etc symbols final Font oldExtraLargeFont = standardTheme.getExtraLargeFont(); final Font oldLargeFont = standardTheme.getLargeFont(); final Font oldRegularFont = standardTheme.getRegularFont(); final Font oldSmallFont = standardTheme.getSmallFont(); final Font extraLargeFont = new Font(Font.SANS_SERIF, oldExtraLargeFont.getStyle(), oldExtraLargeFont.getSize()); final Font largeFont = new Font(Font.SANS_SERIF, oldLargeFont.getStyle(), oldLargeFont.getSize()); final Font regularFont = new Font(Font.SANS_SERIF, oldRegularFont.getStyle(), oldRegularFont.getSize()); final Font smallFont = new Font(Font.SANS_SERIF, oldSmallFont.getStyle(), oldSmallFont.getSize()); standardTheme.setExtraLargeFont(extraLargeFont); standardTheme.setLargeFont(largeFont); standardTheme.setRegularFont(regularFont); standardTheme.setSmallFont(smallFont); standardTheme.apply(chart); } } }