Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2026, 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
Expand Down Expand Up @@ -245,10 +245,11 @@ public void flush() {
systemAssistant.flush();
}

@Override public Object getContent(DataFormat dataFormat) {
@Override
public Object getContent(DataFormat dataFormat) {
if (dataCache != null) {
for (Pair<DataFormat, Object> pair : dataCache) {
if (pair.getKey() == dataFormat) {
if (pair.getKey().equals(dataFormat)) {
return pair.getValue();
}
}
Expand All @@ -258,11 +259,11 @@ public void flush() {
ClipboardAssistance assistant =
(currentDragboard != null) ? currentDragboard : systemAssistant;

if (dataFormat == DataFormat.IMAGE) {
if (DataFormat.IMAGE.equals(dataFormat)) {
return readImage();
} else if (dataFormat == DataFormat.URL) {
} else if (DataFormat.URL.equals(dataFormat)) {
return assistant.getData(Clipboard.URI_TYPE);
} else if (dataFormat == DataFormat.FILES) {
} else if (DataFormat.FILES.equals(dataFormat)) {
Object data = assistant.getData(Clipboard.FILE_LIST_TYPE);
if (data == null) return Collections.emptyList();
String[] paths = (String[]) data;
Expand Down Expand Up @@ -438,10 +439,11 @@ private boolean placeImage(final Image image) {
return set;
}

@Override public boolean hasContent(DataFormat dataFormat) {
@Override
public boolean hasContent(DataFormat dataFormat) {
if (dataCache != null) {
for (Pair<DataFormat, Object> pair : dataCache) {
if (pair.getKey() == dataFormat) {
if (pair.getKey().equals(dataFormat)) {
return true;
}
}
Expand All @@ -456,17 +458,17 @@ private boolean placeImage(final Image image) {
return false;
}
for (String t: stypes) {
if (dataFormat == DataFormat.IMAGE &&
if (DataFormat.IMAGE.equals(dataFormat) &&
t.equalsIgnoreCase(Clipboard.RAW_IMAGE_TYPE)) {
return true;
} else if (dataFormat == DataFormat.URL &&
} else if (DataFormat.URL.equals(dataFormat) &&
t.equalsIgnoreCase(Clipboard.URI_TYPE)) {
return true;
} else if (dataFormat == DataFormat.IMAGE &&
} else if (DataFormat.IMAGE.equals(dataFormat) &&
t.equalsIgnoreCase(Clipboard.HTML_TYPE) &&
parseIMG(assistant.getData(Clipboard.HTML_TYPE)) != null) {
return true;
} else if (dataFormat == DataFormat.FILES &&
} else if (DataFormat.FILES.equals(dataFormat) &&
t.equalsIgnoreCase(Clipboard.FILE_LIST_TYPE)) {
return true;
}
Expand Down Expand Up @@ -528,16 +530,16 @@ private boolean putContentToPeer(Pair<DataFormat, Object>... content) {
// might expect the JPG bits directly, rather than the DIB / TIFF bits.
// So what we do is, any IMAGE type DataFormat that comes in will be stored
// in DIB / TIFF, while specific bits will also be stored (in the future).
if (dataFormat == DataFormat.IMAGE) {
if (DataFormat.IMAGE.equals(dataFormat)) {
dataSet = placeImage(convertObjectToImage(data));
} else if (dataFormat == DataFormat.URL) {
} else if (DataFormat.URL.equals(dataFormat)) {
// TODO Weird, but this is how Glass wants it...
systemAssistant.setData(Clipboard.URI_TYPE, data);
dataSet = true;
} else if (dataFormat == DataFormat.RTF) {
} else if (DataFormat.RTF.equals(dataFormat)) {
systemAssistant.setData(Clipboard.RTF_TYPE, data);
dataSet = true;
} else if (dataFormat == DataFormat.FILES) {
} else if (DataFormat.FILES.equals(dataFormat)) {
// Have to convert from List<File> to String[]
List<File> list = (List<File>)data;
if (list.size() != 0) {
Expand All @@ -551,8 +553,10 @@ private boolean putContentToPeer(Pair<DataFormat, Object>... content) {
}
} else {
if (data instanceof Serializable) {
if ((dataFormat != DataFormat.PLAIN_TEXT && dataFormat != DataFormat.HTML) ||
!(data instanceof String))
if (
(!(DataFormat.PLAIN_TEXT.equals(dataFormat)) && !(DataFormat.HTML.equals(dataFormat))) ||
!(data instanceof String)
)
{
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2026, 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
Expand All @@ -25,13 +25,9 @@

package javafx.scene.input;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import com.sun.javafx.util.WeakReferenceQueue;
import javafx.beans.NamedArg;

/**
Expand All @@ -41,14 +37,9 @@
*/
public class DataFormat {

/**
* A static cache of all DataFormats created and currently in use. This is needed
* by the underlying implementation, such that, given a mime type, we can determine
* the associated DataFormat. The OS level is going to supply us with a mime type
* (or other string based key), and we need to be able to map this back to the FX
* DataFormat.
*/
private static final WeakReferenceQueue<DataFormat> DATA_FORMAT_LIST = new WeakReferenceQueue<>();
// A static registry of DataFormats for the purposes of checking against constructing DataFormats
// that contain mismatched mime types.
private static final HashMap<String,DataFormat> registry = new HashMap<>();

/**
* Represents a plain text string.
Expand Down Expand Up @@ -101,7 +92,7 @@ public class DataFormat {
* A set of identifiers, typically mime types, for this DataFormat.
* In most cases this will be a single String.
*/
private final Set<String> identifier;
private final Set<String> identifiers;

/**
* Create a new DataFormat, specifying the set of ids that are associated with
Expand All @@ -126,49 +117,61 @@ public class DataFormat {
* to drag data of this type from/to {@link javafx.embed.swing.JFXPanel}.
* </p>
* @param ids The set of ids used to represent this DataFormat on the clipboard.
* @throws IllegalArgumentException if one of the given mime types is already
* assigned to another DataFormat.
* @throws IllegalArgumentException if one of the given ids is already
* assigned to another DataFormat with a different set of ids
* @throws NullPointerException if any of the ids is null
*/
public DataFormat(@NamedArg("ids") String... ids) {
DATA_FORMAT_LIST.cleanup();
if (ids != null) {
for (String id : ids) {
if (lookupMimeType(id) != null) {
throw new IllegalArgumentException("DataFormat '" + id +
"' already exists.");
if ((ids == null) || (ids.length == 0)) {
identifiers = Set.of();
return;
}

identifiers = Set.of(ids);
// check for mismatched formats
boolean isNew = true;
synchronized (registry) {
for (String id : identifiers) {
DataFormat f = registry.get(id);
if (f != null) {
if (!identifiers.equals(f.identifiers)) {
throw new IllegalArgumentException("DataFormat '" + id + "' already exists.");
}
isNew = false;
}
}
this.identifier = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(ids)));
} else {
this.identifier = Collections.<String>emptySet();
}

// Add to the statis data format list.
DATA_FORMAT_LIST.add(this);
// add to the registry if new
if (isNew) {
for (String id : ids) {
registry.put(id, this);
}
}
}
}

/**
* Gets the unmodifiable set of identifiers for this DataFormat.
* @return an unmodifiable set that is never null.
*/
public final Set<String> getIdentifiers() {
return identifier;
return identifiers;
}

/**
* Returns a string representation of this {@code DataFormat} object.
* @return a string representation of this {@code DataFormat} object.
*/
@Override public String toString() {
if (identifier.isEmpty()) {
if (identifiers.isEmpty()) {
return "[]";
} else if (identifier.size() == 1) {
} else if (identifiers.size() == 1) {
StringBuilder sb = new StringBuilder("[");
sb.append(identifier.iterator().next());
sb.append(identifiers.iterator().next());
return (sb.append("]").toString());
} else {
StringBuilder b = new StringBuilder("[");
Iterator<String> itr = identifier.iterator();
Iterator<String> itr = identifiers.iterator();
while (itr.hasNext()) {
b = b.append(itr.next());
if (itr.hasNext()) {
Expand All @@ -187,7 +190,7 @@ public final Set<String> getIdentifiers() {
@Override public int hashCode() {
int hash = 7;

for (String id : identifier) {
for (String id : identifiers) {
hash = 31 * hash + id.hashCode();
}

Expand All @@ -199,18 +202,12 @@ public final Set<String> getIdentifiers() {
* @param obj the reference object with which to compare.
* @return {@code true} if this object is equal to the {@code obj} argument; {@code false} otherwise.
*/
@Override public boolean equals(Object obj) {
if (obj == null || ! (obj instanceof DataFormat)) {
return false;
}

DataFormat otherDataFormat = (DataFormat) obj;

if (identifier.equals(otherDataFormat.identifier)) {
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}

return false;
return (obj instanceof DataFormat f) && identifiers.equals(f.identifiers);
}

/**
Expand All @@ -224,13 +221,8 @@ public static DataFormat lookupMimeType(String mimeType) {
return null;
}

Iterator itr = DATA_FORMAT_LIST.iterator();
while (itr.hasNext()) {
DataFormat dataFormat = (DataFormat) itr.next();
if (dataFormat.getIdentifiers().contains(mimeType)) {
return dataFormat;
}
synchronized (registry) {
return registry.get(mimeType);
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2026, 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
Expand All @@ -25,18 +25,18 @@

package test.javafx.scene.input;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.stream.Stream;
import javafx.scene.input.DataFormat;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class DataFormatTest {

Expand Down Expand Up @@ -69,9 +69,9 @@ public void testMimeTypes(DataFormat format, String mime1, String mime2) {
@ParameterizedTest
@MethodSource("getParams")
public void dataFormatsShouldBeFound(DataFormat format, String mime1, String mime2) {
assertSame(format, DataFormat.lookupMimeType(mime1));
assertEquals(format, DataFormat.lookupMimeType(mime1));
if (mime2 != null) {
assertSame(format, DataFormat.lookupMimeType(mime2));
assertEquals(format, DataFormat.lookupMimeType(mime2));
}
}

Expand All @@ -84,14 +84,30 @@ public void testToString(DataFormat format, String mime1, String mime2) {

@ParameterizedTest
@MethodSource("getParams")
public void shouldNotBePossibleToReuseMimeTypes(DataFormat format, String mime1, String mime2) {
public void shouldBePossibleToReuseEquivalentMimeTypes(DataFormat f, String mime1, String mime2) {
DataFormat f1 = new DataFormat(f.getIdentifiers().toArray(String[]::new));
assertEquals(f, f1);
DataFormat f2 = new DataFormat(f.getIdentifiers().toArray(String[]::new));
assertEquals(f, f2);
assertEquals(f1, f2);
}

@Test
public void shouldNotBePossibleToRegisterMismatchedFormats() {
// using DataFormat.FILES
assertThrows(IllegalArgumentException.class, () -> {
new DataFormat("application/x-java-file-list");
});
assertThrows(IllegalArgumentException.class, () -> {
DataFormat customEqual = new DataFormat(format.getIdentifiers().toArray(
new String[format.getIdentifiers().size()]));
new DataFormat("java.file-list");
});
// using custom
DataFormat f1 = new DataFormat("test/foo", "test/bar");
assertThrows(IllegalArgumentException.class, () -> {
new DataFormat("test/foo");
});
}


@ParameterizedTest
@MethodSource("getParams")
public void testEqualsAndHashCode(DataFormat format, String mime1, String mime2) {
Expand All @@ -101,4 +117,20 @@ public void testEqualsAndHashCode(DataFormat format, String mime1, String mime2)
assertFalse(uniqueFormat.equals(format));
assertFalse(uniqueFormat.hashCode() == format.hashCode());
}

@Test
public void noMoreNullMimeTypes() {
String mime = null;
assertThrows(NullPointerException.class, () -> {
new DataFormat(mime);
});
Comment on lines +124 to +126

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
assertThrows(NullPointerException.class, () -> {
String mime = null;
new DataFormat(mime);
});
String mime = null;
assertThrows(NullPointerException.class, () -> {
new DataFormat(mime);
});

Recommendation is to always have one statement in the assertThrows / assertDoesNotThrows

}

@Test
public void nullArrayIsAllowedForCompatibilityReasons() {
String[] mimes = null;
assertDoesNotThrow(() -> {
new DataFormat(mimes);
});
}
}