/** * 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.gui; import com.rapidminer.gui.new_plotter.configuration.DimensionConfig; import com.rapidminer.gui.new_plotter.configuration.DimensionConfig.PlotDimension; import com.rapidminer.gui.new_plotter.configuration.PlotConfiguration; import com.rapidminer.gui.new_plotter.configuration.RangeAxisConfig; import com.rapidminer.gui.new_plotter.configuration.ValueSource; import com.rapidminer.gui.new_plotter.gui.treenodes.DimensionConfigTreeNode; import com.rapidminer.gui.new_plotter.gui.treenodes.PlotConfigurationTreeNode; import com.rapidminer.gui.new_plotter.gui.treenodes.RangeAxisConfigTreeNode; import com.rapidminer.gui.new_plotter.gui.treenodes.ValueSourceTreeNode; import com.rapidminer.gui.new_plotter.listener.PlotConfigurationListener; import com.rapidminer.gui.new_plotter.listener.events.DimensionConfigChangeEvent; import com.rapidminer.gui.new_plotter.listener.events.DimensionConfigChangeEvent.DimensionConfigChangeType; import com.rapidminer.gui.new_plotter.listener.events.PlotConfigurationChangeEvent; import com.rapidminer.gui.new_plotter.listener.events.PlotConfigurationChangeEvent.PlotConfigurationChangeType; import com.rapidminer.gui.new_plotter.listener.events.RangeAxisConfigChangeEvent; import com.rapidminer.gui.new_plotter.listener.events.RangeAxisConfigChangeEvent.RangeAxisConfigChangeType; import java.util.List; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; /** * @author Nils Woehler * */ public class PlotConfigurationTreeModel extends DefaultTreeModel implements PlotConfigurationListener { private static final long serialVersionUID = 1L; private final PlotConfigurationTree plotConfigTree; private PlotConfiguration plotConfig; public static int NUMBER_OF_PERMANENT_DIMENSIONS = 4; /** * @param root */ public PlotConfigurationTreeModel(DefaultMutableTreeNode root, PlotConfiguration plotConfig, PlotConfigurationTree plotConfigTree) { super(root); this.plotConfig = plotConfig; this.plotConfigTree = plotConfigTree; if (root != null) { fillNewPlotConfigNode(plotConfig); } if (plotConfig != null) { plotConfig.addPlotConfigurationListener(this); } } private void rangeAxisConfigAdded(int index, RangeAxisConfig rangeAxis) { RangeAxisConfigTreeNode newChild = new RangeAxisConfigTreeNode(rangeAxis); insertNodeInto(newChild, (MutableTreeNode) root, index + NUMBER_OF_PERMANENT_DIMENSIONS); List<ValueSource> rangeAxisValueSources = rangeAxis.getValueSources(); if (rangeAxis.getValueSources().size() > 0) { int idx = 0; // add new value source child nodes for (ValueSource source : rangeAxisValueSources) { valueSourceAdded(idx, source, rangeAxis); ++idx; } } else { // change selection path TreePath pathToNewChild = new TreePath(getPathToRoot(newChild)); makeVisibleAndSelect(pathToNewChild); } } private void rangeAxisConfigRemoved(int index, RangeAxisConfig rangeAxis) { removeNodeFromParent((MutableTreeNode) root.getChildAt(index + NUMBER_OF_PERMANENT_DIMENSIONS)); reload(); plotConfigTree.expandAll(); // Acquire new selection element int childCount = root.getChildCount(); Object newSelection = null; if (childCount > NUMBER_OF_PERMANENT_DIMENSIONS) { newSelection = root.getChildAt(childCount - 1); } else { newSelection = root; } // change selection path TreePath path = new TreePath(getPathToRoot((TreeNode) newSelection)); makeVisibleAndSelect(path); } private void dimensionConfigAdded(PlotDimension dimension, DimensionConfig dimensionConfig) { PlotConfigurationTreeNode root = (PlotConfigurationTreeNode) this.root; DefaultMutableTreeNode child = (DefaultMutableTreeNode) root.getChild(dimension); child.setUserObject(dimensionConfig); // change selection path TreePath path = new TreePath(getPathToRoot(child)); makeVisibleAndSelect(path); } private void dimensionConfigRemoved(PlotDimension dimension, DimensionConfig dimensionConfig) { PlotConfigurationTreeNode root = (PlotConfigurationTreeNode) this.root; DefaultMutableTreeNode child = (DefaultMutableTreeNode) root.getChild(dimension); child.setUserObject(null); } private void rangeAxisMoved(int index, RangeAxisConfig rangeAxisConfig) { PlotConfigurationTreeNode rootNode = (PlotConfigurationTreeNode) root; RangeAxisConfigTreeNode childNode = (RangeAxisConfigTreeNode) rootNode.getChild(rangeAxisConfig); // remove from old parent removeNodeFromParent(childNode); // add at new index int newIndex = index + NUMBER_OF_PERMANENT_DIMENSIONS; insertNodeInto(childNode, rootNode, newIndex); // change selection path TreePath path = new TreePath(getPathToRoot(childNode)); makeVisibleAndSelect(path); } private void valueSourcesCleared(RangeAxisConfig source) { RangeAxisConfigTreeNode rangeAxisNode = getRangeAxisTreeNode(source); if (rangeAxisNode != null) { int childCount = rangeAxisNode.getChildCount(); for (int i = 0; i < childCount; ++i) { removeNodeFromParent((MutableTreeNode) rangeAxisNode.getChildAt(i)); } // change selection path TreePath path = new TreePath(getPathToRoot(rangeAxisNode)); makeVisibleAndSelect(path); } else { throw new RuntimeException("RangeAxisConfig source is not present in TreeModel. This should not happen."); } } private void valueSourceAdded(int index, ValueSource valueSource, RangeAxisConfig source) { RangeAxisConfigTreeNode rangeAxisNode = getRangeAxisTreeNode(source); if (rangeAxisNode != null) { TreeNode child = rangeAxisNode.getChild(valueSource); if (child != null) { return; // already added.. } // create new value source tree node ValueSourceTreeNode newChild = new ValueSourceTreeNode(valueSource); // add new tree node insertNodeInto(newChild, rangeAxisNode, index); // change selection path TreePath path = new TreePath(getPathToRoot(newChild)); makeVisibleAndSelect(path); } else { throw new RuntimeException("RangeAxisConfig source is not present in TreeModel. This should not happen."); } } private void valueSourceRemoved(ValueSource valueSource, RangeAxisConfig source) { RangeAxisConfigTreeNode rangeAxisNode = getRangeAxisTreeNode(source); if (rangeAxisNode != null) { TreeNode valueSourceNode = rangeAxisNode.getChild(valueSource); if (valueSourceNode == null) { throw new RuntimeException("ValueSource is not present in TreeModel. This should not happen."); } int oldIndex = rangeAxisNode.getIndex(valueSourceNode); removeNodeFromParent((MutableTreeNode) valueSourceNode); // Acquire new selection element int childCount = rangeAxisNode.getChildCount(); Object newSelection = null; TreePath path = new TreePath(getPathToRoot(rangeAxisNode)); if (oldIndex < childCount) { newSelection = rangeAxisNode.getChildAt(oldIndex); path = path.pathByAddingChild(newSelection); } else if (childCount > 0) { newSelection = rangeAxisNode.getChildAt(childCount - 1); path = path.pathByAddingChild(newSelection); } // change selection path makeVisibleAndSelect(path); } else { throw new RuntimeException("RangeAxisConfig source is not present in TreeModel. This should not happen."); } } private void makeVisibleAndSelect(TreePath path) { reload(); plotConfigTree.expandAll(); plotConfigTree.makeVisible(path); plotConfigTree.scrollPathToVisible(path); plotConfigTree.setSelectionPath(path); } private void valueSourceMoved(int index, ValueSource valueSource, RangeAxisConfig source) { PlotConfigurationTreeNode rootNode = (PlotConfigurationTreeNode) root; // get range axis node RangeAxisConfigTreeNode sourceNode = (RangeAxisConfigTreeNode) rootNode.getChild(source); // get value source node ValueSourceTreeNode childNode = (ValueSourceTreeNode) sourceNode.getChild(valueSource); // remove value source node from old parent removeNodeFromParent(childNode); // add value source at new position insertNodeInto(childNode, sourceNode, index); // change selection path TreePath path = new TreePath(getPathToRoot(childNode)); makeVisibleAndSelect(path); } private void rangeAxisConfigChanged(RangeAxisConfigChangeEvent change) { PlotConfigurationTreeNode rootNode = (PlotConfigurationTreeNode) root; RangeAxisConfigTreeNode rangeAxisNode = (RangeAxisConfigTreeNode) rootNode.getChild(change.getSource()); RangeAxisConfigChangeType type = change.getType(); switch (type) { case CLEARED: valueSourcesCleared(change.getSource()); break; case VALUE_SOURCE_ADDED: valueSourceAdded(change.getIndex(), change.getValueSource(), change.getSource()); break; case VALUE_SOURCE_CHANGED: ValueSource source = change.getValueSourceChange().getSource(); ValueSourceTreeNode valueSourceNode = (ValueSourceTreeNode) rangeAxisNode.getChild(source); nodeChanged(valueSourceNode); break; case VALUE_SOURCE_MOVED: valueSourceMoved(change.getIndex(), change.getValueSource(), change.getSource()); break; case VALUE_SOURCE_REMOVED: valueSourceRemoved(change.getValueSource(), change.getSource()); break; default: nodeChanged(rangeAxisNode); } } public void exchangePlotConfiguration(PlotConfiguration newPlotConfig) { if (plotConfig != null) { plotConfig.removePlotConfigurationListener(this); } plotConfig = newPlotConfig; setRoot(new PlotConfigurationTreeNode(newPlotConfig)); fillNewPlotConfigNode(newPlotConfig); newPlotConfig.addPlotConfigurationListener(this); } @Override public boolean plotConfigurationChanged(PlotConfigurationChangeEvent change) { PlotConfigurationChangeType type = change.getType(); RangeAxisConfigChangeEvent rangeAxisConfigChange = change.getRangeAxisConfigChange(); switch (type) { case DIMENSION_CONFIG_ADDED: dimensionConfigAdded(change.getDimension(), change.getDimensionConfig()); break; case DIMENSION_CONFIG_CHANGED: dimensionConfigChanged(change); break; case DIMENSION_CONFIG_REMOVED: dimensionConfigRemoved(change.getDimension(), change.getDimensionConfig()); break; case RANGE_AXIS_CONFIG_ADDED: rangeAxisConfigAdded(change.getIndex(), change.getRangeAxisConfig()); break; case RANGE_AXIS_CONFIG_CHANGED: rangeAxisConfigChanged(rangeAxisConfigChange); break; case RANGE_AXIS_CONFIG_MOVED: rangeAxisMoved(change.getIndex(), change.getRangeAxisConfig()); break; case RANGE_AXIS_CONFIG_REMOVED: rangeAxisConfigRemoved(change.getIndex(), change.getRangeAxisConfig()); break; case META_CHANGE: for (PlotConfigurationChangeEvent events : change.getPlotConfigChangeEvents()) { plotConfigurationChanged(events); } default: } return true; } private void dimensionConfigChanged(PlotConfigurationChangeEvent change) { PlotConfigurationTreeNode rootNode = (PlotConfigurationTreeNode) root; DimensionConfigChangeEvent dimensionChange = change.getDimensionChange(); DimensionConfigTreeNode dimensionConfigNode = (DimensionConfigTreeNode) rootNode.getChild(dimensionChange .getDimension()); nodeChanged(dimensionConfigNode); if (dimensionChange.getType() == DimensionConfigChangeType.COLUMN) { // change selection path TreePath path = new TreePath(getPathToRoot(dimensionConfigNode)); makeVisibleAndSelect(path); } } private RangeAxisConfigTreeNode getRangeAxisTreeNode(RangeAxisConfig rangeAxis) { PlotConfigurationTreeNode root = (PlotConfigurationTreeNode) this.root; return (RangeAxisConfigTreeNode) root.getChild(rangeAxis); } private void fillNewPlotConfigNode(PlotConfiguration plotConfig) { if (plotConfig.getRangeAxisCount() == 0) { plotConfig.addRangeAxisConfig(new RangeAxisConfig(null, plotConfig)); } // CAUTION: If you add more dimension configs you have to adapt // NUMBER_OF_PERMANENT_DIMENSIONS!!! // add domain dimension config insertNodeInto(new DimensionConfigTreeNode(PlotDimension.DOMAIN, plotConfig.getDomainConfigManager()), (MutableTreeNode) root, root.getChildCount()); // add color dimension config insertNodeInto(new DimensionConfigTreeNode(PlotDimension.COLOR, plotConfig.getDimensionConfig(PlotDimension.COLOR)), (MutableTreeNode) root, root.getChildCount()); // add shape dimension config insertNodeInto(new DimensionConfigTreeNode(PlotDimension.SHAPE, plotConfig.getDimensionConfig(PlotDimension.SHAPE)), (MutableTreeNode) root, root.getChildCount()); // add size dimension config insertNodeInto(new DimensionConfigTreeNode(PlotDimension.SIZE, plotConfig.getDimensionConfig(PlotDimension.SIZE)), (MutableTreeNode) root, root.getChildCount()); // CAUTION: If you add more dimension configs you have to adapt // NUMBER_OF_PERMANENT_DIMENSIONS!!! // at the end add existing range axis tree nodes List<RangeAxisConfig> rangeAxisConfigs = plotConfig.getRangeAxisConfigs(); int idx = 0; for (RangeAxisConfig rangeAxis : rangeAxisConfigs) { rangeAxisConfigAdded(idx, rangeAxis); ++idx; } } }