/** * 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.new_plotter.configuration; import com.rapidminer.gui.new_plotter.PlotConfigurationError; import com.rapidminer.gui.new_plotter.configuration.DimensionConfig.PlotDimension; import com.rapidminer.gui.new_plotter.data.DimensionConfigData; import com.rapidminer.gui.new_plotter.engine.jfreechart.link_and_brush.listener.LinkAndBrushListener; import com.rapidminer.gui.new_plotter.engine.jfreechart.link_and_brush.listener.LinkAndBrushSelection; import com.rapidminer.gui.new_plotter.engine.jfreechart.link_and_brush.listener.LinkAndBrushSelection.SelectionType; import com.rapidminer.gui.new_plotter.engine.jfreechart.link_and_brush.listener.LinkAndBrushSelectionListener; import com.rapidminer.gui.new_plotter.utility.ContinuousColorProvider; import com.rapidminer.tools.container.Pair; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.jfree.data.Range; /** * @author Nils Woehler * */ public class LinkAndBrushMaster implements LinkAndBrushSelectionListener { private final PlotConfiguration plotConfig; private boolean zoomedIn = false; private boolean useGrayForOutliers = false; private Map<Integer, Range> rangeAxisIndexToZoomMap = new HashMap<Integer, Range>(); private Range domainAxisZoom; /** the list of {@link LinkAndBrushListener}s */ private transient List<WeakReference<LinkAndBrushListener>> listeners = new LinkedList<WeakReference<LinkAndBrushListener>>(); public LinkAndBrushMaster(PlotConfiguration plotConfig) { this.plotConfig = plotConfig; } public List<PlotConfigurationError> getErrors() { List<PlotConfigurationError> errors = new LinkedList<PlotConfigurationError>(); return errors; } public List<PlotConfigurationError> getWarnings() { List<PlotConfigurationError> warnings = new LinkedList<PlotConfigurationError>(); if (zoomedIn) { warnings.add(new PlotConfigurationError("zoomed_in")); } return warnings; } public boolean isZoomedIn() { return zoomedIn; } public void clearZooming(boolean fireEvent) { zoomedIn = false; domainAxisZoom = null; rangeAxisIndexToZoomMap.clear(); if (fireEvent) { informLinkAndBrushListeners(new LinkAndBrushSelection(SelectionType.RESTORE_AUTO_BOUNDS, new LinkedList<Pair<Integer, Range>>(), new LinkedList<Pair<Integer, Range>>())); } } public void clearRangeAxisZooming(boolean fireEvent) { rangeAxisIndexToZoomMap.clear(); zoomedIn = (domainAxisZoom != null); if (fireEvent) { informLinkAndBrushListeners(new LinkAndBrushSelection(SelectionType.RESTORE_AUTO_BOUNDS, new LinkedList<Pair<Integer, Range>>(), new LinkedList<Pair<Integer, Range>>())); } } public void clearDomainAxisZooming(boolean fireEvent) { domainAxisZoom = null; zoomedIn = (rangeAxisIndexToZoomMap.keySet().size() > 0); if (fireEvent) { informLinkAndBrushListeners(new LinkAndBrushSelection(SelectionType.RESTORE_AUTO_BOUNDS, new LinkedList<Pair<Integer, Range>>(), new LinkedList<Pair<Integer, Range>>())); } } /** * Returns <code>null</code> if isZoomedIn() returns <code>false</code>. */ public Range getDomainZoom() { return domainAxisZoom; } /** * Returns <code>null</code> if isZommedIn() returns <code>false</code> or if checking for a at * zoom time unknown {@link RangeAxisConfig}. */ public Range getRangeAxisZoom(RangeAxisConfig rangeAxisConfig, PlotConfiguration plotConfig) { int indexOf = plotConfig.getIndexOfRangeAxisConfigById(rangeAxisConfig.getId()); return rangeAxisIndexToZoomMap.get(indexOf); } @Override public void selectedLinkAndBrushRectangle(LinkAndBrushSelection e) { if (e.getType() == SelectionType.ZOOM_IN) { zoomedIn = true; // fetch domain axis range Pair<Integer, Range> domainAxisRange = e.getDomainAxisRange(); if (domainAxisRange != null) { setDomainAxisZoom(domainAxisRange.getSecond(), null); } // fetch range axis config ranges List<RangeAxisConfig> rangeAxisConfigs = plotConfig.getRangeAxisConfigs(); List<Pair<Integer, Range>> valueAxisRanges = e.getValueAxisRanges(); if (valueAxisRanges.size() > 0) { for (Pair<Integer, Range> newRangeAxisRangePair : valueAxisRanges) { RangeAxisConfig rangeAxisConfig = rangeAxisConfigs.get(newRangeAxisRangePair.getFirst()); int indexOf = plotConfig.getIndexOfRangeAxisConfigById(rangeAxisConfig.getId()); setRangeAxisZoom(indexOf, newRangeAxisRangePair.getSecond(), null); } } } if (e.getType() == SelectionType.RESTORE_AUTO_BOUNDS) { clearZooming(false); } if (e.getType() == SelectionType.COLOR_ZOOM) { Double minColorValue = e.getMinColorValue(); Double maxColorValue = e.getMaxColorValue(); if (e.getPlotInstance() != null) { DimensionConfigData dimensionConfigData = e.getPlotInstance().getPlotData() .getDimensionConfigData(plotConfig.getDefaultDimensionConfigs().get(PlotDimension.COLOR)); ContinuousColorProvider colProv = null; if (minColorValue != null && dimensionConfigData != null && dimensionConfigData.getColorProvider() instanceof ContinuousColorProvider) { colProv = (ContinuousColorProvider) dimensionConfigData.getColorProvider(); colProv.setMinValue(minColorValue); } if (maxColorValue != null && dimensionConfigData != null && dimensionConfigData.getColorProvider() instanceof ContinuousColorProvider) { colProv = (ContinuousColorProvider) dimensionConfigData.getColorProvider(); colProv.setMaxValue(maxColorValue); } if (colProv != null) { colProv.setUseGrayForOutliers(useGrayForOutliers); } } } else if (e.getType() == SelectionType.COLOR_SELECTION) { Double minColorValue = e.getMinColorValue(); Double maxColorValue = e.getMaxColorValue(); if (e.getPlotInstance() != null) { DimensionConfigData dimensionConfigData = e.getPlotInstance().getPlotData() .getDimensionConfigData(plotConfig.getDefaultDimensionConfigs().get(PlotDimension.COLOR)); ContinuousColorProvider colProv = null; if (minColorValue != null && dimensionConfigData != null && dimensionConfigData.getColorProvider() instanceof ContinuousColorProvider) { colProv = (ContinuousColorProvider) dimensionConfigData.getColorProvider(); colProv.setMinValue(minColorValue); } if (maxColorValue != null && dimensionConfigData != null && dimensionConfigData.getColorProvider() instanceof ContinuousColorProvider) { colProv = (ContinuousColorProvider) dimensionConfigData.getColorProvider(); colProv.setMaxValue(maxColorValue); } if (colProv != null) { colProv.setUseGrayForOutliers(useGrayForOutliers); } } } if (e.getType() == SelectionType.RESTORE_COLOR) { if (e.getPlotInstance() != null) { DimensionConfigData dimensionConfigData = e.getPlotInstance().getPlotData() .getDimensionConfigData(plotConfig.getDefaultDimensionConfigs().get(PlotDimension.COLOR)); if (dimensionConfigData != null && dimensionConfigData.getColorProvider() instanceof ContinuousColorProvider) { ContinuousColorProvider colProv = (ContinuousColorProvider) dimensionConfigData.getColorProvider(); colProv.revertMinAndMaxValuesBackToOriginalValues(); } } } informLinkAndBrushListeners(e); } /** * Sets the domain axis zoom. * * @param domainAxisRange * @param e * if {@code null}, will not inform listeners */ public void setDomainAxisZoom(Range domainAxisZoom, LinkAndBrushSelection e) { if (domainAxisZoom == null) { throw new IllegalArgumentException("domainAxisRange must not be null!"); } this.domainAxisZoom = domainAxisZoom; if (e != null) { informLinkAndBrushListeners(e); } } /** * Sets the range axis zoom of the range axis specified by the given index. * * @param indexOfRangeAxis * @param rangeAxisZoom * @param e * if {@code null}, will not inform listeners */ public void setRangeAxisZoom(int indexOfRangeAxis, Range rangeAxisZoom, LinkAndBrushSelection e) { if (indexOfRangeAxis < 0) { throw new IllegalArgumentException("indexOfRangeAxis must not be < 0"); } rangeAxisIndexToZoomMap.put(indexOfRangeAxis, rangeAxisZoom); if (e != null) { informLinkAndBrushListeners(e); } } protected LinkAndBrushMaster clone(PlotConfiguration plotConfig) { LinkAndBrushMaster clone = new LinkAndBrushMaster(plotConfig); clone.domainAxisZoom = this.domainAxisZoom; Map<Integer, Range> clonedRangeAxisIndexToZoomMap = new HashMap<Integer, Range>(); for (Integer key : rangeAxisIndexToZoomMap.keySet()) { Range value = rangeAxisIndexToZoomMap.get(key); clonedRangeAxisIndexToZoomMap.put(key, new Range(value.getLowerBound(), value.getUpperBound())); } clone.rangeAxisIndexToZoomMap = clonedRangeAxisIndexToZoomMap; clone.zoomedIn = this.zoomedIn; return clone; } /** * Adds the given {@link LinkAndBrushListener} to this {@link LinkAndBrushMaster}. * * @param l */ public void addLinkAndBrushListener(LinkAndBrushListener l) { listeners.add(new WeakReference<LinkAndBrushListener>(l)); } /** * Removes the given {@link LinkAndBrushListener} from this {@link LinkAndBrushMaster}. * * @param l */ public void removeLinkAndBrushListener(LinkAndBrushListener l) { Iterator<WeakReference<LinkAndBrushListener>> it = listeners.iterator(); while (it.hasNext()) { LinkAndBrushListener listener = it.next().get(); if (l != null) { if (listener != null && listener.equals(l)) { it.remove(); } } else { it.remove(); } } } /** * Informs all {@link LinkAndBrushListener}s of an update. * * @param e */ private void informLinkAndBrushListeners(LinkAndBrushSelection e) { Iterator<WeakReference<LinkAndBrushListener>> it = listeners.iterator(); while (it.hasNext()) { WeakReference<LinkAndBrushListener> wrl = it.next(); LinkAndBrushListener l = wrl.get(); if (l != null) { l.linkAndBrushUpdate(e); } else { it.remove(); } } } public boolean isUseGrayForOutliers() { return useGrayForOutliers; } public void setUseGrayForOutliers(boolean useGrayForOutliers) { this.useGrayForOutliers = useGrayForOutliers; } }