001/* 002 * $Id$ 003 * 004 * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 * 021 */ 022package org.jdesktop.swingx.plaf.basic.core; 023 024 025import java.io.*; 026import java.awt.datatransfer.*; 027import javax.swing.plaf.UIResource; 028 029/** 030 * A transferable implementation for the default data transfer of some Swing 031 * components. 032 * 033 * @author Timothy Prinzing 034 * @version 1.10 11/17/05 035 */ 036public class BasicTransferable implements Transferable, UIResource { 037 038 protected String plainData; 039 protected String htmlData; 040 041 private static DataFlavor[] htmlFlavors; 042 private static DataFlavor[] stringFlavors; 043 private static DataFlavor[] plainFlavors; 044 045 static { 046 try { 047 htmlFlavors = new DataFlavor[3]; 048 htmlFlavors[0] = new DataFlavor("text/html;class=java.lang.String"); 049 htmlFlavors[1] = new DataFlavor("text/html;class=java.io.Reader"); 050 htmlFlavors[2] = new DataFlavor("text/html;charset=unicode;class=java.io.InputStream"); 051 052 plainFlavors = new DataFlavor[3]; 053 plainFlavors[0] = new DataFlavor("text/plain;class=java.lang.String"); 054 plainFlavors[1] = new DataFlavor("text/plain;class=java.io.Reader"); 055 plainFlavors[2] = new DataFlavor("text/plain;charset=unicode;class=java.io.InputStream"); 056 057 stringFlavors = new DataFlavor[2]; 058 stringFlavors[0] = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType+";class=java.lang.String"); 059 stringFlavors[1] = DataFlavor.stringFlavor; 060 061 } catch (ClassNotFoundException cle) { 062 System.err.println("error initializing javax.swing.plaf.basic.BasicTranserable"); 063 } 064 } 065 066 public BasicTransferable(String plainData, String htmlData) { 067 this.plainData = plainData; 068 this.htmlData = htmlData; 069 } 070 071 072 /** 073 * Returns an array of DataFlavor objects indicating the flavors the data 074 * can be provided in. The array should be ordered according to preference 075 * for providing the data (from most richly descriptive to least descriptive). 076 * @return an array of data flavors in which this data can be transferred 077 */ 078 public DataFlavor[] getTransferDataFlavors() { 079 DataFlavor[] richerFlavors = getRicherFlavors(); 080 int nRicher = (richerFlavors != null) ? richerFlavors.length : 0; 081 int nHTML = (isHTMLSupported()) ? htmlFlavors.length : 0; 082 int nPlain = (isPlainSupported()) ? plainFlavors.length: 0; 083 int nString = (isPlainSupported()) ? stringFlavors.length : 0; 084 int nFlavors = nRicher + nHTML + nPlain + nString; 085 DataFlavor[] flavors = new DataFlavor[nFlavors]; 086 087 // fill in the array 088 int nDone = 0; 089 if (nRicher > 0) { 090 System.arraycopy(richerFlavors, 0, flavors, nDone, nRicher); 091 nDone += nRicher; 092 } 093 if (nHTML > 0) { 094 System.arraycopy(htmlFlavors, 0, flavors, nDone, nHTML); 095 nDone += nHTML; 096 } 097 if (nPlain > 0) { 098 System.arraycopy(plainFlavors, 0, flavors, nDone, nPlain); 099 nDone += nPlain; 100 } 101 if (nString > 0) { 102 System.arraycopy(stringFlavors, 0, flavors, nDone, nString); 103 nDone += nString; 104 } 105 return flavors; 106 } 107 108 /** 109 * Returns whether or not the specified data flavor is supported for 110 * this object. 111 * @param flavor the requested flavor for the data 112 * @return boolean indicating whether or not the data flavor is supported 113 */ 114 public boolean isDataFlavorSupported(DataFlavor flavor) { 115 DataFlavor[] flavors = getTransferDataFlavors(); 116 for (int i = 0; i < flavors.length; i++) { 117 if (flavors[i].equals(flavor)) { 118 return true; 119 } 120 } 121 return false; 122 } 123 124 /** 125 * Returns an object which represents the data to be transferred. The class 126 * of the object returned is defined by the representation class of the flavor. 127 * 128 * @param flavor the requested flavor for the data 129 * @see DataFlavor#getRepresentationClass 130 * @exception IOException if the data is no longer available 131 * in the requested flavor. 132 * @exception UnsupportedFlavorException if the requested data flavor is 133 * not supported. 134 */ 135 public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { 136 DataFlavor[] richerFlavors = getRicherFlavors(); 137 if (isRicherFlavor(flavor)) { 138 return getRicherData(flavor); 139 } else if (isHTMLFlavor(flavor)) { 140 String data = getHTMLData(); 141 data = (data == null) ? "" : data; 142 if (String.class.equals(flavor.getRepresentationClass())) { 143 return data; 144 } else if (Reader.class.equals(flavor.getRepresentationClass())) { 145 return new StringReader(data); 146 } else if (InputStream.class.equals(flavor.getRepresentationClass())) { 147 return new StringBufferInputStream(data); 148 } 149 // fall through to unsupported 150 } else if (isPlainFlavor(flavor)) { 151 String data = getPlainData(); 152 data = (data == null) ? "" : data; 153 if (String.class.equals(flavor.getRepresentationClass())) { 154 return data; 155 } else if (Reader.class.equals(flavor.getRepresentationClass())) { 156 return new StringReader(data); 157 } else if (InputStream.class.equals(flavor.getRepresentationClass())) { 158 return new StringBufferInputStream(data); 159 } 160 // fall through to unsupported 161 162 } else if (isStringFlavor(flavor)) { 163 String data = getPlainData(); 164 data = (data == null) ? "" : data; 165 return data; 166 } 167 throw new UnsupportedFlavorException(flavor); 168 } 169 170 // --- richer subclass flavors ---------------------------------------------- 171 172 protected boolean isRicherFlavor(DataFlavor flavor) { 173 DataFlavor[] richerFlavors = getRicherFlavors(); 174 int nFlavors = (richerFlavors != null) ? richerFlavors.length : 0; 175 for (int i = 0; i < nFlavors; i++) { 176 if (richerFlavors[i].equals(flavor)) { 177 return true; 178 } 179 } 180 return false; 181 } 182 183 /** 184 * Some subclasses will have flavors that are more descriptive than HTML 185 * or plain text. If this method returns a non-null value, it will be 186 * placed at the start of the array of supported flavors. 187 */ 188 protected DataFlavor[] getRicherFlavors() { 189 return null; 190 } 191 192 protected Object getRicherData(DataFlavor flavor) throws UnsupportedFlavorException { 193 return null; 194 } 195 196 // --- html flavors ---------------------------------------------------------- 197 198 /** 199 * Returns whether or not the specified data flavor is an HTML flavor that 200 * is supported. 201 * @param flavor the requested flavor for the data 202 * @return boolean indicating whether or not the data flavor is supported 203 */ 204 protected boolean isHTMLFlavor(DataFlavor flavor) { 205 DataFlavor[] flavors = htmlFlavors; 206 for (int i = 0; i < flavors.length; i++) { 207 if (flavors[i].equals(flavor)) { 208 return true; 209 } 210 } 211 return false; 212 } 213 214 /** 215 * Should the HTML flavors be offered? If so, the method 216 * getHTMLData should be implemented to provide something reasonable. 217 */ 218 protected boolean isHTMLSupported() { 219 return htmlData != null; 220 } 221 222 /** 223 * Fetch the data in a text/html format 224 */ 225 protected String getHTMLData() { 226 return htmlData; 227 } 228 229 // --- plain text flavors ---------------------------------------------------- 230 231 /** 232 * Returns whether or not the specified data flavor is an plain flavor that 233 * is supported. 234 * @param flavor the requested flavor for the data 235 * @return boolean indicating whether or not the data flavor is supported 236 */ 237 protected boolean isPlainFlavor(DataFlavor flavor) { 238 DataFlavor[] flavors = plainFlavors; 239 for (int i = 0; i < flavors.length; i++) { 240 if (flavors[i].equals(flavor)) { 241 return true; 242 } 243 } 244 return false; 245 } 246 247 /** 248 * Should the plain text flavors be offered? If so, the method 249 * getPlainData should be implemented to provide something reasonable. 250 */ 251 protected boolean isPlainSupported() { 252 return plainData != null; 253 } 254 255 /** 256 * Fetch the data in a text/plain format. 257 */ 258 protected String getPlainData() { 259 return plainData; 260 } 261 262 // --- string flavorss -------------------------------------------------------- 263 264 /** 265 * Returns whether or not the specified data flavor is a String flavor that 266 * is supported. 267 * @param flavor the requested flavor for the data 268 * @return boolean indicating whether or not the data flavor is supported 269 */ 270 protected boolean isStringFlavor(DataFlavor flavor) { 271 DataFlavor[] flavors = stringFlavors; 272 for (int i = 0; i < flavors.length; i++) { 273 if (flavors[i].equals(flavor)) { 274 return true; 275 } 276 } 277 return false; 278 } 279 280 281}