/* =========================================================== * JFreeChart : a free chart library for the Java(tm) platform * =========================================================== * * (C) Copyright 2000-2014, by Object Refinery Limited and Contributors. * * Project Info: http://www.jfree.org/jfreechart/index.html * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. * * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners.] * * --------------------------------- * PieDatasetSelectionExtension.java * --------------------------------- * (C) Copyright 2013, 2014, by Michael Zinsmaier and Contributors. * * Original Author: Michael Zinsmaier; * Contributor(s): David Gilbert (for Object Refinery Limited); * * Changes * ------- * 17-Sep-2013 : Version 1 (MZ); * */ package org.jfree.data.extension.impl; import java.util.HashMap; import org.jfree.data.UnknownKeyException; import org.jfree.data.extension.DatasetCursor; import org.jfree.data.extension.DatasetIterator; import org.jfree.data.extension.DatasetSelectionExtension; import org.jfree.data.extension.IterableSelection; import org.jfree.data.general.DatasetChangeEvent; import org.jfree.data.general.PieDataset; import org.jfree.data.general.SelectionChangeListener; /** * Extends a pie dataset with a selection state for each data item. * * @author zinsmaie */ public class PieDatasetSelectionExtension<KEY extends Comparable<KEY>> extends AbstractDatasetSelectionExtension<PieCursor<KEY>, PieDataset> implements IterableSelection<PieCursor<KEY>> { /** a generated serial id */ private static final long serialVersionUID = -1735271052194147081L; /** * private ref to the stored dataset to avoid casting same as * ({@link AbstractDatasetSelectionExtension#dataset}) */ private PieDataset dataset; /** Storage for the selection attributes of the data items. */ private HashMap<KEY, Boolean> selectionData; /** * Creates a separate selection extension for the specified dataset. * * @param dataset the underlying dataset ({@code null} not permitted). */ public PieDatasetSelectionExtension(PieDataset dataset) { super(dataset); this.dataset = dataset; initSelection(); } /** * Creates a separate selection extension for the specified dataset. And * adds an initial selection change listener, e.g. a plot that should be * redrawn on selection changes. * * @param dataset the underlying dataset ({@code null} not permitted). * @param initialListener the initial listener. */ public PieDatasetSelectionExtension(PieDataset dataset, SelectionChangeListener initialListener) { super(dataset); addChangeListener(initialListener); } /** * {@link DatasetSelectionExtension#isSelected(DatasetCursor)} */ @Override public boolean isSelected(PieCursor<KEY> cursor) { Boolean b = this.selectionData.get(cursor.key); if (b == null) { throw new UnknownKeyException("Unrecognised key " + cursor.key); } return Boolean.TRUE.equals(b); } /** * {@link DatasetSelectionExtension#setSelected(DatasetCursor, boolean)} */ @Override public void setSelected(PieCursor<KEY> cursor, boolean selected) { this.selectionData.put(cursor.key, Boolean.valueOf(selected)); notifyIfRequired(); } /** * {@link DatasetSelectionExtension#clearSelection()} */ @Override public void clearSelection() { initSelection(); } /** * A change of the underlying dataset clears the selection and reinitializes * it. * * @param event event information. */ @Override public void datasetChanged(DatasetChangeEvent event) { initSelection(); } /** * Inits the selection attribute storage and sets all data items to * unselected. */ private void initSelection() { this.selectionData = new HashMap<KEY, Boolean>(); // pie datasets are not yet typed therefore the cast is necessary // (and may fail) for (Comparable key : this.dataset.getKeys()) { this.selectionData.put((KEY) key, Boolean.FALSE); } notifyIfRequired(); } //ITERATOR IMPLEMENTATION /** * {@link IterableSelection#getIterator()} */ @Override public DatasetIterator<PieCursor<KEY>> getIterator() { return new PieDatasetSelectionIterator(); } /** * {@link IterableSelection#getSelectionIterator(boolean)} */ @Override public DatasetIterator<PieCursor<KEY>> getSelectionIterator( boolean selected) { return new PieDatasetSelectionIterator(selected); } /** * Allows to iterate over all data items or the selected / unselected data * items. Provides on each iteration step a DatasetCursor that defines * the position of the data item. * * @author zinsmaie */ private class PieDatasetSelectionIterator implements DatasetIterator<PieCursor<KEY>> { // could be improved wtr speed by storing selected elements directly for // faster access however storage efficiency would decrease /** a generated serial id */ private static final long serialVersionUID = -9037547822331524470L; /** current section initialized before the start of the dataset */ private int section = -1; /** * return all data item positions (null), only the selected (true) or * only the unselected (false) */ private Boolean filter = null; /** * creates an iterator over all data item positions */ public PieDatasetSelectionIterator() { } /** * Creates an iterator that iterates either over all selected or all * unselected data item positions. * * @param selected if true the iterator will iterate over the selected * data item positions */ public PieDatasetSelectionIterator(boolean selected) { filter = selected; } /** {@link Iterator#hasNext() */ @Override public boolean hasNext() { if (nextPosition() != -1) { return true; } return false; } /** * {@link Iterator#next()} */ @Override public PieCursor<KEY> next() { this.section = nextPosition(); //pie datasets are not yet typed therefore the cast is necessary //(and may fail) KEY key = (KEY)dataset.getKey(this.section); return new PieCursor<KEY>(key); } /** * iterator remove operation is not supported */ @Override public void remove() { throw new UnsupportedOperationException(); } /** * Calculates the next position based on the current position * and the filter status. * @return an array holding the next position section */ private int nextPosition() { int pSection = this.section; while ((pSection+1) < dataset.getItemCount()) { if (filter != null) { Comparable<?> key = dataset.getKey((pSection+1)); if (!(filter.equals(selectionData.get(key)))) { pSection++; continue; } } //success return (pSection+1); } return -1; } } }