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    }