alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.util.datatransfer;

import java.awt.datatransfer.*;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedHashMap;

import javax.swing.event.EventListenerList;

import org.openide.util.NbBundle;

/** Provides additional operations on
* a transferable.
*
* @author Jaroslav Tulach
*/
public class ExTransferable extends Object implements Transferable {
    /** An implementation of Transferable that contains no data. */
    public static final Transferable EMPTY = new Empty ();

    /** Flavor for transfer of multiple objects.
    */
    public static final DataFlavor multiFlavor=
        new DataFlavor (
            "application/x-java-openide-multinode;class=org.openide.util.datatransfer.MultiTransferObject", // NOI18N
            NbBundle.getBundle (ExTransferable.class).
            getString ("transferFlavorsMultiFlavorName")
        );

    /** hash map that assigns objects to dataflavors (DataFlavor, Single) */
    private LinkedHashMap map;

    /** listeners */
    private EventListenerList listeners;

    /** Creates new support.
    * @param t transferable to to copy values from
    * @param o clipobard owner (or null)
    */
    private ExTransferable (final Transferable t) {
        map = new LinkedHashMap ();

        final DataFlavor[] df = t.getTransferDataFlavors ();
        if (df != null) {
            for (int i = 0; i < df.length; i++) {
                try {
                    final int fi = i;
                    map.put (df[i], new Single (df[i]) {
                                 public Object getData () throws IOException, UnsupportedFlavorException {
                                     return t.getTransferData (df[fi]);
                                 }
                             });
                } catch (Exception ex) {
                    // ignore if the data cannot be retrived
                }
            }
        }
    }

    /** Add a new flavor with its data.
    * @param single the single transferable to use
    */
    public void put (Single single) {
        map.put (single.flavor, single);
    }

    /** Remove a flavor from the supported set.
     * @param flavor the flavor to remove
    */
    public void remove (DataFlavor flavor) {
        map.remove (flavor);
    }

    /* Get supported flavors.
     * @return the flavors
    */
    public DataFlavor[] getTransferDataFlavors () {
        return (DataFlavor[])map.keySet ().toArray (new DataFlavor[0]);
    }

    /* Is this flavor supported?
    * @param flavor flavor to test
    * @return true if this flavor is supported
    */
    public boolean isDataFlavorSupported (DataFlavor flavor) {
        return map.containsKey (flavor);
    }

    /* Get the transferable data for this flavor.
     * @param flavor the flavor
     * @return the data
     * @throws IOException currently not thrown
     * @throws UnsupportedFlavorException if that flavor is not supported
    */
    public Object getTransferData (DataFlavor flavor)
    throws UnsupportedFlavorException, IOException {
        Single o = (Single) map.get (flavor);
        if (o == null)
            throw new UnsupportedFlavorException (flavor);
        return o.getTransferData(flavor);
    }

    /** Method to create a new extended transferable from a plain transferable.
    * If the given transferable is already ExTransferable, then it
    * is returned as is. 
    * Otherwise the data is copied.
    *
    * @param t transferable to create support for
    * @return extended transferable
    */
    public static ExTransferable create (Transferable t) {
        // [PENDING] check should probably be: if (t.getClass() == ExTransferable.class)
        // (in case for some weird reason someone subclasses ExTransferable)
        if (t instanceof ExTransferable) return (ExTransferable)t;
        return new ExTransferable (t);
    }

    /** Adds a listener to watch the life-cycle of this object.
    *
    * @param l the listener
    */
    public synchronized final void addTransferListener (TransferListener l) {
        if (listeners == null) {
            listeners = new EventListenerList ();
        }
        listeners.add (TransferListener.class, l);
    }

    /** Removes a listener.
    */
    public synchronized final void removeTransferListener (TransferListener l) {
        if (listeners != null) {
            listeners.remove (TransferListener.class, l);
        }
    }

    /** Fires notification to all listeners about
    * accepting the drag.
    * @param action one of java.awt.dnd.DnDConstants.ACTION_*
    */
    final void fireAccepted (int action) {
        if (listeners == null) {
            return;
        }
        Object[] arr = listeners.getListenerList ();
        for (int i = arr.length - 1; i >= 0; i -= 2) {
            ((TransferListener)arr[i]).accepted (action);
        }
    }

