    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
    043    package org.jfree.chart;
    044
    045    import java.awt.Graphics2D;
    046    import java.awt.datatransfer.DataFlavor;
    047    import java.awt.datatransfer.Transferable;
    048    import java.awt.datatransfer.UnsupportedFlavorException;
    049    import java.awt.geom.AffineTransform;
    050    import java.awt.geom.Rectangle2D;
    051    import java.awt.image.BufferedImage;
    052    import java.io.IOException;
    053
    054    /**
    055     * A class used to represent a chart on the clipboard.
    056     *
    057     * @since 1.0.13
    058     */
    059    public 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    }