提交 ccedcb80 编写于 作者: D denis

7075105: WIN: Provide a way to format HTML on drop

Reviewed-by: uta, serb
上级 33efe959
......@@ -174,7 +174,7 @@ public class CDataTransferer extends DataTransferer {
bytes = Normalizer.normalize(new String(bytes, "UTF8"), Form.NFC).getBytes("UTF8");
}
return super.translateBytesOrStream(stream, bytes, flavor, format, transferable);
return super.translateBytes(bytes, flavor, format, transferable);
}
......@@ -257,16 +257,13 @@ public class CDataTransferer extends DataTransferer {
private native byte[] imageDataToPlatformImageBytes(int[] rData, int nW, int nH);
/**
* Translates either a byte array or an input stream which contain
* Translates a byte array which contains
* platform-specific image data in the given format into an Image.
*/
protected Image platformImageBytesOrStreamToImage(InputStream stream, byte[] bytes, long format) throws IOException {
byte[] imageData = bytes;
if (imageData == null)
imageData = inputStreamToByteArray(stream);
return getImageForByteStream(imageData);
protected Image platformImageBytesToImage(byte[] bytes, long format)
throws IOException
{
return getImageForByteStream(bytes);
}
private native Image getImageForByteStream(byte[] bytes);
......
......@@ -25,7 +25,6 @@
package java.awt.datatransfer;
import java.awt.Toolkit;
import java.io.*;
import java.nio.*;
import java.util.*;
......@@ -162,6 +161,18 @@ public class DataFlavor implements Externalizable, Cloneable {
}
}
/*
* private initializer
*/
static private DataFlavor initHtmlDataFlavor(String htmlFlavorType) {
try {
return new DataFlavor ("text/html; class=java.lang.String;document=" +
htmlFlavorType + ";charset=Unicode");
} catch (Exception e) {
return null;
}
}
/**
* The <code>DataFlavor</code> representing a Java Unicode String class,
* where:
......@@ -245,6 +256,46 @@ public class DataFlavor implements Externalizable, Cloneable {
*/
public static final String javaRemoteObjectMimeType = "application/x-java-remote-object";
/**
* Represents a piece of an HTML markup. The markup consists of the part
* selected on the source side. Therefore some tags in the markup may be
* unpaired. If the flavor is used to represent the data in
* a {@link Transferable} instance, no additional changes will be made.
* This DataFlavor instance represents the same HTML markup as DataFlavor
* instances which content MIME type does not contain document parameter
* and representation class is the String class.
* <pre>
* representationClass = String
* mimeType = "text/html"
* </pre>
*/
public static DataFlavor selectionHtmlFlavor = initHtmlDataFlavor("selection");
/**
* Represents a piece of an HTML markup. If possible, the markup received
* from a native system is supplemented with pair tags to be
* a well-formed HTML markup. If the flavor is used to represent the data in
* a {@link Transferable} instance, no additional changes will be made.
* <pre>
* representationClass = String
* mimeType = "text/html"
* </pre>
*/
public static DataFlavor fragmentHtmlFlavor = initHtmlDataFlavor("fragment");
/**
* Represents a piece of an HTML markup. If possible, the markup
* received from a native system is supplemented with additional
* tags to make up a well-formed HTML document. If the flavor is used to
* represent the data in a {@link Transferable} instance,
* no additional changes will be made.
* <pre>
* representationClass = String
* mimeType = "text/html"
* </pre>
*/
public static DataFlavor allHtmlFlavor = initHtmlDataFlavor("all");
/**
* Constructs a new <code>DataFlavor</code>. This constructor is
* provided only for the purpose of supporting the
......@@ -949,8 +1000,8 @@ public class DataFlavor implements Externalizable, Cloneable {
return false;
}
if ("text".equals(getPrimaryType()) &&
DataTransferer.doesSubtypeSupportCharset(this) &&
if ("text".equals(getPrimaryType())) {
if (DataTransferer.doesSubtypeSupportCharset(this) &&
representationClass != null &&
!(isRepresentationClassReader() ||
String.class.equals(representationClass) ||
......@@ -971,6 +1022,17 @@ public class DataFlavor implements Externalizable, Cloneable {
}
}
}
if ("html".equals(getSubType()) &&
this.getParameter("document") != null )
{
if (!this.getParameter("document").
equals(that.getParameter("document")))
{
return false;
}
}
}
}
return true;
......
......@@ -41,7 +41,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
......@@ -100,6 +100,11 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
*/
private static final String TEXT_PLAIN_BASE_TYPE = "text/plain";
/**
* A String representing text/html MIME type.
*/
private static final String HTML_TEXT_BASE_TYPE = "text/html";
/**
* This constant is passed to flavorToNativeLookup() to indicate that a
* a native should be synthesized, stored, and returned by encoding the
......@@ -113,7 +118,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* text DataFlavors).
* Do not use the field directly, use getNativeToFlavor() instead.
*/
private Map nativeToFlavor = new HashMap();
private final Map<String, List<DataFlavor>> nativeToFlavor = new HashMap<>();
/**
* Accessor to nativeToFlavor map. Since we use lazy initialization we must
......@@ -122,7 +127,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
*
* @return nativeToFlavor
*/
private Map getNativeToFlavor() {
private Map<String, List<DataFlavor>> getNativeToFlavor() {
if (!isMapInitialized) {
initSystemFlavorMap();
}
......@@ -134,7 +139,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* native Strings.
* Do not use the field directly, use getFlavorToNative() instead.
*/
private Map flavorToNative = new HashMap();
private final Map flavorToNative = new HashMap();
/**
* Accessor to flavorToNative map. Since we use lazy initialization we must
......@@ -421,14 +426,17 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
}
}
// For text/* flavors, store mappings in separate maps to
// enable dynamic mapping generation at a run-time.
final LinkedHashSet<DataFlavor> dfs = new LinkedHashSet<>();
dfs.add(flavor);
if ("text".equals(flavor.getPrimaryType())) {
store(value, key, getFlavorToNative());
store(key, value, getNativeToFlavor());
} else {
store(flavor, key, getFlavorToNative());
store(key, flavor, getNativeToFlavor());
dfs.addAll(convertMimeTypeToDataFlavors(value));
}
for (DataFlavor df : dfs) {
store(df, key, getFlavorToNative());
store(key, df, getNativeToFlavor());
}
}
}
......@@ -530,7 +538,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* only if the specified native is encoded as a Java MIME type.
*/
private List nativeToFlavorLookup(String nat) {
List flavors = (List)getNativeToFlavor().get(nat);
List<DataFlavor> flavors = getNativeToFlavor().get(nat);
if (nat != null && !disabledMappingGenerationKeys.contains(nat)) {
DataTransferer transferer = DataTransferer.getInstance();
......@@ -625,7 +633,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
getNativesForFlavorCache.remove(flav);
getNativesForFlavorCache.remove(null);
List flavors = (List)getNativeToFlavor().get(encoded);
List<DataFlavor> flavors = getNativeToFlavor().get(encoded);
if (flavors == null) {
flavors = new ArrayList(1);
getNativeToFlavor().put(encoded, flavors);
......@@ -681,7 +689,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
}
if (flav == null) {
retval = new ArrayList(getNativeToFlavor().keySet());
retval = new ArrayList<String>(getNativeToFlavor().keySet());
} else if (disabledMappingGenerationKeys.contains(flav)) {
// In this case we shouldn't synthesize a native for this flavor,
// since its mappings were explicitly specified.
......@@ -809,140 +817,162 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
}
}
LinkedList retval = new LinkedList();
final LinkedHashSet <DataFlavor> returnValue =
new LinkedHashSet<>();
if (nat == null) {
List natives = getNativesForFlavor(null);
HashSet dups = new HashSet(natives.size());
final List<String> natives = getNativesForFlavor(null);
for (Iterator natives_iter = natives.iterator();
natives_iter.hasNext(); )
for (String n : natives)
{
List flavors =
getFlavorsForNative((String)natives_iter.next());
for (Iterator flavors_iter = flavors.iterator();
flavors_iter.hasNext(); )
final List<DataFlavor> flavors = getFlavorsForNative(n);
for (DataFlavor df : flavors)
{
Object flavor = flavors_iter.next();
if (dups.add(flavor)) {
retval.add(flavor);
}
returnValue.add(df);
}
}
} else {
List flavors = nativeToFlavorLookup(nat);
final List<DataFlavor> flavors = nativeToFlavorLookup(nat);
if (disabledMappingGenerationKeys.contains(nat)) {
return flavors;
}
HashSet dups = new HashSet(flavors.size());
final List<DataFlavor> flavorsAndBaseTypes =
nativeToFlavorLookup(nat);
List flavorsAndbaseTypes = nativeToFlavorLookup(nat);
for (DataFlavor df : flavorsAndBaseTypes) {
returnValue.add(df);
if ("text".equals(df.getPrimaryType())) {
try {
returnValue.addAll(
convertMimeTypeToDataFlavors(
new MimeType(df.getMimeType()
).getBaseType()));
} catch (MimeTypeParseException e) {
e.printStackTrace();
}
}
}
}
final ArrayList arrayList = new ArrayList(returnValue);
getFlavorsForNativeCache.put(nat, new SoftReference(arrayList));
return (List)arrayList.clone();
}
private static LinkedHashSet<DataFlavor> convertMimeTypeToDataFlavors(
final String baseType) {
final LinkedHashSet<DataFlavor> returnValue =
new LinkedHashSet<DataFlavor>();
for (Iterator flavorsAndbaseTypes_iter =
flavorsAndbaseTypes.iterator();
flavorsAndbaseTypes_iter.hasNext(); )
{
Object value = flavorsAndbaseTypes_iter.next();
if (value instanceof String) {
String baseType = (String)value;
String subType = null;
try {
MimeType mimeType = new MimeType(baseType);
final MimeType mimeType = new MimeType(baseType);
subType = mimeType.getSubType();
} catch (MimeTypeParseException mtpe) {
// Cannot happen, since we checked all mappings
// on load from flavormap.properties.
assert(false);
}
if (DataTransferer.doesSubtypeSupportCharset(subType,
null)) {
if (TEXT_PLAIN_BASE_TYPE.equals(baseType) &&
dups.add(DataFlavor.stringFlavor))
if (DataTransferer.doesSubtypeSupportCharset(subType, null)) {
if (TEXT_PLAIN_BASE_TYPE.equals(baseType))
{
retval.add(DataFlavor.stringFlavor);
returnValue.add(DataFlavor.stringFlavor);
}
for (int i = 0; i < UNICODE_TEXT_CLASSES.length; i++) {
for (String unicodeClassName : UNICODE_TEXT_CLASSES) {
final String mimeType = baseType + ";charset=Unicode;class=" +
unicodeClassName;
final LinkedHashSet<String> mimeTypes =
handleHtmlMimeTypes(baseType, mimeType);
for (String mt : mimeTypes) {
DataFlavor toAdd = null;
try {
toAdd = new DataFlavor
(baseType + ";charset=Unicode;class=" +
UNICODE_TEXT_CLASSES[i]);
toAdd = new DataFlavor(mt);
} catch (ClassNotFoundException cannotHappen) {
}
if (dups.add(toAdd)) {
retval.add(toAdd);
returnValue.add(toAdd);
}
}
for (Iterator charset_iter =
DataTransferer.standardEncodings();
charset_iter.hasNext(); )
{
String charset = (String)charset_iter.next();
for (String charset : DataTransferer.standardEncodings()) {
for (int i = 0; i < ENCODED_TEXT_CLASSES.length;
i++)
{
DataFlavor toAdd = null;
try {
toAdd = new DataFlavor
(baseType + ";charset=" + charset +
";class=" + ENCODED_TEXT_CLASSES[i]);
} catch (ClassNotFoundException cannotHappen) {
}
for (String encodedTextClass : ENCODED_TEXT_CLASSES) {
final String mimeType =
baseType + ";charset=" + charset +
";class=" + encodedTextClass;
final LinkedHashSet<String> mimeTypes =
handleHtmlMimeTypes(baseType, mimeType);
for (String mt : mimeTypes) {
DataFlavor df = null;
try {
df = new DataFlavor(mt);
// Check for equality to plainTextFlavor so
// that we can ensure that the exact charset of
// plainTextFlavor, not the canonical charset
// or another equivalent charset with a
// different name, is used.
if (toAdd.equals(DataFlavor.plainTextFlavor)) {
toAdd = DataFlavor.plainTextFlavor;
if (df.equals(DataFlavor.plainTextFlavor)) {
df = DataFlavor.plainTextFlavor;
}
} catch (ClassNotFoundException cannotHappen) {
}
if (dups.add(toAdd)) {
retval.add(toAdd);
returnValue.add(df);
}
}
}
if (TEXT_PLAIN_BASE_TYPE.equals(baseType) &&
dups.add(DataFlavor.plainTextFlavor))
if (TEXT_PLAIN_BASE_TYPE.equals(baseType))
{
retval.add(DataFlavor.plainTextFlavor);
returnValue.add(DataFlavor.plainTextFlavor);
}
} else {
// Non-charset text natives should be treated as
// opaque, 8-bit data in any of its various
// representations.
for (int i = 0; i < ENCODED_TEXT_CLASSES.length; i++) {
for (String encodedTextClassName : ENCODED_TEXT_CLASSES) {
DataFlavor toAdd = null;
try {
toAdd = new DataFlavor(baseType +
";class=" + ENCODED_TEXT_CLASSES[i]);
";class=" + encodedTextClassName);
} catch (ClassNotFoundException cannotHappen) {
}
if (dups.add(toAdd)) {
retval.add(toAdd);
returnValue.add(toAdd);
}
}
return returnValue;
}
} else {
DataFlavor flavor = (DataFlavor)value;
if (dups.add(flavor)) {
retval.add(flavor);
}
}
private static final String [] htmlDocumntTypes =
new String [] {"all", "selection", "fragment"};
private static LinkedHashSet<String> handleHtmlMimeTypes(
String baseType, String mimeType) {
LinkedHashSet<String> returnValues = new LinkedHashSet<>();
if (HTML_TEXT_BASE_TYPE.equals(baseType)) {
for (String documentType : htmlDocumntTypes) {
returnValues.add(mimeType + ";document=" + documentType);
}
} else {
returnValues.add(mimeType);
}
ArrayList arrayList = new ArrayList(retval);
getFlavorsForNativeCache.put(nat, new SoftReference(arrayList));
return (List)arrayList.clone();
return returnValues;
}
/**
......
......@@ -171,12 +171,12 @@ public abstract class DataTransferer {
* Lazy initialization of Standard Encodings.
*/
private static class StandardEncodingsHolder {
private static final SortedSet standardEncodings = load();
private static final SortedSet<String> standardEncodings = load();
private static SortedSet load() {
private static SortedSet<String> load() {
final Comparator comparator =
new CharsetComparator(IndexedComparator.SELECT_WORST);
final SortedSet tempSet = new TreeSet(comparator);
final SortedSet<String> tempSet = new TreeSet<String>(comparator);
tempSet.add("US-ASCII");
tempSet.add("ISO-8859-1");
tempSet.add("UTF-8");
......@@ -523,8 +523,8 @@ public abstract class DataTransferer {
* So as to avoid loading all available character converters, optional,
* non-standard, character sets are not included.
*/
public static Iterator standardEncodings() {
return StandardEncodingsHolder.standardEncodings.iterator();
public static Set <String> standardEncodings() {
return StandardEncodingsHolder.standardEncodings;
}
/**
......@@ -1068,17 +1068,10 @@ public abstract class DataTransferer {
*
* Native to Java string conversion
*/
private String translateBytesOrStreamToString(InputStream str, byte[] bytes,
long format,
private String translateBytesToString(byte[] bytes, long format,
Transferable localeTransferable)
throws IOException
{
// A String holds all of its data in memory at one time, so
// we can't avoid reading the entire InputStream at this point.
if (bytes == null) {
bytes = inputStreamToByteArray(str);
}
str.close();
Long lFormat = Long.valueOf(format);
String charset = getBestCharsetForTextFormat(lFormat, localeTransferable);
......@@ -1221,13 +1214,13 @@ search:
("cannot transfer non-text data as Reader");
}
Reader r = (Reader)obj;
StringBuffer buf = new StringBuffer();
try (Reader r = (Reader)obj) {
int c;
while ((c = r.read()) != -1) {
buf.append((char)c);
}
r.close();
}
return translateTransferableString(
buf.toString(),
......@@ -1309,7 +1302,7 @@ search:
return bytes;
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] theByteArray = null;
// Target data is a file list. Source data must be a
// java.util.List which contains java.io.File or String instances.
......@@ -1324,8 +1317,9 @@ search:
final ArrayList<String> fileList = castToFiles(list, userProtectionDomain);
bos = convertFileListToBytes(fileList);
try (ByteArrayOutputStream bos = convertFileListToBytes(fileList)) {
theByteArray = bos.toByteArray();
}
// Target data is a URI list. Source data must be a
// java.util.List which contains java.io.File or String instances.
......@@ -1360,57 +1354,72 @@ search:
}
byte[] eoln = "\r\n".getBytes(targetCharset);
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
for (int i = 0; i < uriList.size(); i++) {
byte[] bytes = uriList.get(i).getBytes(targetCharset);
bos.write(bytes, 0, bytes.length);
bos.write(eoln, 0, eoln.length);
}
theByteArray = bos.toByteArray();
}
// Source data is an InputStream. For arbitrary flavors, just grab the
// bytes and dump them into a byte array. For text flavors, decode back
// to a String and recur to reencode according to the requested format.
} else if (flavor.isRepresentationClassInputStream()) {
InputStream is = (InputStream)obj;
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
try (InputStream is = (InputStream)obj) {
boolean eof = false;
int avail = is.available();
byte[] tmp = new byte[avail > 8192 ? avail : 8192];
do {
int ret;
if (!(eof = (ret = is.read(tmp, 0, tmp.length)) == -1)) {
bos.write(tmp, 0, ret);
int aValue;
if (!(eof = (aValue = is.read(tmp, 0, tmp.length)) == -1)) {
bos.write(tmp, 0, aValue);
}
} while (!eof);
is.close();
}
if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
byte[] bytes = bos.toByteArray();
bos.close();
String sourceEncoding = DataTransferer.getTextCharset(flavor);
return translateTransferableString(
new String(bytes, sourceEncoding),
format);
}
theByteArray = bos.toByteArray();
}
// Source data is an RMI object
} else if (flavor.isRepresentationClassRemote()) {
Object mo = RMI.newMarshalledObject(obj);
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(mo);
oos.close();
theByteArray = convertObjectToBytes(mo);
// Source data is Serializable
} else if (flavor.isRepresentationClassSerializable()) {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.close();
theByteArray = convertObjectToBytes(obj);
} else {
throw new IOException("data translation failed");
}
byte[] ret = bos.toByteArray();
bos.close();
return ret;
return theByteArray;
}
private static byte[] convertObjectToBytes(Object object) throws IOException {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos))
{
oos.writeObject(object);
return bos.toByteArray();
}
}
protected abstract ByteArrayOutputStream convertFileListToBytes(ArrayList<String> fileList) throws IOException;
......@@ -1565,38 +1574,8 @@ search:
long format, Transferable localeTransferable)
throws IOException
{
return translateBytesOrStream(null, bytes, flavor, format,
localeTransferable);
}
public Object translateStream(InputStream str, DataFlavor flavor,
long format, Transferable localeTransferable)
throws IOException
{
return translateBytesOrStream(str, null, flavor, format,
localeTransferable);
}
/**
* Primary translation function for translating either a byte array or
* an InputStream into an Object, given a source format and a target
* DataFlavor.
*
* One of str/bytes is non-null; the other is null.
* The conversion from byte[] to InputStream is cheap, so do that
* immediately if necessary. The opposite conversion is expensive,
* so avoid it if possible.
*/
protected Object translateBytesOrStream(InputStream str, byte[] bytes,
DataFlavor flavor, long format,
Transferable localeTransferable)
throws IOException
{
if (str == null) {
str = new ByteArrayInputStream(bytes);
}
Object theObject = null;
// Source data is a file list. Use the dragQueryFile native function to
// do most of the decoding. Then wrap File objects around the String
......@@ -1605,12 +1584,8 @@ search:
if (!DataFlavor.javaFileListFlavor.equals(flavor)) {
throw new IOException("data translation failed");
}
if (bytes == null) {
bytes = inputStreamToByteArray(str);
}
String[] filenames = dragQueryFile(bytes);
if (filenames == null) {
str.close();
return null;
}
......@@ -1619,78 +1594,25 @@ search:
for (int i = 0; i < filenames.length; i++) {
files[i] = new File(filenames[i]);
}
str.close();
// Turn the list of Files into a List and return
return Arrays.asList(files);
// Source data is a URI list. Convert to DataFlavor.javaFileListFlavor
// where possible.
} else if (isURIListFormat(format) && DataFlavor.javaFileListFlavor.equals(flavor)) {
try {
URI uris[] = dragQueryURIs(str, bytes, format, localeTransferable);
if (uris == null) {
return null;
}
ArrayList files = new ArrayList();
for (URI uri : uris) {
try {
files.add(new File(uri));
} catch (IllegalArgumentException illegalArg) {
// When converting from URIs to less generic files,
// common practice (Wine, SWT) seems to be to
// silently drop the URIs that aren't local files.
}
}
return files;
} finally {
str.close();
}
theObject = Arrays.asList(files);
// Target data is a String. Strip terminating NUL bytes. Decode bytes
// into characters. Search-and-replace EOLN.
} else if (String.class.equals(flavor.getRepresentationClass()) &&
isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
return translateBytesOrStreamToString(
str, bytes,
format, localeTransferable);
// Special hack to maintain backwards-compatibility with the brokenness
// of StringSelection. Return a StringReader instead of an InputStream.
// Recur to obtain String and encapsulate.
} else if (DataFlavor.plainTextFlavor.equals(flavor)) {
return new StringReader(translateBytesOrStreamToString(
str, bytes,
format, localeTransferable));
// Target data is an InputStream. For arbitrary flavors, just return
// the raw bytes. For text flavors, decode to strip terminators and
// search-and-replace EOLN, then reencode according to the requested
// flavor.
} else if (flavor.isRepresentationClassInputStream()) {
return translateBytesOrStreamToInputStream(str, flavor, format,
localeTransferable);
theObject = translateBytesToString(bytes, format, localeTransferable);
// Target data is a Reader. Obtain data in InputStream format, encoded
// as "Unicode" (utf-16be). Then use an InputStreamReader to decode
// back to chars on demand.
} else if (flavor.isRepresentationClassReader()) {
if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
throw new IOException
("cannot transfer non-text data as Reader");
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) {
theObject = translateStream(bais,
flavor, format, localeTransferable);
}
InputStream is = (InputStream)
translateBytesOrStreamToInputStream
(str, DataFlavor.plainTextFlavor, format,
localeTransferable);
String unicode =
DataTransferer.getTextCharset(DataFlavor.plainTextFlavor);
Reader reader = new InputStreamReader(is, unicode);
return constructFlavoredObject(reader, flavor, Reader.class);
// Target data is a CharBuffer. Recur to obtain String and wrap.
} else if (flavor.isRepresentationClassCharBuffer()) {
if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
......@@ -1698,11 +1620,10 @@ search:
("cannot transfer non-text data as CharBuffer");
}
CharBuffer buffer = CharBuffer.wrap(translateBytesOrStreamToString(
str, bytes,
format, localeTransferable));
CharBuffer buffer = CharBuffer.wrap(
translateBytesToString(bytes,format, localeTransferable));
return constructFlavoredObject(buffer, flavor, CharBuffer.class);
theObject = constructFlavoredObject(buffer, flavor, CharBuffer.class);
// Target data is a char array. Recur to obtain String and convert to
// char array.
......@@ -1712,9 +1633,8 @@ search:
("cannot transfer non-text data as char array");
}
return translateBytesOrStreamToString(
str, bytes,
format, localeTransferable).toCharArray();
theObject = translateBytesToString(
bytes, format, localeTransferable).toCharArray();
// Target data is a ByteBuffer. For arbitrary flavors, just return
// the raw bytes. For text flavors, convert to a String to strip
......@@ -1722,20 +1642,14 @@ search:
// the requested flavor.
} else if (flavor.isRepresentationClassByteBuffer()) {
if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
bytes = translateBytesOrStreamToString(
str, bytes,
format, localeTransferable
).getBytes(
bytes = translateBytesToString(
bytes, format, localeTransferable).getBytes(
DataTransferer.getTextCharset(flavor)
);
} else {
if (bytes == null) {
bytes = inputStreamToByteArray(str);
}
}
ByteBuffer buffer = ByteBuffer.wrap(bytes);
return constructFlavoredObject(buffer, flavor, ByteBuffer.class);
theObject = constructFlavoredObject(buffer, flavor, ByteBuffer.class);
// Target data is a byte array. For arbitrary flavors, just return
// the raw bytes. For text flavors, convert to a String to strip
......@@ -1743,40 +1657,28 @@ search:
// the requested flavor.
} else if (byteArrayClass.equals(flavor.getRepresentationClass())) {
if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
return translateBytesOrStreamToString(
str, bytes,
format, localeTransferable
).getBytes(
DataTransferer.getTextCharset(flavor)
);
theObject = translateBytesToString(
bytes, format, localeTransferable
).getBytes(DataTransferer.getTextCharset(flavor));
} else {
return (bytes != null) ? bytes : inputStreamToByteArray(str);
theObject = bytes;
}
// Target data is an RMI object
} else if (flavor.isRepresentationClassRemote()) {
try {
byte[] ba = inputStreamToByteArray(str);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(ba));
Object ret = RMI.getMarshalledObject(ois.readObject());
ois.close();
str.close();
return ret;
} catch (Exception e) {
throw new IOException(e.getMessage());
// Target data is an InputStream. For arbitrary flavors, just return
// the raw bytes. For text flavors, decode to strip terminators and
// search-and-replace EOLN, then reencode according to the requested
// flavor.
} else if (flavor.isRepresentationClassInputStream()) {
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) {
theObject = translateStream(bais, flavor, format, localeTransferable);
}
// Target data is Serializable
} else if (flavor.isRepresentationClassSerializable()) {
try {
byte[] ba = inputStreamToByteArray(str);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(ba));
Object ret = ois.readObject();
ois.close();
str.close();
return ret;
} catch (Exception e) {
throw new IOException(e.getMessage());
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) {
theObject = translateStream(bais, flavor, format, localeTransferable);
}
// Target data is Image
......@@ -1785,20 +1687,118 @@ search:
throw new IOException("data translation failed");
}
Image image = platformImageBytesOrStreamToImage(str, bytes, format);
str.close();
return image;
theObject = platformImageBytesToImage(bytes, format);
}
if (theObject == null) {
throw new IOException("data translation failed");
}
return theObject;
}
/**
* Primary translation function for translating
* an InputStream into an Object, given a source format and a target
* DataFlavor.
*/
public Object translateStream(InputStream str, DataFlavor flavor,
long format, Transferable localeTransferable)
throws IOException
{
Object theObject = null;
// Source data is a URI list. Convert to DataFlavor.javaFileListFlavor
// where possible.
if (isURIListFormat(format)
&& DataFlavor.javaFileListFlavor.equals(flavor))
{
URI uris[] = dragQueryURIs(str, format, localeTransferable);
if (uris == null) {
return null;
}
ArrayList files = new ArrayList();
for (URI uri : uris) {
try {
files.add(new File(uri));
} catch (IllegalArgumentException illegalArg) {
// When converting from URIs to less generic files,
// common practice (Wine, SWT) seems to be to
// silently drop the URIs that aren't local files.
}
}
theObject = files;
// Special hack to maintain backwards-compatibility with the brokenness
// of StringSelection. Return a StringReader instead of an InputStream.
// Recur to obtain String and encapsulate.
} else if (DataFlavor.plainTextFlavor.equals(flavor)) {
theObject = new StringReader(translateBytesToString(
inputStreamToByteArray(str),
format, localeTransferable));
// Target data is an InputStream. For arbitrary flavors, just return
// the raw bytes. For text flavors, decode to strip terminators and
// search-and-replace EOLN, then reencode according to the requested
// flavor.
} else if (flavor.isRepresentationClassInputStream()) {
theObject = translateStreamToInputStream(str, flavor, format,
localeTransferable);
// Target data is a Reader. Obtain data in InputStream format, encoded
// as "Unicode" (utf-16be). Then use an InputStreamReader to decode
// back to chars on demand.
} else if (flavor.isRepresentationClassReader()) {
if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
throw new IOException
("cannot transfer non-text data as Reader");
}
InputStream is = (InputStream)translateStreamToInputStream(
str, DataFlavor.plainTextFlavor,
format, localeTransferable);
String unicode = DataTransferer.getTextCharset(DataFlavor.plainTextFlavor);
Reader reader = new InputStreamReader(is, unicode);
theObject = constructFlavoredObject(reader, flavor, Reader.class);
// Target data is an RMI object
} else if (flavor.isRepresentationClassRemote()) {
try (ObjectInputStream ois =
new ObjectInputStream(str))
{
theObject = RMI.getMarshalledObject(ois.readObject());
}catch (Exception e) {
throw new IOException(e.getMessage());
}
// Target data is Serializable
} else if (flavor.isRepresentationClassSerializable()) {
try (ObjectInputStream ois =
new ObjectInputStream(str))
{
theObject = ois.readObject();
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
return theObject;
}
/**
* For arbitrary flavors, just use the raw InputStream. For text flavors,
* ReencodingInputStream will decode and reencode the InputStream on demand
* so that we can strip terminators and search-and-replace EOLN.
*/
private Object translateBytesOrStreamToInputStream
private Object translateStreamToInputStream
(InputStream str, DataFlavor flavor, long format,
Transferable localeTransferable) throws IOException
{
......@@ -2054,7 +2054,6 @@ search:
* Decodes URIs from either a byte array or a stream.
*/
protected URI[] dragQueryURIs(InputStream stream,
byte[] bytes,
long format,
Transferable localeTransferable)
throws IOException
......@@ -2067,10 +2066,10 @@ search:
* Translates either a byte array or an input stream which contain
* platform-specific image data in the given format into an Image.
*/
protected abstract Image platformImageBytesOrStreamToImage(InputStream str,
byte[] bytes,
long format)
throws IOException;
protected abstract Image platformImageBytesToImage(
byte[] bytes,long format) throws IOException;
/**
* Translates either a byte array or an input stream which contain
......@@ -2078,13 +2077,9 @@ search:
*
* @param mimeType image MIME type, such as: image/png, image/jpeg, image/gif
*/
protected Image standardImageBytesOrStreamToImage(InputStream inputStream,
byte[] bytes,
String mimeType)
throws IOException {
if (inputStream == null) {
inputStream = new ByteArrayInputStream(bytes);
}
protected Image standardImageBytesToImage(
byte[] bytes, String mimeType) throws IOException
{
Iterator readerIterator = ImageIO.getImageReadersByMIMEType(mimeType);
......@@ -2097,9 +2092,9 @@ search:
while (readerIterator.hasNext()) {
ImageReader imageReader = (ImageReader)readerIterator.next();
try {
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) {
ImageInputStream imageInputStream =
ImageIO.createImageInputStream(inputStream);
ImageIO.createImageInputStream(bais);
try {
ImageReadParam param = imageReader.getDefaultReadParam();
......@@ -2456,7 +2451,7 @@ search:
protected static byte[] inputStreamToByteArray(InputStream str)
throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
int len = 0;
byte[] buf = new byte[8192];
......@@ -2466,6 +2461,7 @@ search:
return baos.toByteArray();
}
}
/**
* Returns platform-specific mappings for the specified native.
......
......@@ -57,7 +57,6 @@ import sun.awt.AppContext;
import sun.awt.SunToolkit;
import sun.awt.datatransfer.DataTransferer;
import sun.awt.datatransfer.ToolkitThreadBlockedHandler;
import sun.security.util.SecurityConstants;
/**
* <p>
......@@ -260,6 +259,7 @@ public abstract class SunDropTargetContextPeer implements DropTargetContextPeer,
}
final long format = lFormat.longValue();
Object ret = getNativeData(format);
if (ret instanceof byte[]) {
......@@ -270,11 +270,14 @@ public abstract class SunDropTargetContextPeer implements DropTargetContextPeer,
throw new InvalidDnDOperationException(e.getMessage());
}
} else if (ret instanceof InputStream) {
InputStream inputStream = (InputStream)ret;
try {
return DataTransferer.getInstance().
translateStream((InputStream)ret, df, format, this);
translateStream(inputStream, df, format, this);
} catch (IOException e) {
throw new InvalidDnDOperationException(e.getMessage());
} finally {
inputStream.close();
}
} else {
throw new IOException("no native data was transfered");
......
......@@ -212,10 +212,9 @@ public class XDataTransferer extends DataTransferer {
* Translates either a byte array or an input stream which contain
* platform-specific image data in the given format into an Image.
*/
protected Image platformImageBytesOrStreamToImage(InputStream inputStream,
byte[] bytes,
long format)
throws IOException {
protected Image platformImageBytesToImage(
byte[] bytes, long format) throws IOException
{
String mimeType = null;
if (format == PNG_ATOM.getAtom()) {
mimeType = "image/png";
......@@ -235,7 +234,7 @@ public class XDataTransferer extends DataTransferer {
}
}
if (mimeType != null) {
return standardImageBytesOrStreamToImage(inputStream, bytes, mimeType);
return standardImageBytesToImage(bytes, mimeType);
} else {
String nativeFormat = getNativeForFormat(format);
throw new IOException("Translation from " + nativeFormat +
......@@ -330,8 +329,8 @@ public class XDataTransferer extends DataTransferer {
* a valid MIME and return a list of flavors to which the data in this MIME
* type can be translated by the Data Transfer subsystem.
*/
public List getPlatformMappingsForNative(String nat) {
List flavors = new ArrayList();
public List <DataFlavor> getPlatformMappingsForNative(String nat) {
List <DataFlavor> flavors = new ArrayList();
if (nat == null) {
return flavors;
......@@ -346,16 +345,14 @@ public class XDataTransferer extends DataTransferer {
return flavors;
}
Object value = df;
DataFlavor value = df;
final String primaryType = df.getPrimaryType();
final String baseType = primaryType + "/" + df.getSubType();
// For text formats we map natives to MIME strings instead of data
// flavors to enable dynamic text native-to-flavor mapping generation.
// See SystemFlavorMap.getFlavorsForNative() for details.
if ("text".equals(primaryType)) {
value = primaryType + "/" + df.getSubType();
} else if ("image".equals(primaryType)) {
if ("image".equals(primaryType)) {
Iterator readers = ImageIO.getImageReadersByMIMEType(baseType);
if (readers.hasNext()) {
flavors.add(DataFlavor.imageFlavor);
......@@ -438,16 +435,13 @@ public class XDataTransferer extends DataTransferer {
}
}
} else if (DataTransferer.isFlavorCharsetTextType(df)) {
final Iterator iter = DataTransferer.standardEncodings();
// stringFlavor is semantically equivalent to the standard
// "text/plain" MIME type.
if (DataFlavor.stringFlavor.equals(df)) {
baseType = "text/plain";
}
while (iter.hasNext()) {
String encoding = (String)iter.next();
for (String encoding : DataTransferer.standardEncodings()) {
if (!encoding.equals(charset)) {
natives.add(baseType + ";charset=" + encoding);
}
......
......@@ -191,32 +191,60 @@ public class WDataTransferer extends DataTransferer {
DataFlavor flavor,
long format) throws IOException
{
byte[] bytes = super.translateTransferable(contents, flavor, format);
byte[] bytes = null;
if (format == CF_HTML) {
if (contents.isDataFlavorSupported(DataFlavor.selectionHtmlFlavor)) {
// if a user provides data represented by
// DataFlavor.selectionHtmlFlavor format, we use this
// type to store the data in the native clipboard
bytes = super.translateTransferable(contents,
DataFlavor.selectionHtmlFlavor,
format);
} else if (contents.isDataFlavorSupported(DataFlavor.allHtmlFlavor)) {
// if we cannot get data represented by the
// DataFlavor.selectionHtmlFlavor format
// but the DataFlavor.allHtmlFlavor format is avialable
// we belive that the user knows how to represent
// the data and how to mark up selection in a
// system specific manner. Therefor, we use this data
bytes = super.translateTransferable(contents,
DataFlavor.allHtmlFlavor,
format);
} else {
// handel other html flavor types, including custom and
// fragment ones
bytes = HTMLCodec.convertToHTMLFormat(bytes);
}
} else {
// we handle non-html types basing on their
// flavors
bytes = super.translateTransferable(contents, flavor, format);
}
return bytes;
}
protected Object translateBytesOrStream(InputStream str, byte[] bytes,
// The stream is closed as a closable object
public Object translateStream(InputStream str,
DataFlavor flavor, long format,
Transferable localeTransferable)
throws IOException
{
if (format == CF_HTML && flavor.isFlavorTextType()) {
if (str == null) {
str = new ByteArrayInputStream(bytes);
bytes = null;
str = new HTMLCodec(str,
EHTMLReadMode.getEHTMLReadMode(flavor));
}
return super.translateStream(str, flavor, format,
localeTransferable);
str = new HTMLCodec(str, EHTMLReadMode.HTML_READ_SELECTION);
}
public Object translateBytes(byte[] bytes, DataFlavor flavor, long format,
Transferable localeTransferable) throws IOException
{
if (format == CF_FILEGROUPDESCRIPTORA || format == CF_FILEGROUPDESCRIPTORW) {
if (null != str ) {
str.close();
}
if (bytes == null || !DataFlavor.javaFileListFlavor.equals(flavor)) {
throw new IOException("data translation failed");
}
......@@ -240,26 +268,22 @@ public class WDataTransferer extends DataTransferer {
if (format == CFSTR_INETURL &&
URL.class.equals(flavor.getRepresentationClass()))
{
if (bytes == null) {
bytes = inputStreamToByteArray(str);
str = null;
}
String charset = getDefaultTextCharset();
if (localeTransferable != null && localeTransferable.
isDataFlavorSupported(javaTextEncodingFlavor))
{
try {
charset = new String((byte[])localeTransferable.
getTransferData(javaTextEncodingFlavor),
"UTF-8");
getTransferData(javaTextEncodingFlavor), "UTF-8");
} catch (UnsupportedFlavorException cannotHappen) {
}
}
return new URL(new String(bytes, charset));
}
return super.translateBytesOrStream(str, bytes, flavor, format,
return super.translateBytes(bytes , flavor, format,
localeTransferable);
}
public boolean isLocaleDependentTextFormat(long format) {
......@@ -419,9 +443,7 @@ public class WDataTransferer extends DataTransferer {
* Translates either a byte array or an input stream which contain
* platform-specific image data in the given format into an Image.
*/
protected Image platformImageBytesOrStreamToImage(InputStream str,
byte[] bytes,
long format)
protected Image platformImageBytesToImage(byte[] bytes, long format)
throws IOException {
String mimeType = null;
if (format == CF_PNG) {
......@@ -430,11 +452,7 @@ public class WDataTransferer extends DataTransferer {
mimeType = "image/jpeg";
}
if (mimeType != null) {
return standardImageBytesOrStreamToImage(str, bytes, mimeType);
}
if (bytes == null) {
bytes = inputStreamToByteArray(str);
return standardImageBytesToImage(bytes, mimeType);
}
int[] imageData = platformImageBytesToImageData(bytes, format);
......@@ -492,7 +510,22 @@ final class WToolkitThreadBlockedHandler extends Mutex
enum EHTMLReadMode {
HTML_READ_ALL,
HTML_READ_FRAGMENT,
HTML_READ_SELECTION
HTML_READ_SELECTION;
public static EHTMLReadMode getEHTMLReadMode (DataFlavor df) {
EHTMLReadMode mode = HTML_READ_SELECTION;
String parameter = df.getParameter("document");
if ("all".equals(parameter)) {
mode = HTML_READ_ALL;
} else if ("fragment".equals(parameter)) {
mode = HTML_READ_FRAGMENT;
}
return mode;
}
}
/**
......@@ -581,8 +614,6 @@ class HTMLCodec extends InputStream {
htmlSuffix = "</BODY>" + htmlSuffix;
};
};
htmlPrefix = htmlPrefix + START_FRAGMENT_CMT;
htmlSuffix = END_FRAGMENT_CMT + htmlSuffix;
}
String stBaseUrl = DEF_SOURCE_URL;
......
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
@test
@bug 7075105
@summary WIN: Provide a way to format HTML on drop
@author Denis Fokin: area=datatransfer
@build HtmlTransferable PutAllHtmlFlavorsOnClipboard
@build PutOnlyAllHtmlFlavorOnClipboard PutSelectionAndFragmentHtmlFlavorsOnClipboard
@run main HTMLDataFlavorTest
*/
import java.awt.*;
import java.awt.datatransfer.*;
import java.io.*;
import java.util.HashMap;
public class HTMLDataFlavorTest {
private static HashMap<DataFlavor, String> dataFlavors = new HashMap<DataFlavor, String>();
public static void main(String[] args) throws IOException, UnsupportedFlavorException {
dataFlavors.put(DataFlavor.allHtmlFlavor, HtmlTransferable.ALL_HTML_AS_STRING);
dataFlavors.put(DataFlavor.fragmentHtmlFlavor, HtmlTransferable.FRAGMENT_HTML_AS_STRING);
dataFlavors.put(DataFlavor.selectionHtmlFlavor, HtmlTransferable.SELECTION_HTML_AS_STRING);
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
resetClipboardContent(clipboard);
// 1. Put all three html flavors on clipboard.
// Get the data within the same JVM
// Expect that the resulted html is the selection
// wrapped in all three types
clipboard.setContents(new HtmlTransferable(HtmlTransferable.htmlDataFlavors),null);
// Test local transfer
testClipboardContent(clipboard, HtmlTransferable.htmlDataFlavors);
resetClipboardContent(clipboard);
// 2. Put only DataFlavor.allHtmlFlavor on clipboard.
// Expect that the resulted html is the all
// wrapped in all three types
putHtmlInAnotherProcess("PutOnlyAllHtmlFlavorOnClipboard");
for (DataFlavor df : HtmlTransferable.htmlDataFlavors) {
if (!clipboard.isDataFlavorAvailable(df)) {
throw new RuntimeException("The data should be available.");
}
}
if (!clipboard.getData(DataFlavor.allHtmlFlavor).toString().
equals(dataFlavors.get(DataFlavor.allHtmlFlavor).toString()))
{
throw new RuntimeException("DataFlavor.allHtmlFlavor data " +
"should be identical to the data put on the source side.");
}
resetClipboardContent(clipboard);
// 3. Put all three html flavors on clipboard.
// Expect that the resulted html is the selection
// wrapped in all three types
putHtmlInAnotherProcess("PutAllHtmlFlavorsOnClipboard");
for (DataFlavor df : HtmlTransferable.htmlDataFlavors) {
if (!clipboard.isDataFlavorAvailable(df)) {
throw new RuntimeException("The data should be available.");
}
}
if (!clipboard.getData(DataFlavor.selectionHtmlFlavor).toString().
equals(dataFlavors.get(DataFlavor.selectionHtmlFlavor)))
{
throw new RuntimeException("DataFlavor.allHtmlFlavor data " +
"should be identical to the data put on the source side.");
}
}
private static void resetClipboardContent(Clipboard clipboard) {
clipboard.setContents(
new StringSelection("The data is used to empty the clipboard content"
),null);
}
private static void putHtmlInAnotherProcess(String putterCommand) {
try {
String command = System.getProperty("java.home") + "/bin/java -cp " +
System.getProperty("test.classes", ".") + " " +
putterCommand;
System.out.println("Execute process : " + command);
Process p = Runtime.getRuntime().exec(command);
try {
p.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("The data has been set remotely");
try (BufferedReader stdstr = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
String s;
while ((s = stdstr.readLine()) != null) {
s = stdstr.readLine();
System.out.println(s);
}
}
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()))) {
String s;
while ((s = br.readLine()) != null) {
s = br.readLine();
System.err.println(s);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void testClipboardContent(Clipboard clipboard,
DataFlavor [] expectedDataFlavors)
throws UnsupportedFlavorException, IOException {
for (DataFlavor df : clipboard.getAvailableDataFlavors()) {
System.out.println("available df: " + df.getMimeType());
}
for (DataFlavor df : expectedDataFlavors) {
if (!clipboard.isDataFlavorAvailable(df)) {
throw new RuntimeException("The data should be available.");
}
System.out.println("Checking \"" + df.getParameter("document") + "\" for correspondence");
if (!dataFlavors.get(df).toString().equals(clipboard.getData(df).toString())) {
System.err.println("Expected data: " + dataFlavors.get(df).toString());
System.err.println("Actual data: " + clipboard.getData(df).toString());
throw new RuntimeException("An html flavor with parameter \"" +
df.getParameter("document") + "\" does not correspond to the transferred data.");
}
}
}
}
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
/**
* A transferable that mimic ie html data
*/
class HtmlTransferable implements Transferable {
final static String SOURCE_HTML = "<html><head><title>Simple html content</title></head>" +
"<body><ol><li>Dasha</li><li>Masha</li><li>Lida</li></ol></body></html>";
// Data identical to ie output for the next html without end of lines,
// that is gotten by java system clipboard
// <html>
// <head>
// <title>Simple html content</title>
// </head>
// <body>
// <ol>
// <li>Dasha</li>
// <li>Masha</li>
// <li>Lida</li>
// </ol>
// </body>
// </html>
final static String ALL_HTML_AS_STRING = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n" +
"\n" +
"<HTML><HEAD><TITLE>Simple html content</TITLE></HEAD>\n" +
"\n" +
"<BODY>\n" +
"\n" +
"<OL><!--StartFragment--><LI>Masha\n" +
"<LI>Lida</LI><!--EndFragment--></OL>\n" +
"</BODY>\n" +
"</HTML>";
final static String FRAGMENT_HTML_AS_STRING = "<LI>Masha\n" +
"<LI>Lida</LI>";
final static String SELECTION_HTML_AS_STRING = "<LI>Masha" +
"<LI>Lida</LI>";
private DataFlavor[] supportedDataFlavors;
final static DataFlavor[] htmlDataFlavors = new DataFlavor [] {
DataFlavor.allHtmlFlavor,
DataFlavor.fragmentHtmlFlavor,
DataFlavor.selectionHtmlFlavor
};
@Override
public DataFlavor[] getTransferDataFlavors() {
return supportedDataFlavors;
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
for (DataFlavor supportedDataFlavor : supportedDataFlavors) {
if (supportedDataFlavor.equals(flavor)) {
return true;
}
}
return false;
}
HtmlTransferable(DataFlavor[] supportedDataFlavors) {
this.supportedDataFlavors = supportedDataFlavors;
}
@Override
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException, IOException {
if (isDataFlavorSupported(flavor)) {
if (flavor.equals(DataFlavor.allHtmlFlavor)) {
return ALL_HTML_AS_STRING;
} else if (flavor.equals(DataFlavor.fragmentHtmlFlavor)) {
return FRAGMENT_HTML_AS_STRING;
} else if (flavor.equals(DataFlavor.selectionHtmlFlavor)) {
return SELECTION_HTML_AS_STRING;
}
}
throw new UnsupportedFlavorException(flavor);
}
}
<html>
<!--
@test
@bug 7075105
@summary WIN: Provide a way to format HTML on drop
@author Denis Fokin area=datatransfer
@run applet/manual=yesno ManualHTMLDataFlavorTest.html
-->
<head>
<title>ManualHTMLDataFlavorTest</title>
</head>
<body>
<h1>ManualHTMLDataFlavorTest<br>Bug ID: 7075105</h1>
<p> See the dialog box (usually in upper left corner) for instructions</p>
<APPLET CODE="ManualHTMLDataFlavorTest.class" WIDTH=200 HEIGHT=200></APPLET>
</body>
</html>
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
test
@bug 7075105
@summary WIN: Provide a way to format HTML on drop
@author Denis Fokin: area=datatransfer
@run applet/manual=yesno ManualHTMLDataFlavorTest
*/
import java.applet.Applet;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.*;
import java.io.IOException;
public class ManualHTMLDataFlavorTest extends Applet {
class DropPane extends Panel implements DropTargetListener {
DropPane() {
requestFocus();
setBackground(Color.red);
setDropTarget(new DropTarget(this, DnDConstants.ACTION_COPY, this));
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200,200);
}
@Override
public void dragEnter(DropTargetDragEvent dtde) {
dtde.acceptDrag(DnDConstants.ACTION_COPY);
}
@Override
public void dragOver(DropTargetDragEvent dtde) {
dtde.acceptDrag(DnDConstants.ACTION_COPY);
}
@Override
public void dropActionChanged(DropTargetDragEvent dtde) {
dtde.acceptDrag(DnDConstants.ACTION_COPY);
}
@Override
public void dragExit(DropTargetEvent dte) {}
@Override
public void drop(DropTargetDropEvent dtde) {
if (!dtde.isDataFlavorSupported(DataFlavor.allHtmlFlavor)) {
Sysout.println("DataFlavor.allHtmlFlavor is not present in the system clipboard");
dtde.rejectDrop();
return;
} else if (!dtde.isDataFlavorSupported(DataFlavor.fragmentHtmlFlavor)) {
Sysout.println("DataFlavor.fragmentHtmlFlavor is not present in the system clipboard");
dtde.rejectDrop();
return;
} else if (!dtde.isDataFlavorSupported(DataFlavor.selectionHtmlFlavor)) {
Sysout.println("DataFlavor.selectionHtmlFlavor is not present in the system clipboard");
dtde.rejectDrop();
return;
}
dtde.acceptDrop(DnDConstants.ACTION_COPY);
Transferable t = dtde.getTransferable();
try {
Sysout.println("ALL:");
Sysout.println(t.getTransferData(DataFlavor.allHtmlFlavor).toString());
Sysout.println("FRAGMENT:");
Sysout.println(t.getTransferData(DataFlavor.fragmentHtmlFlavor).toString());
Sysout.println("SELECTION:");
Sysout.println(t.getTransferData(DataFlavor.selectionHtmlFlavor).toString());
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void init() {
String[] instructions =
{
"1) The test contains a drop-aware panel with a red background",
"2) Open some page in a browser, select some text",
" Drag and drop it on the red panel",
" IMPORTANT NOTE: the page should be stored locally.",
" otherwise for instance iexplore can prohibit drag and drop from",
" the browser to other applications because of",
" the protected mode restrictions.",
"3) Check the data in the output area of this dialog",
"5) The output should not contain information that any of",
" flavors is not present in the system clipboard",
"6) The output should contain data in three different formats",
" provided by the system clipboard",
" - Data after the \"ALL:\" marker should include the data",
" from the the \"SELECTION:\" marker",
" - Data after the \"FRAGMENT\" marker should include the data",
" from the \"SELECTION:\" marker and may be some closing",
" tags could be added to the mark-up",
" - Data after the \"SELECTION:\" marker should correspond",
" to the data selected in the browser",
"7) If the above requirements are met, the test is passed"
};
add(new DropPane());
Sysout.createDialogWithInstructions( instructions );
new ManualHTMLDataFlavorTest();
}
public void start ()
{
setSize (200,200);
setVisible(true);
validate();
}// start()
}
/* Place other classes related to the test after this line */
/****************************************************
Standard Test Machinery
DO NOT modify anything below -- it's a standard
chunk of code whose purpose is to make user
interaction uniform, and thereby make it simpler
to read and understand someone else's test.
****************************************************/
/**
This is part of the standard test machinery.
It creates a dialog (with the instructions), and is the interface
for sending text messages to the user.
To print the instructions, send an array of strings to Sysout.createDialog
WithInstructions method. Put one line of instructions per array entry.
To display a message for the tester to see, simply call Sysout.println
with the string to be displayed.
This mimics System.out.println but works within the test harness as well
as standalone.
*/
class Sysout
{
private static TestDialog dialog;
public static void createDialogWithInstructions( String[] instructions )
{
dialog = new TestDialog( new Frame(), "Instructions" );
dialog.printInstructions( instructions );
dialog.setVisible(true);
println( "Any messages for the tester will display here." );
}
public static void createDialog( )
{
dialog = new TestDialog( new Frame(), "Instructions" );
String[] defInstr = { "Instructions will appear here. ", "" } ;
dialog.printInstructions( defInstr );
dialog.setVisible(true);
println( "Any messages for the tester will display here." );
}
public static void printInstructions( String[] instructions )
{
dialog.printInstructions( instructions );
}
public static void println( String messageIn )
{
dialog.displayMessage( messageIn );
}
}// Sysout class
/**
This is part of the standard test machinery. It provides a place for the
test instructions to be displayed, and a place for interactive messages
to the user to be displayed.
To have the test instructions displayed, see Sysout.
To have a message to the user be displayed, see Sysout.
Do not call anything in this dialog directly.
*/
class TestDialog extends Dialog
{
TextArea instructionsText;
TextArea messageText;
int maxStringLength = 80;
//DO NOT call this directly, go through Sysout
public TestDialog( Frame frame, String name )
{
super( frame, name );
int scrollBoth = TextArea.SCROLLBARS_BOTH;
instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth );
add( "North", instructionsText );
messageText = new TextArea( "", 5, maxStringLength, scrollBoth );
add("Center", messageText);
pack();
setVisible(true);
}// TestDialog()
//DO NOT call this directly, go through Sysout
public void printInstructions( String[] instructions )
{
//Clear out any current instructions
instructionsText.setText( "" );
//Go down array of instruction strings
String printStr, remainingStr;
for( int i=0; i < instructions.length; i++ )
{
//chop up each into pieces maxSringLength long
remainingStr = instructions[ i ];
while( remainingStr.length() > 0 )
{
//if longer than max then chop off first max chars to print
if( remainingStr.length() >= maxStringLength )
{
//Try to chop on a word boundary
int posOfSpace = remainingStr.
lastIndexOf( ' ', maxStringLength - 1 );
if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1;
printStr = remainingStr.substring( 0, posOfSpace + 1 );
remainingStr = remainingStr.substring( posOfSpace + 1 );
}
//else just print
else
{
printStr = remainingStr;
remainingStr = "";
}
instructionsText.append( printStr + "\n" );
}// while
}// for
}//printInstructions()
//DO NOT call this directly, go through Sysout
public void displayMessage( String messageIn )
{
messageText.append( messageIn + "\n" );
System.out.println(messageIn);
}
}// TestDialog class
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.*;
public class PutAllHtmlFlavorsOnClipboard {
public static void main(String[] args) {
System.out.println("PutAllHtmlFlavorsOnClipboard has been started.");
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
new HtmlTransferable(HtmlTransferable.htmlDataFlavors), null);
System.out.println("Data has been put on clipboard in a separate process");
}
}
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
public class PutOnlyAllHtmlFlavorOnClipboard {
public static void main(String[] args) {
System.out.println("PutOnlyAllHtmlFlavorOnClipboard has been started.");
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
new HtmlTransferable(new DataFlavor[]{DataFlavor.allHtmlFlavor}), null);
System.out.println("Data has been put on clipboard in a separate process");
}
}
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
public class PutSelectionAndFragmentHtmlFlavorsOnClipboard {
public static void main(String[] args) {
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
new HtmlTransferable(new DataFlavor[]{DataFlavor.selectionHtmlFlavor,
DataFlavor.fragmentHtmlFlavor}), null);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册