    /** Fires notification to all listeners about
    * accepting the drag.
    */
    final void fireRejected () {
        if (listeners == null) {
            return;
        }
        Object[] arr = listeners.getListenerList ();
        for (int i = arr.length - 1; i >= 0; i -= 2) {
            ((TransferListener)arr[i]).rejected ();
        }
    }

    /** Fires notification to all listeners about
    * accepting the drag.
    */
    final void fireOwnershipLost () {
        if (listeners == null) {
            return;
        }
        Object[] arr = listeners.getListenerList ();
        for (int i = arr.length - 1; i >= 0; i -= 2) {
            ((TransferListener)arr[i]).ownershipLost ();
        }
    }

    /** Support for transferable owner with only one data flavor.
    * Subclasses need only implement {@link #getData}.
    */
    public static abstract class Single extends Object implements Transferable {
        /** the supported data flavor */
        private DataFlavor flavor;

        /** Constructor.
        * @param flavor flavor of the data
        */
        public Single (DataFlavor flavor) {
            this.flavor = flavor;
        }

        /* Flavors that are supported.
        * @return array with contextFlavor
        * @see TransferFlavors.contextFlavor
        */
        public DataFlavor[] getTransferDataFlavors () {
            return new DataFlavor[] { flavor };
        }

        /* Is the flavor supported?
        * @param flavor flavor to test
        * @return true if this flavor is supported
        */
        public boolean isDataFlavorSupported (DataFlavor flavor) {
            return this.flavor.equals (flavor);
        }

        /* Creates transferable data for this flavor.
        */
        public Object getTransferData (DataFlavor flavor)
        throws UnsupportedFlavorException, IOException {
            if (!this.flavor.equals (flavor)) throw new UnsupportedFlavorException (flavor);
            return getData ();
        }

        /** Abstract method to override to provide the right data for this
        * transferable.
        *
        * @return the data
        * @throws IOException when an I/O error occurs
        * @throws UnsupportedFlavorException if the flavor is not supported
        */
        protected abstract Object getData () throws IOException, UnsupportedFlavorException;
    }


    /** Transferable object for multiple transfer.
     * It allows several types of data
    * to be combined into one clipboard element.
    *
    * @author Jaroslav Tulach
    */
    public static class Multi extends Object implements Transferable {
        /** object that is about to be return as result of transfer */
        private MultiTransferObject transferObject;

        /** supported flavors list */
        private static final DataFlavor[] flavorList = { multiFlavor };

        /** Constructor taking a list of Transferable objects.
         *
         * @param trans array of transferable objects
         */
        public Multi (Transferable[] trans) {
            transferObject = new TransferObjectImpl (trans);
        }

        /** Get supported flavors.
         * @return only one flavor, {@link #multiFlavor}
        */
        public DataFlavor[] getTransferDataFlavors() {
            return flavorList;
        }

        /** Is this flavor supported?
         * @param flavor the flavor
        * @return true only if the flavor is {@link #multiFlavor}
        */
        public boolean isDataFlavorSupported(DataFlavor flavor) {
            return flavor.equals (multiFlavor);
        }

        /** Get transfer data.
         * @param flavor the flavor ({@link #multiFlavor})
        * @return {@link MultiTransferObject} that represents data in this object
        * @exception UnsupportedFlavorException when the flavor is not supported
        * @exception IOException when it is not possible to read data
        */
        public Object getTransferData(DataFlavor flavor)
        throws UnsupportedFlavorException, IOException {
            if (!isDataFlavorSupported (flavor)) {
                throw new UnsupportedFlavorException (flavor);
            }
            return transferObject;
        }

        /** Class implementing MultiTransferObject interface. */
        static class TransferObjectImpl implements MultiTransferObject {
            /** transferable objects */
            private Transferable[] trans;

            /** Creates new object from transferable objects.
            * @param trans array of transferable objects
            */
            public TransferObjectImpl (Transferable[] trans) {
                this.trans = trans;
            }

            /** Number of transfered elements.
            * @return number of elements
            */
            public int getCount () {
                return trans.length;
            }

            /** @return Transferable at the specific index */
            public Transferable getTransferableAt(int index) {
                return trans[index];
            }

