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}