JDK-4066902 : Clipboard.setContents not working for custom flavor
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version:
    1.0e,1.1,1.1.2,1.1.4,1.1.7,1.1.8,1.2.0,1.3.0 1.0e,1.1,1.1.2,1.1.4,1.1.7,1.1.8,1.2.0,1.3.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS:
    generic,solaris,solaris_7,windows_95,windows_nt generic,solaris,solaris_7,windows_95,windows_nt
  • CPU: generic,x86,sparc
  • Submitted: 1997-07-23
  • Updated: 2000-08-03
  • Resolved: 2000-08-03
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Description

Name: el35337			Date: 07/23/97


The clipboard contents in win32 does not seem to be able
to be set to custom flavors: the following code fails
under win32 (NT and 95) but works under solaris:

import java.awt.datatransfer.*;
import java.awt.*;
import java.io.*;
 
class SuperDuperObject
{
    int value;
    public SuperDuperObject(int value) {
        this.value = value;
    }

    public String toString() {
        return "SuperDuper:" + value;
    }
}

class MyTransferable implements Transferable
{

    public static DataFlavor myFlavor;
    static {
        try {
            myFlavor = new DataFlavor(
                            Class.forName("SuperDuperObject"),
                            "SuperDuperObject");
        } catch ( ClassNotFoundException ex ) {
        }
    }

    private static final int MY = 0;
    private static final int STRING = 1;
    private static final int PLAIN_TEXT = 2;

    private DataFlavor[] flavors = {
        myFlavor,
        DataFlavor.stringFlavor,
        DataFlavor.plainTextFlavor
    };

    private SuperDuperObject obj;