            /** Test whether data flavor is supported by index-th item.
            *
            * @param index the index of
            * @param flavor flavor to test
            * @return true if flavor is supported by all elements
            */
            public boolean isDataFlavorSupported(int index, DataFlavor flavor) {
                try {
                    return trans[index].isDataFlavorSupported (flavor);
                } catch (Exception e) {
                    return false;
                    // patch to get the Netbeans start under Solaris
                    // [PENDINGbeta]
                }
            }

            /** Test whether each transfered item supports at least one of these
            * flavors. Each item can support different flavor.
            * @param array array of flavors
            */
            public boolean areDataFlavorsSupported (DataFlavor[] array) {
                HashSet flav = new HashSet ();
                for (int i = 0; i < array.length; i++) {
                    flav.add (array[i]);
                }


                // cycles through all transferable objects and scans their content
                // to find out if each supports at least one requested flavor
outer: for (int i = 0; i < trans.length; i++) {
                    // insert all flavors of the first object into array
                    DataFlavor[] flavors = trans[i].getTransferDataFlavors ();
                    if (flavors == null) return false;

                    // loop through rest of Transferable objects
                    for (int j = 0; j < flavors.length; j++) {
                        if (flav.contains (flavors[j])) {
                            // this flavor is supported
                            continue outer;
                        }
                    }
                    // for this transferable no flavor is supported
                    return false;
                }
                return true;

            }

            /** Gets list of all supported flavors for i-th element.
            * @param i the element to find flavors for
            * @return array of supported flavors
            */
            public DataFlavor[] getTransferDataFlavors (int i) {
                return trans[i].getTransferDataFlavors ();
            }

            /**
            * @param indx index of element to work with
            * @param flavor one needs to obtain
            * @return object for the flavor of the i-th element
            */
            public Object getTransferData(int indx, DataFlavor flavor)
            throws UnsupportedFlavorException, IOException {
                return trans[indx].getTransferData (flavor);
            }

            /** Compute common flavors.
            * @param t array of transferable objects
            * @return array of common flavors
            * /
            private static DataFlavor[] computeCommonFlavors (Transferable[] t) {
                if (t.length == 0) {
                    // no flavor is supported => return empty array
                    return new DataFlavor[] { };
                }

                // insert all flavors of the first object into array
                DataFlavor[] flavors = t[0].getTransferDataFlavors ();
                // number of non null elements in flavors array
                int flavorsCount = (flavors == null)? 0 : flavors.length;
                int flavorsLength = flavorsCount; // non-changing length of the original flavors array

                // loop through rest of Transferable objects
                for (int i = 1; i < t.length; i++) {
                    // loop through array
                    for (int j = 0; j < flavorsLength; j++) {
                        // if the flavor is not supported
                        boolean supported = false;
                        try {
                            supported = t[i].isDataFlavorSupported (flavors[j]);
                        } catch (Exception e) {
                            // patch to get the Netbeans start under Solaris
                            // [PENDINGbeta]
                        }
                        if (flavors[j] != null && !supported) {
                            // then clear it
                            flavors[j] = null;
                            flavorsCount--;
                        }
                    }
                }

                // create resulting array
                DataFlavor[] result = new DataFlavor[flavorsLength];
                for (int i = 0, j = 0; i < flavorsLength; i++) {
                    if (flavors[i] != null) {
                        // add it to the result
                        result[j++] = flavors[i];
                    }
                }

                return result;
            }
            */
        }
    }


    /** TransferableOwnerEmpty is TransferableOwner that contains no data.
    *
    * @author Jaroslav Tulach
    */
    private static class Empty extends Object implements Transferable {
        /** Package private constructor to allow only one instance from TransferableOwner.
        */
        Empty() {
        }

        /** Flavors that are supported.
        * @return empty array
        */
        public DataFlavor[] getTransferDataFlavors () {
            return new DataFlavor[] {};
        }

        /** Does not support any flavor
        * @param flavor flavor to test
        * @return false
        */
        public boolean isDataFlavorSupported (DataFlavor flavor) {
            return false;
        }

        /** Creates transferable data for this flavor.
        * @exception UnsupportedFlavorException does not support any flavor
        */
        public Object getTransferData (DataFlavor flavor)
        throws UnsupportedFlavorException, IOException {
            throw new UnsupportedFlavorException (flavor);
        }
    }

}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.