001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2020, 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 * ChartTransferable.java 029 * ---------------------- 030 * (C) Copyright 2009-2020, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 */ 036 037package org.jfree.chart; 038 039import java.awt.Graphics2D; 040import java.awt.datatransfer.DataFlavor; 041import java.awt.datatransfer.Transferable; 042import java.awt.datatransfer.UnsupportedFlavorException; 043import java.awt.geom.AffineTransform; 044import java.awt.geom.Rectangle2D; 045import java.awt.image.BufferedImage; 046import java.io.IOException; 047 048/** 049 * A class used to represent a chart on the clipboard. 050 * 051 * @since 1.0.13 052 */ 053public class ChartTransferable implements Transferable { 054 055 /** The data flavor. */ 056 final DataFlavor imageFlavor = new DataFlavor( 057 "image/x-java-image; class=java.awt.Image", "Image"); 058 059 /** The chart. */ 060 private JFreeChart chart; 061 062 /** The width of the chart on the clipboard. */ 063 private int width; 064 065 /** The height of the chart on the clipboard. */ 066 private int height; 067 068 /** 069 * The smallest width at which the chart will be drawn (if necessary, the 070 * chart will then be scaled down to fit the requested width). 071 * 072 * @since 1.0.14 073 */ 074 private int minDrawWidth; 075 076 /** 077 * The smallest height at which the chart will be drawn (if necessary, the 078 * chart will then be scaled down to fit the requested height). 079 * 080 * @since 1.0.14 081 */ 082 private int minDrawHeight; 083 084 /** 085 * The largest width at which the chart will be drawn (if necessary, the 086 * chart will then be scaled up to fit the requested width). 087 * 088 * @since 1.0.14 089 */ 090 private int maxDrawWidth; 091 092 /** 093 * The largest height at which the chart will be drawn (if necessary, the 094 * chart will then be scaled up to fit the requested height). 095 * 096 * @since 1.0.14 097 */ 098 private int maxDrawHeight; 099 100 /** 101 * Creates a new chart selection. 102 * 103 * @param chart the chart. 104 * @param width the chart width. 105 * @param height the chart height. 106 */ 107 public ChartTransferable(JFreeChart chart, int width, int height) { 108 this(chart, width, height, true); 109 } 110 111 /** 112 * Creates a new chart selection. 113 * 114 * @param chart the chart. 115 * @param width the chart width. 116 * @param height the chart height. 117 * @param cloneData clone the dataset(s)? 118 */ 119 public ChartTransferable(JFreeChart chart, int width, int height, 120 boolean cloneData) { 121 this(chart, width, height, 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE, 122 true); 123 } 124 125 /** 126 * Creates a new chart selection. The minimum and maximum drawing 127 * dimensions are used to match the scaling behaviour in the 128 * {@link ChartPanel} class. 129 * 130 * @param chart the chart. 131 * @param width the chart width. 132 * @param height the chart height. 133 * @param minDrawW the minimum drawing width. 134 * @param minDrawH the minimum drawing height. 135 * @param maxDrawW the maximum drawing width. 136 * @param maxDrawH the maximum drawing height. 137 * @param cloneData clone the dataset(s)? 138 * 139 * @since 1.0.14 140 */ 141 public ChartTransferable(JFreeChart chart, int width, int height, 142 int minDrawW, int minDrawH, int maxDrawW, int maxDrawH, 143 boolean cloneData) { 144 145 // we clone the chart because presumably there can be some delay 146 // between putting this instance on the system clipboard and 147 // actually having the getTransferData() method called... 148 try { 149 this.chart = (JFreeChart) chart.clone(); 150 } 151 catch (CloneNotSupportedException e) { 152 this.chart = chart; 153 } 154 // FIXME: we've cloned the chart, but the dataset(s) aren't cloned 155 // and we should do that 156 this.width = width; 157 this.height = height; 158 this.minDrawWidth = minDrawW; 159 this.minDrawHeight = minDrawH; 160 this.maxDrawWidth = maxDrawW; 161 this.maxDrawHeight = maxDrawH; 162 } 163 164 /** 165 * Returns the data flavors supported. 166 * 167 * @return The data flavors supported. 168 */ 169 @Override 170 public DataFlavor[] getTransferDataFlavors() { 171 return new DataFlavor[] {this.imageFlavor}; 172 } 173 174 /** 175 * Returns {@code true} if the specified flavor is supported. 176 * 177 * @param flavor the flavor. 178 * 179 * @return A boolean. 180 */ 181 @Override 182 public boolean isDataFlavorSupported(DataFlavor flavor) { 183 return this.imageFlavor.equals(flavor); 184 } 185 186 /** 187 * Returns the content for the requested flavor, if it is supported. 188 * 189 * @param flavor the requested flavor. 190 * 191 * @return The content. 192 * 193 * @throws java.awt.datatransfer.UnsupportedFlavorException if the flavor 194 * is not supported. 195 * @throws java.io.IOException if there is an IO problem. 196 */ 197 @Override 198 public Object getTransferData(DataFlavor flavor) 199 throws UnsupportedFlavorException, IOException { 200 if (this.imageFlavor.equals(flavor)) { 201 return createBufferedImage(this.chart, this.width, this.height, 202 this.minDrawWidth, this.minDrawHeight, this.maxDrawWidth, 203 this.maxDrawHeight); 204 } else { 205 throw new UnsupportedFlavorException(flavor); 206 } 207 } 208 209 /** 210 * A utility method that creates an image of a chart, with scaling. 211 * 212 * @param chart the chart. 213 * @param w the image width. 214 * @param h the image height. 215 * @param minDrawW the minimum width for chart drawing. 216 * @param minDrawH the minimum height for chart drawing. 217 * @param maxDrawW the maximum width for chart drawing. 218 * @param maxDrawH the maximum height for chart drawing. 219 * 220 * @return A chart image. 221 * 222 * @since 1.0.14 223 */ 224 private BufferedImage createBufferedImage(JFreeChart chart, int w, int h, 225 int minDrawW, int minDrawH, int maxDrawW, int maxDrawH) { 226 227 BufferedImage image = new BufferedImage(w, h, 228 BufferedImage.TYPE_INT_RGB); // bug #182 229 Graphics2D g2 = image.createGraphics(); 230 231 // work out if scaling is required... 232 boolean scale = false; 233 double drawWidth = w; 234 double drawHeight = h; 235 double scaleX = 1.0; 236 double scaleY = 1.0; 237 if (drawWidth < minDrawW) { 238 scaleX = drawWidth / minDrawW; 239 drawWidth = minDrawW; 240 scale = true; 241 } else if (drawWidth > maxDrawW) { 242 scaleX = drawWidth / maxDrawW; 243 drawWidth = maxDrawW; 244 scale = true; 245 } 246 if (drawHeight < minDrawH) { 247 scaleY = drawHeight / minDrawH; 248 drawHeight = minDrawH; 249 scale = true; 250 } else if (drawHeight > maxDrawH) { 251 scaleY = drawHeight / maxDrawH; 252 drawHeight = maxDrawH; 253 scale = true; 254 } 255 256 Rectangle2D chartArea = new Rectangle2D.Double(0.0, 0.0, drawWidth, 257 drawHeight); 258 if (scale) { 259 AffineTransform st = AffineTransform.getScaleInstance(scaleX, 260 scaleY); 261 g2.transform(st); 262 } 263 chart.draw(g2, chartArea, null, null); 264 g2.dispose(); 265 return image; 266 267 } 268 269}