    public MyTransferable(SuperDuperObject obj) { this.obj = obj; }
    public synchronized DataFlavor[] getTransferDataFlavors() { return flavors;>
    public boolean isDataFlavorSupported(DataFlavor flavor) {
        return (flavor.equals(flavors[STRING])
                || flavor.equals(flavors[PLAIN_TEXT])
                || flavor.equals(flavors[MY]));
    }

    public synchronized Object getTransferData(DataFlavor flavor)
                        throws UnsupportedFlavorException, IOException {
        if (flavor.equals(flavors[STRING])) {
            return (Object)obj.toString();
        } else if (flavor.equals(flavors[PLAIN_TEXT])) {
            return new StringReader(obj.toString());
        } else if (flavor.equals(flavors[MY])) {
            return obj;
        } else {
            throw new UnsupportedFlavorException(flavor);
        }
    }

    public void lostOwnership(Clipboard clipboard, Transferable contents) {
    }
}

public class ClipTest
    implements ClipboardOwner
{
    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();

    public static void main(String args[])
    {
        new ClipTest();
    }

    public ClipTest() {
        //
        // first create the object and attempt to send it to
        // the clipboard
        SuperDuperObject obj = new SuperDuperObject(222);
        Transferable contents = new MyTransferable(obj);
        clipboard.setContents(contents, this);
        System.out.println("atttempted to set clipboard contents set to: "
                                + obj);
        
        //
        // now grab the content back from the clipboard
        // print it to see what we have
        Transferable content = clipboard.getContents(this);
        System.out.println("content = " + content);
        System.out.println("----");
        System.out.println("if this test worked, the above content");
        System.out.println("should be a MyTransferable object");
        
        if (content != null)
        {
            try {
                Object data = content.getTransferData(MyTransferable.myFlavor);
                System.out.println("data = " + data);
            } catch (Exception e) {
                System.out.println("the clipboard contents do not support "
                    + "the myFlavor DataFlavor");
                e.printStackTrace();
            }
        }
    }
     
    public void lostOwnership(Clipboard clipboard, Transferable contents) {
         System.out.println("Clipboard contents replaced");
    }
        
}

company - Novafex Software Limited , email - ###@###.###
================================================================
======
ronan.mandel@Eng 1997-11-12
As JDK 1.2 is being delayed, I'd like to stress
that access to non-text formats on the system
clipboard is essential for the success of Java.

I've expected this feature in JDK 1.1 already but
it sure can't wait until the release of JDK 1.2.
There must be an easy mechanism to convert the
byte sequences taged by a format key on the
Windows clipboard into a custom object within
an applet or application.

I've been promised this feature for 'the next release'
but this should not be 1.2!!

My main interest is in fetching chemical structure
information from the clipboard to be used within
database search tools. Note: image bitmaps are
not a solution. I need the native format for which
there exist 'industry standards'.

Bernd

PS: I may have missed the description of how to do
this in the current release. If there is anything
more than just 'issue to be resolved', I'd love
to know the resource.




calvin.austin@Eng 1998-06-15
You know bug 4032895 seems related to this, either 4032895 is still broken
or this bug may be fixed

Comments
WORK AROUND Name: el35337 Date: 07/23/97 None. ======================================================================
11-06-2004

EVALUATION paul.sheehan@ireland 1998-04-14 Looks like the native code that is currently there will only handle setting the clipboards contents to strings, and assumes that it will always to using a string. Thus before any of this code is called we do a check to see if the object we are passing is an instance of StringSelection. If so then we set the clipboards contents and if not we ignore it. That's why custom flavours arent working. ===== We will address this and other datatransfer problems in two parts. First, we need to unify the underlying datatransfer for DnD and the Clipboard. Currently, they have two separate implementations. This will give the Clipboard the ability to transfer DataFlavors whose representations are InputStreams, Serializable objects, RMI objects, and lists of files. Once we have this functionality, we need to provide mappings from Java objects to native formats (Image to HBITMAP and AudioClip to WAV for example.) (See BugId 4040183) I have mostly finished a new datatransfer implementation on Windows. This new implementation unifies the underlying datatransfer for DnD and the Clipboard. Unfortunately, a few design problems remain and these may require small API changes. Lara is contacting Roger Calnan to see if there is any way we could get these changes into kestrel. I have not attempted to implement this new design on Solaris, but I suspect my work on Windows could serve as an outline. The new design in centered around the new class WDataTransferer: public class WDataTransferer { public static int[] getFormatsForFlavors(Transferable contents, FlavorMap map); public static int[] getFormatsForFlavors(DataFlavor[] flavors, FlavorMap map); public static DataFlavor[] getFlavorsForFormats(int[] formats, FlavorMap map); public static byte[] translateTransferable(Transferable contents, int format) throws IOException; public static byte[] translateTransferable(Transferable contents, FlavorMap flavorMap, int format) throws IOException; public static Object translateBytes(byte[] bytes, DataFlavor flavor, int format) throws IOException; public static Object translateStream(InputStream str, DataFlavor flavor, int format) throws IOException; } This class has two main purposes: * It extends upon the FlavorMap concept of translating between DataFlavors and "Natives" so that client code can translate between DataFlavors and Windows clipboard formats. These integer clipboard formats are passed directly to clipboard and DnD Win32 functions, so no additional conversion is necessary after this point. Previously, data transfer was mostly based on "Natives" and routines for converting "Natives" to clipboard formats existed in several different places in the code. * It provides functions for translating a Transferable into a byte array representation for a given clipboard format, and functions for the reverse translation for a given DataFlavor. The reverse translation can also operate on an InputStream. In some cases, a DropTarget can receive data in the form of a file or a COM stream. If only a portion of the data will be read, converting the file or COM stream into a byte array is unnecessarilly inefficient. Once this new class was in place, I rewrote the DnD Java and Native code to push all of these tasks through WDataTransferer. I then began to hook WClipboard into this new class and ran into several interesting issues: * Historically, the Clipboard and DnD have returned text in two very different forms. Drag and Drop returns a raw stream of bytes. In fact, the stream is so raw, that you need to use DataFlavor.getReaderForText to get anything useful out of it. The Clipboard has always returned Strings or InputStreams/Readers wrapped around Strings. This text is already completely decoded. * When converting a String to Windows text, "\n" must be converted to "\r\n" and a trailing NUL byte (or 2 for Unicode) must be added. * When converting Windows text to a String, all "\r" must be deleted and the bytes must be searched for the first NUL byte (or first two NUL bytes next to each other for Unicode) and the String truncated one byte before this point. * While I have added these extra conversions to the String translations, they are still not in the InputStream translations. This means that at this point the Clipboard is using them, but DnD is not. Should the translations also be applied to InputStreams, or should they become part of the translating Readers returned by getReaderForText? What about the translation case from String to Windows Unicode bytes? * There is a special block of code which adds the Unicode ordering mark to the front of a Unicode byte array. This seems unnecessary. Instead, we should just return a Reader from getReaderForText which is backed by ByteToCharUnicodeLittleUnmarked instead of ByteToCharUnicodeLittle. Likewise, we should make sure we don't add the ordering byte into the outgoing data. * Since there is no way for client code to synchronize access to the system clipboard, we cannot return a Transferable which creates transfer data for a particular DataFlavor on demand. Instead, when client code calls Clipboard.getContents(), we have to pre-render data for all possible DataFlavors. To do this, a created a new class FullyRenderedTransferable (which is in WClipboard.java). (Maybe we should provide a way to lock and unlock the Clipboard explicitly from client code? We could do this in Merlin.) * java.awt.datatransfer.StringSelection is a broken mess. It claims to support DataFlavor.plainTextFlavor, whose representation class is an InputStream, but if you ask a StringSelection for data in that flavor, you actually get back a StringReader. See BugIds 4147507, 4209435, 4221139, and 4283047. * In order to work-around this bug, if client code sends a StringSelection via the Clipboard or DnD, I ignore the flavors to natives map, and just query for the data in the DataFlavor.stringFlavor flavor. This is *wrong*. We should not ignore the flavors to natives map. * Either StringSelection should support lots more DataFlavors (charset=ascii and charset=iso8859_1 are a must), or the data transfer engine should apply these conversions implicitly. It doesn't make sense to advertise that your data is available only as Unicode text, for example. There is certainly a conversion from Unicode to ascii and iso8859_1, even if the conversion is lossy. The conversion should be available for native applications which don't understand Unicode. * For backwards-compatibility, text retrieved from the Clipboard should be available in the DataFlavor.stringFlavor and DataFlavor.plainTextFlavor flavors (because a StringSelection was previously returned). Again, we have to maintain the broken functionality of StringSelection, so asking for the data in the DataFlavor.plainTextFlavor flavor must return a StringReader. In addition, if flavormap.properties specifies a flavor different than one of these two, we should make that available as well. * The idea of a one-to-one and onto mapping of flavors to natives in flavormap.properties seems wrong to me. Why can't this be opened up to provide a many-to-many mapping? This restriction already leads to problems in the new implementation. StringSelection reports that it supports stringFlavor and plainTextFlavor. stringFlavor has no Native mapping, and plainTextFlavor maps to "UNICODE TEXT". Now, Windows 95 doesn't support "UNICODE TEXT" (which is native format 13), so now no native apps can read StringSelections! Again, this could be fixed by augmenting StringSelection, adding implicit conversions, or changing the format of flavormap.properties. david.mendenhall@eng 1999-11-08 This work has been completed on Win32 for merlin and ladybird. Reassigning bug to new engineer for Solaris side. david.mendenhall@eng 2000-02-08 Work completed. david.mendenhall@east 2000-08-03
08-02-2000