    001/* ===========================================================
    002 * JFreeChart : a free chart library for the Java(tm) platform
    003 * ===========================================================
    004 *
    005 * (C) Copyright 2000-2011, by Object Refinery Limited and Contributors.
    006 *
    007 * Project Info:  http://www.jfree.org/jfreechart/index.html
    008 *
    009 * This library is free software; you can redistribute it and/or modify it
    010 * under the terms of the GNU Lesser General Public License as published by
    011 * the Free Software Foundation; either version 2.1 of the License, or
    012 * (at your option) any later version.
    013 *
    014 * This library is distributed in the hope that it will be useful, but
    015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    017 * License for more details.
    018 *
    019 * You should have received a copy of the GNU Lesser General Public
    020 * License along with this library; if not, write to the Free Software
    021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
    022 * USA.
    023 *
    024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    025 * Other names may be trademarks of their respective owners.]
    026 *
    027 * -------------------
    028 * ChartSelection.java
    029 * -------------------
    030 * (C) Copyright 2009, by Object Refinery Limited.
    031 *
    032 * Original Author:  David Gilbert (for Object Refinery Limited);
    033 * Contributor(s):   -;
    034 *
    035 * Changes
    036 * -------
    037 * 08-Apr-2009 : Version 1, with inspiration from patch 1460845 (DG);
    038 * 05-May-2009 : Match the scaling options provided by the ChartPanel
    039 *               class (DG);
    040 *
    041 */
    042
    043package org.jfree.chart;
    044
    045import java.awt.Graphics2D;
    046import java.awt.datatransfer.DataFlavor;
    047import java.awt.datatransfer.Transferable;
    048import java.awt.datatransfer.UnsupportedFlavorException;
    049import java.awt.geom.AffineTransform;
    050import java.awt.geom.Rectangle2D;
    051import java.awt.image.BufferedImage;
    052import java.io.IOException;
    053
    054/**
    055 * A class used to represent a chart on the clipboard.
    056 *
    057 * @since 1.0.13
    058 */
    059public class ChartTransferable implements Transferable {
    060
    061    /** The data flavor. */
    062    final DataFlavor imageFlavor = new DataFlavor(
    063            "image/x-java-image; class=java.awt.Image", "Image");
    064
    065    /** The chart. */
    066    private JFreeChart chart;
    067
    068    /** The width of the chart on the clipboard. */
    069    private int width;
    070
    071    /** The height of the chart on the clipboard. */
    072    private int height;
    073
    074    /**
    075     * The smallest width at which the chart will be drawn (if necessary, the
    076     * chart will then be scaled down to fit the requested width).
    077     *
    078     * @since 1.0.14
    079     */
    080    private int minDrawWidth;
    081
    082    /**
    083     * The smallest height at which the chart will be drawn (if necessary, the
    084     * chart will then be scaled down to fit the requested height).
    085     *
    086     * @since 1.0.14
    087     */
    088    private int minDrawHeight;
    089
    090    /**
    091     * The largest width at which the chart will be drawn (if necessary, the
    092     * chart will then be scaled up to fit the requested width).
    093     *
    094     * @since 1.0.14
    095     */
    096    private int maxDrawWidth;
    097
    098    /**
    099     * The largest height at which the chart will be drawn (if necessary, the
    100     * chart will then be scaled up to fit the requested height).
    101     *
    102     * @since 1.0.14
    103     */
    104    private int maxDrawHeight;
    105
    106    /**
    107     * Creates a new chart selection.
    108     *
    109     * @param chart  the chart.
    110     * @param width  the chart width.
    111     * @param height  the chart height.
    112     */
    113    public ChartTransferable(JFreeChart chart, int width, int height) {
    114        this(chart, width, height, true);
    115    }
    116
    117    /**
    118     * Creates a new chart selection.
    119     *
    120     * @param chart  the chart.
    121     * @param width  the chart width.
    122     * @param height  the chart height.
    123     * @param cloneData  clone the dataset(s)?
    124     */
    125    public ChartTransferable(JFreeChart chart, int width, int height,
    126            boolean cloneData) {
    127        this(chart, width, height, 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE,
    128                true);
    129    }
    130
    131    /**
    132     * Creates a new chart selection.  The minimum and maximum drawing
    133     * dimensions are used to match the scaling behaviour in the
    134     * {@link ChartPanel} class.
    135     *
    136     * @param chart  the chart.
    137     * @param width  the chart width.
    138     * @param height  the chart height.
    139     * @param minDrawW  the minimum drawing width.
    140     * @param minDrawH  the minimum drawing height.
    141     * @param maxDrawW  the maximum drawing width.
    142     * @param maxDrawH  the maximum drawing height.
    143     * @param cloneData  clone the dataset(s)?
    144     *
    145     * @since 1.0.14
    146     */
    147    public ChartTransferable(JFreeChart chart, int width, int height,
    148            int minDrawW, int minDrawH, int maxDrawW, int maxDrawH,
    149            boolean cloneData) {
    150
    151        // we clone the chart because presumably there can be some delay
    152        // between putting this instance on the system clipboard and
    153        // actually having the getTransferData() method called...
    154        try {
    155            this.chart = (JFreeChart) chart.clone();
    156        }
    157        catch (CloneNotSupportedException e) {
    158            this.chart = chart;
    159        }
    160        // FIXME: we've cloned the chart, but the dataset(s) aren't cloned
    161        // and we should do that
    162        this.width = width;
    163        this.height = height;
    164        this.minDrawWidth = minDrawW;
    165        this.minDrawHeight = minDrawH;
    166        this.maxDrawWidth = maxDrawW;
    167        this.maxDrawHeight = maxDrawH;
    168    }
    169
    170    /**
    171     * Returns the data flavors supported.
    172     *
    173     * @return The data flavors supported.
    174     */
    175    public DataFlavor[] getTransferDataFlavors() {
    176        return new DataFlavor[] {this.imageFlavor};
    177    }
    178
    179    /**
    180     * Returns <code>true</code> if the specified flavor is supported.
    181     *
    182     * @param flavor  the flavor.
    183     *
    184     * @return A boolean.
    185     */
    186    public boolean isDataFlavorSupported(DataFlavor flavor) {
    187        return this.imageFlavor.equals(flavor);
    188    }
    189
    190    /**
    191     * Returns the content for the requested flavor, if it is supported.
    192     *
    193     * @param flavor  the requested flavor.
    194     *
    195     * @return The content.
    196     *
    197     * @throws java.awt.datatransfer.UnsupportedFlavorException
    198     * @throws java.io.IOException
    199     */
    200    public Object getTransferData(DataFlavor flavor)
    201            throws UnsupportedFlavorException, IOException {
    202
    203        if (this.imageFlavor.equals(flavor)) {
    204            return createBufferedImage(this.chart, this.width, this.height,
    205                    this.minDrawWidth, this.minDrawHeight, this.maxDrawWidth,
    206                    this.maxDrawHeight);
    207        }
    208        else {
    209            throw new UnsupportedFlavorException(flavor);
    210        }
    211    }
    212
    213    /**
    214     * A utility method that creates an image of a chart, with scaling.
    215     *
    216     * @param chart  the chart.
    217     * @param w  the image width.
    218     * @param h  the image height.
    219     * @param minDrawW  the minimum width for chart drawing.
    220     * @param minDrawH  the minimum height for chart drawing.
    221     * @param maxDrawW  the maximum width for chart drawing.
    222     * @param maxDrawH  the maximum height for chart drawing.
    223     *
    224     * @return  A chart image.
    225     *
    226     * @since 1.0.14
    227     */
    228    private BufferedImage createBufferedImage(JFreeChart chart, int w, int h,
    229            int minDrawW, int minDrawH, int maxDrawW, int maxDrawH) {
    230
    231        BufferedImage image = new BufferedImage(w, h,
    232                BufferedImage.TYPE_INT_ARGB);
    233        Graphics2D g2 = image.createGraphics();
    234
    235        // work out if scaling is required...
    236        boolean scale = false;
    237        double drawWidth = w;
    238        double drawHeight = h;
    239        double scaleX = 1.0;
    240        double scaleY = 1.0;
    241        if (drawWidth < minDrawW) {
    242            scaleX = drawWidth / minDrawW;
    243            drawWidth = minDrawW;
    244            scale = true;
    245        }
    246        else if (drawWidth > maxDrawW) {
    247            scaleX = drawWidth / maxDrawW;
    248            drawWidth = maxDrawW;
    249            scale = true;
    250        }
    251        if (drawHeight < minDrawH) {
    252            scaleY = drawHeight / minDrawH;
    253            drawHeight = minDrawH;
    254            scale = true;
    255        }
    256        else if (drawHeight > maxDrawH) {
    257            scaleY = drawHeight / maxDrawH;
    258            drawHeight = maxDrawH;
    259            scale = true;
    260        }
    261
    262        Rectangle2D chartArea = new Rectangle2D.Double(0.0, 0.0, drawWidth,
    263                drawHeight);
    264        if (scale) {
    265            AffineTransform st = AffineTransform.getScaleInstance(scaleX,
    266                    scaleY);
    267            g2.transform(st);
    268        }
    269        chart.draw(g2, chartArea, null, null);
    270        g2.dispose();
    271        return image;
    272
    273    }
    274
    275}