OpenJDK / amber / amber
changeset 29014:d42eb758b048
Merge
author | ddehaven |
---|---|
date | Tue, 17 Feb 2015 11:44:51 -0800 |
parents | 71fe221460f5 6b20c10ac851 |
children | 82642b0f0945 550dfa936f27 |
files | jdk/make/src/classes/build/tools/module/boot.modules jdk/src/java.desktop/macosx/classes/sun/datatransfer/resources/flavormap.properties jdk/src/java.desktop/share/classes/java/awt/datatransfer/Clipboard.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/ClipboardOwner.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/DataFlavor.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/FlavorEvent.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/FlavorListener.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/FlavorMap.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/FlavorTable.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/MimeType.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/MimeTypeParameterList.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/MimeTypeParseException.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/StringSelection.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/SystemFlavorMap.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/Transferable.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/UnsupportedFlavorException.java jdk/src/java.desktop/share/classes/java/awt/datatransfer/package.html jdk/src/java.desktop/share/classes/sun/datatransfer/DataFlavorUtil.java jdk/src/java.desktop/share/classes/sun/datatransfer/DesktopDatatransferService.java jdk/src/java.desktop/unix/classes/sun/awt/X11/XAWTFormatter.java jdk/src/java.desktop/unix/classes/sun/datatransfer/resources/flavormap.properties jdk/src/java.desktop/windows/classes/sun/datatransfer/resources/flavormap.properties jdk/test/java/awt/color/LoadProfileWithSM.java jdk/test/java/awt/color/LoadStandardProfilesTest.java |
diffstat | 103 files changed, 8404 insertions(+), 6175 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/make/copy/Copy-java.base.gmk Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/make/copy/Copy-java.base.gmk Tue Feb 17 11:44:51 2015 -0800 @@ -60,16 +60,28 @@ endif ################################################################################ -# Copy msvcrXX.dll on windows +# Copy the microsoft runtime libraries on windows +ifeq ($(OPENJDK_TARGET_OS), windows) -ifeq ($(OPENJDK_TARGET_OS), windows) - MSVCR_TARGET := $(LIB_DST_DIR)/$(notdir $(MSVCR_DLL)) # Chmod to avoid permission issues if bundles are unpacked on unix platforms. - $(MSVCR_TARGET): $(MSVCR_DLL) - $(call install-file) + define copy-and-chmod + $(install-file) $(CHMOD) a+rx $@ + endef - TARGETS += $(MSVCR_TARGET) + # Use separate macro calls in case the source files are not in the same + # directory. + $(eval $(call SetupCopyFiles,COPY_MSVCR, \ + DEST := $(LIB_DST_DIR), \ + FILES := $(MSVCR_DLL), \ + MACRO := copy-and-chmod)) + + $(eval $(call SetupCopyFiles,COPY_MSVCP, \ + DEST := $(LIB_DST_DIR), \ + FILES := $(MSVCP_DLL), \ + MACRO := copy-and-chmod)) + + TARGETS += $(COPY_MSVCR) $(COPY_MSVCP) endif ################################################################################
--- a/jdk/make/lib/Awt2dLibraries.gmk Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/make/lib/Awt2dLibraries.gmk Tue Feb 17 11:44:51 2015 -0800 @@ -515,6 +515,77 @@ ################################################################################ +ifeq ($(BUILD_HEADLESS), true) + # Mac and Windows only use the native AWT lib, do not build libawt_headless + ifeq ($(findstring $(OPENJDK_TARGET_OS), windows macosx),) + + LIBAWT_HEADLESS_DIRS := $(JDK_TOPDIR)/src/java.desktop/unix/native/libawt_headless/awt \ + $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/awt \ + $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/opengl \ + $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/x11 \ + $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d/opengl \ + $(JDK_TOPDIR)/src/java.desktop/share/native/common/font \ + # + + LIBAWT_HEADLESS_EXCLUDES := medialib + LIBAWT_HEADLESS_CFLAGS := -I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \ + $(addprefix -I, $(LIBAWT_HEADLESS_DIRS)) \ + -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d \ + -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d/loops \ + -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image/cvutils \ + -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d/pipe \ + -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image \ + -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libawt/java2d \ + -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/font \ + -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/debug \ + -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/font \ + -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libsunwjdga/ \ + $(LIBJAVA_HEADER_FLAGS) \ + # + + LIBAWT_HEADLESS_REORDER := + ifeq ($(OPENJDK_TARGET_OS), solaris) + ifneq ($(OPENJDK_TARGET_CPU), x86_64) + LIBAWT_HEADLESS_REORDER := $(JDK_TOPDIR)/make/mapfiles/libawt_headless/reorder-$(OPENJDK_TARGET_CPU) + endif + endif + + $(eval $(call SetupNativeCompilation,BUILD_LIBAWT_HEADLESS, \ + LIBRARY := awt_headless, \ + OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ + SRC := $(LIBAWT_HEADLESS_DIRS), \ + EXCLUDES := $(LIBAWT_HEADLESS_EXCLUDES), \ + LANG := C, \ + OPTIMIZATION := LOW, \ + CFLAGS := $(CFLAGS_JDKLIB) \ + -DHEADLESS=true \ + -DPACKAGE_PATH=\"$(PACKAGE_PATH)\" \ + $(CUPS_CFLAGS) \ + $(X_CFLAGS) \ + $(LIBAWT_HEADLESS_CFLAGS), \ + MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libawt_headless/mapfile-vers, \ + LDFLAGS := $(LDFLAGS_JDKLIB) \ + $(call SET_SHARED_LIBRARY_ORIGIN), \ + LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \ + LDFLAGS_linux := $(call SET_SHARED_LIBRARY_ORIGIN,/..), \ + LDFLAGS_solaris := $(call SET_SHARED_LIBRARY_ORIGIN,/..), \ + LDFLAGS_macosx := $(call SET_SHARED_LIBRARY_ORIGIN)., \ + REORDER := $(LIBAWT_HEADLESS_REORDER), \ + LDFLAGS_SUFFIX_linux := -ljvm -lawt -lm $(LIBDL) -ljava, \ + LDFLAGS_SUFFIX_aix := -ljvm -lawt -ljava,\ + LDFLAGS_SUFFIX_solaris := $(LIBDL) -ljvm -lawt -lm -ljava $(LIBCXX) -lc, \ + OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libawt_headless, \ + DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES))) + + $(BUILD_LIBAWT_HEADLESS): $(BUILD_LIBAWT) + + TARGETS += $(BUILD_LIBAWT_HEADLESS) + + endif +endif + +################################################################################ + LIBFONTMANAGER_SRC := $(JDK_TOPDIR)/src/java.desktop/share/native/libfontmanager \ $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libfontmanager LIBFONTMANAGER_CFLAGS := \ @@ -562,10 +633,6 @@ BUILD_LIBFONTMANAGER_ExtensionSubtables.cpp_CXXFLAGS := -fno-strict-aliasing endif -# Libfontmanager doesn't actually need X_LIBS to link, but if building -# on a Solaris machine without X installed, using a devkit, linking -# to libawt_xawt will fail without the -L parameters from X_LIBS. Filter -# out the -R parameters since they aren't needed. $(eval $(call SetupNativeCompilation,BUILD_LIBFONTMANAGER, \ LIBRARY := fontmanager, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ @@ -583,9 +650,8 @@ LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \ LDFLAGS_SUFFIX := $(BUILD_LIBFONTMANAGER_FONTLIB), \ LDFLAGS_SUFFIX_linux := -lawt $(LIBM) $(LIBCXX) -ljava -ljvm -lc, \ - LDFLAGS_SUFFIX_solaris := $(filter-out -R%, $(X_LIBS)) \ - -lawt -lawt_xawt -lc $(LIBM) $(LIBCXX) -ljava -ljvm, \ - LDFLAGS_SUFFIX_aix := -lawt -lawt_xawt $(LIBM) $(LIBCXX) -ljava -ljvm,\ + LDFLAGS_SUFFIX_solaris := -lawt -lawt_headless -lc $(LIBM) $(LIBCXX) -ljava -ljvm, \ + LDFLAGS_SUFFIX_aix := -lawt -lawt_headless $(LIBM) $(LIBCXX) -ljava -ljvm,\ LDFLAGS_SUFFIX_macosx := -lawt $(LIBM) $(LIBCXX) -undefined dynamic_lookup \ -ljava -ljvm, \ LDFLAGS_SUFFIX_windows := $(WIN_JAVA_LIB) advapi32.lib user32.lib gdi32.lib \ @@ -601,7 +667,7 @@ $(BUILD_LIBFONTMANAGER): $(BUILD_LIBAWT) ifneq (, $(findstring $(OPENJDK_TARGET_OS), solaris aix)) - $(BUILD_LIBFONTMANAGER): $(BUILD_LIBAWT_XAWT) + $(BUILD_LIBFONTMANAGER): $(BUILD_LIBAWT_HEADLESS) endif TARGETS += $(BUILD_LIBFONTMANAGER) @@ -723,77 +789,6 @@ ################################################################################ -ifeq ($(BUILD_HEADLESS), true) - # Mac and Windows only use the native AWT lib, do not build libawt_headless - ifeq ($(findstring $(OPENJDK_TARGET_OS), windows macosx),) - - LIBAWT_HEADLESS_DIRS := $(JDK_TOPDIR)/src/java.desktop/unix/native/libawt_headless/awt \ - $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/awt \ - $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/opengl \ - $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/x11 \ - $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d/opengl \ - $(JDK_TOPDIR)/src/java.desktop/share/native/common/font \ - # - - LIBAWT_HEADLESS_EXCLUDES := medialib - LIBAWT_HEADLESS_CFLAGS := -I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \ - $(addprefix -I, $(LIBAWT_HEADLESS_DIRS)) \ - -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d \ - -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d/loops \ - -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image/cvutils \ - -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d/pipe \ - -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image \ - -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libawt/java2d \ - -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/font \ - -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/debug \ - -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/font \ - -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libsunwjdga/ \ - $(LIBJAVA_HEADER_FLAGS) \ - # - - LIBAWT_HEADLESS_REORDER := - ifeq ($(OPENJDK_TARGET_OS), solaris) - ifneq ($(OPENJDK_TARGET_CPU), x86_64) - LIBAWT_HEADLESS_REORDER := $(JDK_TOPDIR)/make/mapfiles/libawt_headless/reorder-$(OPENJDK_TARGET_CPU) - endif - endif - - $(eval $(call SetupNativeCompilation,BUILD_LIBAWT_HEADLESS, \ - LIBRARY := awt_headless, \ - OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ - SRC := $(LIBAWT_HEADLESS_DIRS), \ - EXCLUDES := $(LIBAWT_HEADLESS_EXCLUDES), \ - LANG := C, \ - OPTIMIZATION := LOW, \ - CFLAGS := $(CFLAGS_JDKLIB) \ - -DHEADLESS=true \ - -DPACKAGE_PATH=\"$(PACKAGE_PATH)\" \ - $(CUPS_CFLAGS) \ - $(X_CFLAGS) \ - $(LIBAWT_HEADLESS_CFLAGS), \ - MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libawt_headless/mapfile-vers, \ - LDFLAGS := $(LDFLAGS_JDKLIB) \ - $(call SET_SHARED_LIBRARY_ORIGIN), \ - LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \ - LDFLAGS_linux := $(call SET_SHARED_LIBRARY_ORIGIN,/..), \ - LDFLAGS_solaris := $(call SET_SHARED_LIBRARY_ORIGIN,/..), \ - LDFLAGS_macosx := $(call SET_SHARED_LIBRARY_ORIGIN)., \ - REORDER := $(LIBAWT_HEADLESS_REORDER), \ - LDFLAGS_SUFFIX_linux := -ljvm -lawt -lm $(LIBDL) -ljava, \ - LDFLAGS_SUFFIX_aix := -ljvm -lawt -ljava,\ - LDFLAGS_SUFFIX_solaris := $(LIBDL) -ljvm -lawt -lm -ljava $(LIBCXX) -lc, \ - OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libawt_headless, \ - DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES))) - - $(BUILD_LIBAWT_HEADLESS): $(BUILD_LIBAWT) - - TARGETS += $(BUILD_LIBAWT_HEADLESS) - - endif -endif - -################################################################################ - ifndef BUILD_HEADLESS_ONLY LIBSPLASHSCREEN_DIRS := \
--- a/jdk/make/lib/CoreLibraries.gmk Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/make/lib/CoreLibraries.gmk Tue Feb 17 11:44:51 2015 -0800 @@ -271,6 +271,11 @@ # Staticically link with c runtime on windows. LIBJLI_CFLAGS := $(filter-out -MD, $(LIBJLI_CFLAGS)) LIBJLI_OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE) + # Supply the name of the C runtime lib. + LIBJLI_CFLAGS += -DMSVCR_DLL_NAME='"$(notdir $(MSVCR_DLL))"' + ifneq ($(MSVCP_DLL), ) + LIBJLI_CFLAGS += -DMSVCP_DLL_NAME='"$(notdir $(MSVCP_DLL))"' + endif else LIBJLI_OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE)/jli endif
--- a/jdk/make/src/classes/build/tools/module/boot.modules Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/make/src/classes/build/tools/module/boot.modules Tue Feb 17 11:44:51 2015 -0800 @@ -1,5 +1,6 @@ java.base java.compiler +java.datatransfer java.desktop java.instrument java.logging
--- a/jdk/src/java.base/windows/native/libjli/java_md.c Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.base/windows/native/libjli/java_md.c Tue Feb 17 11:44:51 2015 -0800 @@ -265,26 +265,17 @@ * assumed to be present in the "JRE path" directory. If it is not found * there (or "JRE path" fails to resolve), skip the explicit load and let * nature take its course, which is likely to be a failure to execute. - * This is clearly completely specific to the exact compiler version - * which isn't very nice, but its hardly the only place. - * No attempt to look for compiler versions in between 2003 and 2010 - * as we aren't supporting building with those. + * The makefiles will provide the correct lib contained in quotes in the + * macro MSVCR_DLL_NAME. */ -#ifdef _MSC_VER -#if _MSC_VER < 1400 -#define CRT_DLL "msvcr71.dll" -#endif -#if _MSC_VER >= 1600 -#define CRT_DLL "msvcr100.dll" -#endif -#ifdef CRT_DLL +#ifdef MSVCR_DLL_NAME if (GetJREPath(crtpath, MAXPATHLEN)) { if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") + - JLI_StrLen(CRT_DLL) >= MAXPATHLEN) { + JLI_StrLen(MSVCR_DLL_NAME) >= MAXPATHLEN) { JLI_ReportErrorMessage(JRE_ERROR11); return JNI_FALSE; } - (void)JLI_StrCat(crtpath, "\\bin\\" CRT_DLL); /* Add crt dll */ + (void)JLI_StrCat(crtpath, "\\bin\\" MSVCR_DLL_NAME); /* Add crt dll */ JLI_TraceLauncher("CRT path is %s\n", crtpath); if (_access(crtpath, 0) == 0) { if (LoadLibrary(crtpath) == 0) { @@ -293,8 +284,24 @@ } } } -#endif /* CRT_DLL */ -#endif /* _MSC_VER */ +#endif /* MSVCR_DLL_NAME */ +#ifdef MSVCP_DLL_NAME + if (GetJREPath(crtpath, MAXPATHLEN)) { + if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") + + JLI_StrLen(MSVCP_DLL_NAME) >= MAXPATHLEN) { + JLI_ReportErrorMessage(JRE_ERROR11); + return JNI_FALSE; + } + (void)JLI_StrCat(crtpath, "\\bin\\" MSVCP_DLL_NAME); /* Add prt dll */ + JLI_TraceLauncher("PRT path is %s\n", crtpath); + if (_access(crtpath, 0) == 0) { + if (LoadLibrary(crtpath) == 0) { + JLI_ReportErrorMessage(DLL_ERROR4, crtpath); + return JNI_FALSE; + } + } + } +#endif /* MSVCP_DLL_NAME */ loaded = 1; } return JNI_TRUE;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/macosx/classes/sun/datatransfer/resources/flavormap.properties Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,76 @@ +# +# This properties file is used to initialize the default +# java.awt.datatransfer.SystemFlavorMap. It contains the Mac OS X platform-specific, +# default mappings between common Mac OS X selection atoms and platform-independent +# MIME type strings, which will be converted into +# java.awt.datatransfer.DataFlavors. +# +# The standard format is: +# +# <native>=<MIME type>,<MIME type>, ... +# +# <native> should be a string identifier that the native platform will +# recognize as a valid data format. <MIME type> should specify both a MIME +# primary type and a MIME subtype separated by a '/'. The MIME type may include +# parameters, where each parameter is a key/value pair separated by '=', and +# where each parameter to the MIME type is separated by a ';'. +# +# Because SystemFlavorMap implements FlavorTable, developers are free to +# duplicate DataFlavor values and set multiple values for a single native by +# separating them with ",". If a mapping contains a duplicate key or value, +# earlier mappings which included this key or value will be preferred. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", and which support the charset parameter, should specify the exact +# format in which the native platform expects the data. The "charset" +# parameter specifies the char to byte encoding, the "eoln" parameter +# specifies the end-of-line marker, and the "terminators" parameter specifies +# the number of terminating NUL bytes. Note that "eoln" and "terminators" +# are not standardized MIME type parameters. They are specific to this file +# format ONLY. They will not appear in any of the DataFlavors returned by the +# SystemFlavorMap at the Java level. +# +# If the "charset" parameter is omitted, or has zero length, the platform +# default encoding is assumed. If the "eoln" parameter is omitted, or has +# zero length, "\n" is assumed. If the "terminators" parameter is omitted, +# or has a value less than zero, zero is assumed. +# +# Upon initialization, the data transfer subsystem will record the specified +# details of the native text format, but the default SystemFlavorMap will +# present a large set of synthesized DataFlavors which map, in both +# directions, to the native. After receiving data from the application in one +# of the synthetic DataFlavors, the data transfer subsystem will transform +# the data stream into the format specified in this file before passing the +# transformed stream to the native system. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", but which do not support the charset parameter, will be treated as +# opaque, 8-bit data. They will not undergo any transformation process, and +# any "charset", "eoln", or "terminators" parameters specified in this file +# will be ignored. +# +# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of +# text flavors which support the charset parameter. + +UTF8_STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 + +# The COMPOUND_TEXT support for inter-client text transfer is disabled by +# default. The reason is that many native applications prefer this format over +# other native text formats, but are unable to decode the textual data in this +# format properly. This results in java-to-native text transfer failures. +# To enable the COMPOUND_TEXT support for this JRE installation uncomment +# the line below. + +# COMPOUND_TEXT=text/plain;charset=x-compound-text;eoln="\n";terminators=0 + +TEXT=text/plain;eoln="\n";terminators=0 +STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 +FILE_NAME=application/x-java-file-list;class=java.util.List +text/uri-list=application/x-java-file-list;class=java.util.List +PNG=image/x-java-image;class=java.awt.Image +JFIF=image/x-java-image;class=java.awt.Image +TIFF=image/x-java-image;class=java.awt.Image +RICH_TEXT=text/rtf +HTML=text/html;charset=utf-8;eoln="\r\n";terminators=1 +URL=application/x-java-url;class=java.net.URL,\ + text/uri-list;eoln="\r\n";terminators=1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/Clipboard.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,352 @@ +/* + * Copyright (c) 1996, 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.awt.datatransfer; + +import sun.datatransfer.DataFlavorUtil; + +import java.util.Objects; +import java.util.Set; +import java.util.HashSet; +import java.util.Arrays; + +import java.io.IOException; + +/** + * A class that implements a mechanism to transfer data using + * cut/copy/paste operations. + * <p> + * {@link FlavorListener}s may be registered on an instance of the + * Clipboard class to be notified about changes to the set of + * {@link DataFlavor}s available on this clipboard (see + * {@link #addFlavorListener}). + * + * @see java.awt.Toolkit#getSystemClipboard + * @see java.awt.Toolkit#getSystemSelection + * + * @author Amy Fowler + * @author Alexander Gerasimov + */ +public class Clipboard { + + String name; + + /** + * The owner of the clipboard. + */ + protected ClipboardOwner owner; + /** + * Contents of the clipboard. + */ + protected Transferable contents; + + /** + * An aggregate of flavor listeners registered on this local clipboard. + * + * @since 1.5 + */ + private Set<FlavorListener> flavorListeners; + + /** + * A set of <code>DataFlavor</code>s that is available on + * this local clipboard. It is used for tracking changes + * of <code>DataFlavor</code>s available on this clipboard. + * + * @since 1.5 + */ + private Set<DataFlavor> currentDataFlavors; + + /** + * Creates a clipboard object. + * @param name for the clipboard + * @see java.awt.Toolkit#getSystemClipboard + */ + public Clipboard(String name) { + this.name = name; + } + + /** + * Returns the name of this clipboard object. + * @return the name of this clipboard object + * + * @see java.awt.Toolkit#getSystemClipboard + */ + public String getName() { + return name; + } + + /** + * Sets the current contents of the clipboard to the specified + * transferable object and registers the specified clipboard owner + * as the owner of the new contents. + * <p> + * If there is an existing owner different from the argument + * <code>owner</code>, that owner is notified that it no longer + * holds ownership of the clipboard contents via an invocation + * of <code>ClipboardOwner.lostOwnership()</code> on that owner. + * An implementation of <code>setContents()</code> is free not + * to invoke <code>lostOwnership()</code> directly from this method. + * For example, <code>lostOwnership()</code> may be invoked later on + * a different thread. The same applies to <code>FlavorListener</code>s + * registered on this clipboard. + * <p> + * The method throws <code>IllegalStateException</code> if the clipboard + * is currently unavailable. For example, on some platforms, the system + * clipboard is unavailable while it is accessed by another application. + * + * @param contents the transferable object representing the + * clipboard content + * @param owner the object which owns the clipboard content + * @throws IllegalStateException if the clipboard is currently unavailable + * @see java.awt.Toolkit#getSystemClipboard + */ + public synchronized void setContents(Transferable contents, ClipboardOwner owner) { + final ClipboardOwner oldOwner = this.owner; + final Transferable oldContents = this.contents; + + this.owner = owner; + this.contents = contents; + + if (oldOwner != null && oldOwner != owner) { + DataFlavorUtil.getDesktopService().invokeOnEventThread(() -> + oldOwner.lostOwnership(Clipboard.this, oldContents)); + } + fireFlavorsChanged(); + } + + /** + * Returns a transferable object representing the current contents + * of the clipboard. If the clipboard currently has no contents, + * it returns <code>null</code>. The parameter Object requestor is + * not currently used. The method throws + * <code>IllegalStateException</code> if the clipboard is currently + * unavailable. For example, on some platforms, the system clipboard is + * unavailable while it is accessed by another application. + * + * @param requestor the object requesting the clip data (not used) + * @return the current transferable object on the clipboard + * @throws IllegalStateException if the clipboard is currently unavailable + * @see java.awt.Toolkit#getSystemClipboard + */ + public synchronized Transferable getContents(Object requestor) { + return contents; + } + + + /** + * Returns an array of <code>DataFlavor</code>s in which the current + * contents of this clipboard can be provided. If there are no + * <code>DataFlavor</code>s available, this method returns a zero-length + * array. + * + * @return an array of <code>DataFlavor</code>s in which the current + * contents of this clipboard can be provided + * + * @throws IllegalStateException if this clipboard is currently unavailable + * + * @since 1.5 + */ + public DataFlavor[] getAvailableDataFlavors() { + Transferable cntnts = getContents(null); + if (cntnts == null) { + return new DataFlavor[0]; + } + return cntnts.getTransferDataFlavors(); + } + + /** + * Returns whether or not the current contents of this clipboard can be + * provided in the specified <code>DataFlavor</code>. + * + * @param flavor the requested <code>DataFlavor</code> for the contents + * + * @return <code>true</code> if the current contents of this clipboard + * can be provided in the specified <code>DataFlavor</code>; + * <code>false</code> otherwise + * + * @throws NullPointerException if <code>flavor</code> is <code>null</code> + * @throws IllegalStateException if this clipboard is currently unavailable + * + * @since 1.5 + */ + public boolean isDataFlavorAvailable(DataFlavor flavor) { + if (flavor == null) { + throw new NullPointerException("flavor"); + } + + Transferable cntnts = getContents(null); + if (cntnts == null) { + return false; + } + return cntnts.isDataFlavorSupported(flavor); + } + + /** + * Returns an object representing the current contents of this clipboard + * in the specified <code>DataFlavor</code>. + * The class of the object returned is defined by the representation + * class of <code>flavor</code>. + * + * @param flavor the requested <code>DataFlavor</code> for the contents + * + * @return an object representing the current contents of this clipboard + * in the specified <code>DataFlavor</code> + * + * @throws NullPointerException if <code>flavor</code> is <code>null</code> + * @throws IllegalStateException if this clipboard is currently unavailable + * @throws UnsupportedFlavorException if the requested <code>DataFlavor</code> + * is not available + * @throws IOException if the data in the requested <code>DataFlavor</code> + * can not be retrieved + * + * @see DataFlavor#getRepresentationClass + * + * @since 1.5 + */ + public Object getData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + if (flavor == null) { + throw new NullPointerException("flavor"); + } + + Transferable cntnts = getContents(null); + if (cntnts == null) { + throw new UnsupportedFlavorException(flavor); + } + return cntnts.getTransferData(flavor); + } + + + /** + * Registers the specified <code>FlavorListener</code> to receive + * <code>FlavorEvent</code>s from this clipboard. + * If <code>listener</code> is <code>null</code>, no exception + * is thrown and no action is performed. + * + * @param listener the listener to be added + * + * @see #removeFlavorListener + * @see #getFlavorListeners + * @see FlavorListener + * @see FlavorEvent + * @since 1.5 + */ + public synchronized void addFlavorListener(FlavorListener listener) { + if (listener == null) { + return; + } + + if (flavorListeners == null) { + flavorListeners = new HashSet<>(); + currentDataFlavors = getAvailableDataFlavorSet(); + } + + flavorListeners.add(listener); + } + + /** + * Removes the specified <code>FlavorListener</code> so that it no longer + * receives <code>FlavorEvent</code>s from this <code>Clipboard</code>. + * This method performs no function, nor does it throw an exception, if + * the listener specified by the argument was not previously added to this + * <code>Clipboard</code>. + * If <code>listener</code> is <code>null</code>, no exception + * is thrown and no action is performed. + * + * @param listener the listener to be removed + * + * @see #addFlavorListener + * @see #getFlavorListeners + * @see FlavorListener + * @see FlavorEvent + * @since 1.5 + */ + public synchronized void removeFlavorListener(FlavorListener listener) { + if (listener == null || flavorListeners == null) { + return; + } + flavorListeners.remove(listener); + } + + /** + * Returns an array of all the <code>FlavorListener</code>s currently + * registered on this <code>Clipboard</code>. + * + * @return all of this clipboard's <code>FlavorListener</code>s or an empty + * array if no listeners are currently registered + * @see #addFlavorListener + * @see #removeFlavorListener + * @see FlavorListener + * @see FlavorEvent + * @since 1.5 + */ + public synchronized FlavorListener[] getFlavorListeners() { + return flavorListeners == null ? new FlavorListener[0] : + flavorListeners.toArray(new FlavorListener[flavorListeners.size()]); + } + + /** + * Checks change of the <code>DataFlavor</code>s and, if necessary, + * notifies all listeners that have registered interest for notification + * on <code>FlavorEvent</code>s. + * + * @since 1.5 + */ + private void fireFlavorsChanged() { + if (flavorListeners == null) { + return; + } + + Set<DataFlavor> prevDataFlavors = currentDataFlavors; + currentDataFlavors = getAvailableDataFlavorSet(); + if (Objects.equals(prevDataFlavors, currentDataFlavors)) { + return; + } + flavorListeners.forEach(listener -> + DataFlavorUtil.getDesktopService().invokeOnEventThread(() -> + listener.flavorsChanged(new FlavorEvent(Clipboard.this)))); + } + + /** + * Returns a set of <code>DataFlavor</code>s currently available + * on this clipboard. + * + * @return a set of <code>DataFlavor</code>s currently available + * on this clipboard + * + * @since 1.5 + */ + private Set<DataFlavor> getAvailableDataFlavorSet() { + Set<DataFlavor> set = new HashSet<>(); + Transferable contents = getContents(null); + if (contents != null) { + DataFlavor[] flavors = contents.getTransferDataFlavors(); + if (flavors != null) { + set.addAll(Arrays.asList(flavors)); + } + } + return set; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/ClipboardOwner.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1996, 2002, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.awt.datatransfer; + +/** + * Defines the interface for classes that will provide data to + * a clipboard. An instance of this interface becomes the owner + * of the contents of a clipboard (clipboard owner) if it is + * passed as an argument to + * {@link java.awt.datatransfer.Clipboard#setContents} method of + * the clipboard and this method returns successfully. + * The instance remains the clipboard owner until another application + * or another object within this application asserts ownership + * of this clipboard. + * + * @see java.awt.datatransfer.Clipboard + * + * @author Amy Fowler + */ + +public interface ClipboardOwner { + + /** + * Notifies this object that it is no longer the clipboard owner. + * This method will be called when another application or another + * object within this application asserts ownership of the clipboard. + * + * @param clipboard the clipboard that is no longer owned + * @param contents the contents which this owner had placed on the clipboard + */ + public void lostOwnership(Clipboard clipboard, Transferable contents); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,1431 @@ +/* + * Copyright (c) 1996, 2015, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.awt.datatransfer; + +import sun.datatransfer.DataFlavorUtil; +import sun.reflect.misc.ReflectUtil; + +import java.io.ByteArrayInputStream; +import java.io.CharArrayReader; +import java.io.Externalizable; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.OptionalDataException; +import java.io.Reader; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.util.Arrays; +import java.util.Collections; +import java.util.Objects; + +/** + * A {@code DataFlavor} provides meta information about data. {@code DataFlavor} + * is typically used to access data on the clipboard, or during + * a drag and drop operation. + * <p> + * An instance of {@code DataFlavor} encapsulates a content type as + * defined in <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a> + * and <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a>. + * A content type is typically referred to as a MIME type. + * <p> + * A content type consists of a media type (referred + * to as the primary type), a subtype, and optional parameters. See + * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a> + * for details on the syntax of a MIME type. + * <p> + * The JRE data transfer implementation interprets the parameter "class" + * of a MIME type as <B>a representation class</b>. + * The representation class reflects the class of the object being + * transferred. In other words, the representation class is the type of + * object returned by {@link Transferable#getTransferData}. + * For example, the MIME type of {@link #imageFlavor} is + * {@code "image/x-java-image;class=java.awt.Image"}, + * the primary type is {@code image}, the subtype is + * {@code x-java-image}, and the representation class is + * {@code java.awt.Image}. When {@code getTransferData} is invoked + * with a {@code DataFlavor} of {@code imageFlavor}, an instance of + * {@code java.awt.Image} is returned. + * It's important to note that {@code DataFlavor} does no error checking + * against the representation class. It is up to consumers of + * {@code DataFlavor}, such as {@code Transferable}, to honor the representation + * class. + * <br> + * Note, if you do not specify a representation class when + * creating a {@code DataFlavor}, the default + * representation class is used. See appropriate documentation for + * {@code DataFlavor}'s constructors. + * <p> + * Also, {@code DataFlavor} instances with the "text" primary + * MIME type may have a "charset" parameter. Refer to + * <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a> and + * {@link #selectBestTextFlavor} for details on "text" MIME types + * and the "charset" parameter. + * <p> + * Equality of {@code DataFlavors} is determined by the primary type, + * subtype, and representation class. Refer to {@link #equals(DataFlavor)} for + * details. When determining equality, any optional parameters are ignored. + * For example, the following produces two {@code DataFlavors} that + * are considered identical: + * <pre> + * DataFlavor flavor1 = new DataFlavor(Object.class, "X-test/test; class=<java.lang.Object>; foo=bar"); + * DataFlavor flavor2 = new DataFlavor(Object.class, "X-test/test; class=<java.lang.Object>; x=y"); + * // The following returns true. + * flavor1.equals(flavor2); + * </pre> + * As mentioned, {@code flavor1} and {@code flavor2} are considered identical. + * As such, asking a {@code Transferable} for either {@code DataFlavor} returns + * the same results. + * <p> + * For more information on using data transfer with Swing see + * the <a href="http://docs.oracle.com/javase/tutorial/uiswing/dnd/index.html"> + * How to Use Drag and Drop and Data Transfer</a>, + * section in <em>Java Tutorial</em>. + * + * @author Blake Sullivan + * @author Laurence P. G. Cable + * @author Jeff Dunn + */ +public class DataFlavor implements Externalizable, Cloneable { + + private static final long serialVersionUID = 8367026044764648243L; + private static final Class<InputStream> ioInputStreamClass = InputStream.class; + + /** + * Tries to load a class from: the bootstrap loader, the system loader, + * the context loader (if one is present) and finally the loader specified. + * + * @param className the name of the class to be loaded + * @param fallback the fallback loader + * @return the class loaded + * @exception ClassNotFoundException if class is not found + */ + protected final static Class<?> tryToLoadClass(String className, + ClassLoader fallback) + throws ClassNotFoundException + { + ReflectUtil.checkPackageAccess(className); + try { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + ClassLoader loader = ClassLoader.getSystemClassLoader(); + try { + // bootstrap class loader and system class loader if present + return Class.forName(className, true, loader); + } + catch (ClassNotFoundException exception) { + // thread context class loader if and only if present + loader = Thread.currentThread().getContextClassLoader(); + if (loader != null) { + try { + return Class.forName(className, true, loader); + } + catch (ClassNotFoundException e) { + // fallback to user's class loader + } + } + } + } catch (SecurityException exception) { + // ignore secured class loaders + } + return Class.forName(className, true, fallback); + } + + /* + * private initializer + */ + static private DataFlavor createConstant(Class<?> rc, String prn) { + try { + return new DataFlavor(rc, prn); + } catch (Exception e) { + return null; + } + } + + /* + * private initializer + */ + static private DataFlavor createConstant(String mt, String prn) { + try { + return new DataFlavor(mt, prn); + } catch (Exception e) { + return null; + } + } + + /* + * 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: + * <pre> + * representationClass = java.lang.String + * mimeType = "application/x-java-serialized-object" + * </pre> + */ + public static final DataFlavor stringFlavor = createConstant(java.lang.String.class, "Unicode String"); + + /** + * The <code>DataFlavor</code> representing a Java Image class, + * where: + * <pre> + * representationClass = java.awt.Image + * mimeType = "image/x-java-image" + * </pre> + */ + public static final DataFlavor imageFlavor = createConstant("image/x-java-image; class=java.awt.Image", "Image"); + + /** + * The <code>DataFlavor</code> representing plain text with Unicode + * encoding, where: + * <pre> + * representationClass = InputStream + * mimeType = "text/plain; charset=unicode" + * </pre> + * This <code>DataFlavor</code> has been <b>deprecated</b> because + * (1) Its representation is an InputStream, an 8-bit based representation, + * while Unicode is a 16-bit character set; and (2) The charset "unicode" + * is not well-defined. "unicode" implies a particular platform's + * implementation of Unicode, not a cross-platform implementation. + * + * @deprecated as of 1.3. Use <code>DataFlavor.getReaderForText(Transferable)</code> + * instead of <code>Transferable.getTransferData(DataFlavor.plainTextFlavor)</code>. + */ + @Deprecated + public static final DataFlavor plainTextFlavor = createConstant("text/plain; charset=unicode; class=java.io.InputStream", "Plain Text"); + + /** + * A MIME Content-Type of application/x-java-serialized-object represents + * a graph of Java object(s) that have been made persistent. + * + * The representation class associated with this <code>DataFlavor</code> + * identifies the Java type of an object returned as a reference + * from an invocation <code>java.awt.datatransfer.getTransferData</code>. + */ + public static final String javaSerializedObjectMimeType = "application/x-java-serialized-object"; + + /** + * To transfer a list of files to/from Java (and the underlying + * platform) a <code>DataFlavor</code> of this type/subtype and + * representation class of <code>java.util.List</code> is used. + * Each element of the list is required/guaranteed to be of type + * <code>java.io.File</code>. + */ + public static final DataFlavor javaFileListFlavor = createConstant("application/x-java-file-list;class=java.util.List", null); + + /** + * To transfer a reference to an arbitrary Java object reference that + * has no associated MIME Content-type, across a <code>Transferable</code> + * interface WITHIN THE SAME JVM, a <code>DataFlavor</code> + * with this type/subtype is used, with a <code>representationClass</code> + * equal to the type of the class/interface being passed across the + * <code>Transferable</code>. + * <p> + * The object reference returned from + * <code>Transferable.getTransferData</code> for a <code>DataFlavor</code> + * with this MIME Content-Type is required to be + * an instance of the representation Class of the <code>DataFlavor</code>. + */ + public static final String javaJVMLocalObjectMimeType = "application/x-java-jvm-local-objectref"; + + /** + * In order to pass a live link to a Remote object via a Drag and Drop + * <code>ACTION_LINK</code> operation a Mime Content Type of + * application/x-java-remote-object should be used, + * where the representation class of the <code>DataFlavor</code> + * represents the type of the <code>Remote</code> interface to be + * transferred. + */ + 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 + * <code>Externalizable</code> interface. It is not + * intended for public (client) use. + * + * @since 1.2 + */ + public DataFlavor() { + super(); + } + + /** + * Constructs a fully specified <code>DataFlavor</code>. + * + * @exception NullPointerException if either <code>primaryType</code>, + * <code>subType</code> or <code>representationClass</code> is null + */ + private DataFlavor(String primaryType, String subType, MimeTypeParameterList params, Class<?> representationClass, String humanPresentableName) { + super(); + if (primaryType == null) { + throw new NullPointerException("primaryType"); + } + if (subType == null) { + throw new NullPointerException("subType"); + } + if (representationClass == null) { + throw new NullPointerException("representationClass"); + } + + if (params == null) params = new MimeTypeParameterList(); + + params.set("class", representationClass.getName()); + + if (humanPresentableName == null) { + humanPresentableName = params.get("humanPresentableName"); + + if (humanPresentableName == null) + humanPresentableName = primaryType + "/" + subType; + } + + try { + mimeType = new MimeType(primaryType, subType, params); + } catch (MimeTypeParseException mtpe) { + throw new IllegalArgumentException("MimeType Parse Exception: " + mtpe.getMessage()); + } + + this.representationClass = representationClass; + this.humanPresentableName = humanPresentableName; + + mimeType.removeParameter("humanPresentableName"); + } + + /** + * Constructs a <code>DataFlavor</code> that represents a Java class. + * <p> + * The returned <code>DataFlavor</code> will have the following + * characteristics: + * <pre> + * representationClass = representationClass + * mimeType = application/x-java-serialized-object + * </pre> + * @param representationClass the class used to transfer data in this flavor + * @param humanPresentableName the human-readable string used to identify + * this flavor; if this parameter is <code>null</code> + * then the value of the MIME Content Type is used + * @exception NullPointerException if <code>representationClass</code> is null + */ + public DataFlavor(Class<?> representationClass, String humanPresentableName) { + this("application", "x-java-serialized-object", null, representationClass, humanPresentableName); + if (representationClass == null) { + throw new NullPointerException("representationClass"); + } + } + + /** + * Constructs a <code>DataFlavor</code> that represents a + * <code>MimeType</code>. + * <p> + * The returned <code>DataFlavor</code> will have the following + * characteristics: + * <p> + * If the <code>mimeType</code> is + * "application/x-java-serialized-object; class=<representation class>", + * the result is the same as calling + * <code>new DataFlavor(Class.forName(<representation class>)</code>. + * <p> + * Otherwise: + * <pre> + * representationClass = InputStream + * mimeType = mimeType + * </pre> + * @param mimeType the string used to identify the MIME type for this flavor; + * if the <code>mimeType</code> does not specify a + * "class=" parameter, or if the class is not successfully + * loaded, then an <code>IllegalArgumentException</code> + * is thrown + * @param humanPresentableName the human-readable string used to identify + * this flavor; if this parameter is <code>null</code> + * then the value of the MIME Content Type is used + * @exception IllegalArgumentException if <code>mimeType</code> is + * invalid or if the class is not successfully loaded + * @exception NullPointerException if <code>mimeType</code> is null + */ + public DataFlavor(String mimeType, String humanPresentableName) { + super(); + if (mimeType == null) { + throw new NullPointerException("mimeType"); + } + try { + initialize(mimeType, humanPresentableName, this.getClass().getClassLoader()); + } catch (MimeTypeParseException mtpe) { + throw new IllegalArgumentException("failed to parse:" + mimeType); + } catch (ClassNotFoundException cnfe) { + throw new IllegalArgumentException("can't find specified class: " + cnfe.getMessage()); + } + } + + /** + * Constructs a <code>DataFlavor</code> that represents a + * <code>MimeType</code>. + * <p> + * The returned <code>DataFlavor</code> will have the following + * characteristics: + * <p> + * If the mimeType is + * "application/x-java-serialized-object; class=<representation class>", + * the result is the same as calling + * <code>new DataFlavor(Class.forName(<representation class>)</code>. + * <p> + * Otherwise: + * <pre> + * representationClass = InputStream + * mimeType = mimeType + * </pre> + * @param mimeType the string used to identify the MIME type for this flavor + * @param humanPresentableName the human-readable string used to + * identify this flavor + * @param classLoader the class loader to use + * @exception ClassNotFoundException if the class is not loaded + * @exception IllegalArgumentException if <code>mimeType</code> is + * invalid + * @exception NullPointerException if <code>mimeType</code> is null + */ + public DataFlavor(String mimeType, String humanPresentableName, ClassLoader classLoader) throws ClassNotFoundException { + super(); + if (mimeType == null) { + throw new NullPointerException("mimeType"); + } + try { + initialize(mimeType, humanPresentableName, classLoader); + } catch (MimeTypeParseException mtpe) { + throw new IllegalArgumentException("failed to parse:" + mimeType); + } + } + + /** + * Constructs a <code>DataFlavor</code> from a <code>mimeType</code> string. + * The string can specify a "class=<fully specified Java class name>" + * parameter to create a <code>DataFlavor</code> with the desired + * representation class. If the string does not contain "class=" parameter, + * <code>java.io.InputStream</code> is used as default. + * + * @param mimeType the string used to identify the MIME type for this flavor; + * if the class specified by "class=" parameter is not + * successfully loaded, then an + * <code>ClassNotFoundException</code> is thrown + * @exception ClassNotFoundException if the class is not loaded + * @exception IllegalArgumentException if <code>mimeType</code> is + * invalid + * @exception NullPointerException if <code>mimeType</code> is null + */ + public DataFlavor(String mimeType) throws ClassNotFoundException { + super(); + if (mimeType == null) { + throw new NullPointerException("mimeType"); + } + try { + initialize(mimeType, null, this.getClass().getClassLoader()); + } catch (MimeTypeParseException mtpe) { + throw new IllegalArgumentException("failed to parse:" + mimeType); + } + } + + /** + * Common initialization code called from various constructors. + * + * @param mimeType the MIME Content Type (must have a class= param) + * @param humanPresentableName the human Presentable Name or + * <code>null</code> + * @param classLoader the fallback class loader to resolve against + * + * @throws MimeTypeParseException + * @throws ClassNotFoundException + * @throws NullPointerException if <code>mimeType</code> is null + * + * @see #tryToLoadClass + */ + private void initialize(String mimeType, String humanPresentableName, ClassLoader classLoader) throws MimeTypeParseException, ClassNotFoundException { + if (mimeType == null) { + throw new NullPointerException("mimeType"); + } + + this.mimeType = new MimeType(mimeType); // throws + + String rcn = getParameter("class"); + + if (rcn == null) { + if ("application/x-java-serialized-object".equals(this.mimeType.getBaseType())) + + throw new IllegalArgumentException("no representation class specified for:" + mimeType); + else + representationClass = java.io.InputStream.class; // default + } else { // got a class name + representationClass = DataFlavor.tryToLoadClass(rcn, classLoader); + } + + this.mimeType.setParameter("class", representationClass.getName()); + + if (humanPresentableName == null) { + humanPresentableName = this.mimeType.getParameter("humanPresentableName"); + if (humanPresentableName == null) + humanPresentableName = this.mimeType.getPrimaryType() + "/" + this.mimeType.getSubType(); + } + + this.humanPresentableName = humanPresentableName; // set it. + + this.mimeType.removeParameter("humanPresentableName"); // just in case + } + + /** + * String representation of this <code>DataFlavor</code> and its + * parameters. The resulting <code>String</code> contains the name of + * the <code>DataFlavor</code> class, this flavor's MIME type, and its + * representation class. If this flavor has a primary MIME type of "text", + * supports the charset parameter, and has an encoded representation, the + * flavor's charset is also included. See <code>selectBestTextFlavor</code> + * for a list of text flavors which support the charset parameter. + * + * @return string representation of this <code>DataFlavor</code> + * @see #selectBestTextFlavor + */ + public String toString() { + String string = getClass().getName(); + string += "["+paramString()+"]"; + return string; + } + + private String paramString() { + String params = ""; + params += "mimetype="; + if (mimeType == null) { + params += "null"; + } else { + params += mimeType.getBaseType(); + } + params += ";representationclass="; + if (representationClass == null) { + params += "null"; + } else { + params += representationClass.getName(); + } + if (DataFlavorUtil.isFlavorCharsetTextType(this) && + (isRepresentationClassInputStream() || + isRepresentationClassByteBuffer() || + byte[].class.equals(representationClass))) + { + params += ";charset=" + DataFlavorUtil.getTextCharset(this); + } + return params; + } + + /** + * Returns a <code>DataFlavor</code> representing plain text with Unicode + * encoding, where: + * <pre> + * representationClass = java.io.InputStream + * mimeType = "text/plain; + * charset=<platform default Unicode encoding>" + * </pre> + * Sun's implementation for Microsoft Windows uses the encoding <code>utf-16le</code>. + * Sun's implementation for Solaris and Linux uses the encoding + * <code>iso-10646-ucs-2</code>. + * + * @return a <code>DataFlavor</code> representing plain text + * with Unicode encoding + * @since 1.3 + */ + public static final DataFlavor getTextPlainUnicodeFlavor() { + return new DataFlavor( + "text/plain;charset=" + DataFlavorUtil.getDesktopService().getDefaultUnicodeEncoding() + +";class=java.io.InputStream", "Plain Text"); + } + + /** + * Selects the best text <code>DataFlavor</code> from an array of <code> + * DataFlavor</code>s. Only <code>DataFlavor.stringFlavor</code>, and + * equivalent flavors, and flavors that have a primary MIME type of "text", + * are considered for selection. + * <p> + * Flavors are first sorted by their MIME types in the following order: + * <ul> + * <li>"text/sgml" + * <li>"text/xml" + * <li>"text/html" + * <li>"text/rtf" + * <li>"text/enriched" + * <li>"text/richtext" + * <li>"text/uri-list" + * <li>"text/tab-separated-values" + * <li>"text/t140" + * <li>"text/rfc822-headers" + * <li>"text/parityfec" + * <li>"text/directory" + * <li>"text/css" + * <li>"text/calendar" + * <li>"application/x-java-serialized-object" + * <li>"text/plain" + * <li>"text/<other>" + * </ul> + * <p>For example, "text/sgml" will be selected over + * "text/html", and <code>DataFlavor.stringFlavor</code> will be chosen + * over <code>DataFlavor.plainTextFlavor</code>. + * <p> + * If two or more flavors share the best MIME type in the array, then that + * MIME type will be checked to see if it supports the charset parameter. + * <p> + * The following MIME types support, or are treated as though they support, + * the charset parameter: + * <ul> + * <li>"text/sgml" + * <li>"text/xml" + * <li>"text/html" + * <li>"text/enriched" + * <li>"text/richtext" + * <li>"text/uri-list" + * <li>"text/directory" + * <li>"text/css" + * <li>"text/calendar" + * <li>"application/x-java-serialized-object" + * <li>"text/plain" + * </ul> + * The following MIME types do not support, or are treated as though they + * do not support, the charset parameter: + * <ul> + * <li>"text/rtf" + * <li>"text/tab-separated-values" + * <li>"text/t140" + * <li>"text/rfc822-headers" + * <li>"text/parityfec" + * </ul> + * For "text/<other>" MIME types, the first time the JRE needs to + * determine whether the MIME type supports the charset parameter, it will + * check whether the parameter is explicitly listed in an arbitrarily + * chosen <code>DataFlavor</code> which uses that MIME type. If so, the JRE + * will assume from that point on that the MIME type supports the charset + * parameter and will not check again. If the parameter is not explicitly + * listed, the JRE will assume from that point on that the MIME type does + * not support the charset parameter and will not check again. Because + * this check is performed on an arbitrarily chosen + * <code>DataFlavor</code>, developers must ensure that all + * <code>DataFlavor</code>s with a "text/<other>" MIME type specify + * the charset parameter if it is supported by that MIME type. Developers + * should never rely on the JRE to substitute the platform's default + * charset for a "text/<other>" DataFlavor. Failure to adhere to this + * restriction will lead to undefined behavior. + * <p> + * If the best MIME type in the array does not support the charset + * parameter, the flavors which share that MIME type will then be sorted by + * their representation classes in the following order: + * <code>java.io.InputStream</code>, <code>java.nio.ByteBuffer</code>, + * <code>[B</code>, <all others>. + * <p> + * If two or more flavors share the best representation class, or if no + * flavor has one of the three specified representations, then one of those + * flavors will be chosen non-deterministically. + * <p> + * If the best MIME type in the array does support the charset parameter, + * the flavors which share that MIME type will then be sorted by their + * representation classes in the following order: + * <code>java.io.Reader</code>, <code>java.lang.String</code>, + * <code>java.nio.CharBuffer</code>, <code>[C</code>, <all others>. + * <p> + * If two or more flavors share the best representation class, and that + * representation is one of the four explicitly listed, then one of those + * flavors will be chosen non-deterministically. If, however, no flavor has + * one of the four specified representations, the flavors will then be + * sorted by their charsets. Unicode charsets, such as "UTF-16", "UTF-8", + * "UTF-16BE", "UTF-16LE", and their aliases, are considered best. After + * them, the platform default charset and its aliases are selected. + * "US-ASCII" and its aliases are worst. All other charsets are chosen in + * alphabetical order, but only charsets supported by this implementation + * of the Java platform will be considered. + * <p> + * If two or more flavors share the best charset, the flavors will then + * again be sorted by their representation classes in the following order: + * <code>java.io.InputStream</code>, <code>java.nio.ByteBuffer</code>, + * <code>[B</code>, <all others>. + * <p> + * If two or more flavors share the best representation class, or if no + * flavor has one of the three specified representations, then one of those + * flavors will be chosen non-deterministically. + * + * @param availableFlavors an array of available <code>DataFlavor</code>s + * @return the best (highest fidelity) flavor according to the rules + * specified above, or <code>null</code>, + * if <code>availableFlavors</code> is <code>null</code>, + * has zero length, or contains no text flavors + * @since 1.3 + */ + public static final DataFlavor selectBestTextFlavor( + DataFlavor[] availableFlavors) { + if (availableFlavors == null || availableFlavors.length == 0) { + return null; + } + + DataFlavor bestFlavor = Collections.max(Arrays.asList(availableFlavors), + DataFlavorUtil.getTextFlavorComparator()); + + if (!bestFlavor.isFlavorTextType()) { + return null; + } + + return bestFlavor; + } + + /** + * Gets a Reader for a text flavor, decoded, if necessary, for the expected + * charset (encoding). The supported representation classes are + * <code>java.io.Reader</code>, <code>java.lang.String</code>, + * <code>java.nio.CharBuffer</code>, <code>[C</code>, + * <code>java.io.InputStream</code>, <code>java.nio.ByteBuffer</code>, + * and <code>[B</code>. + * <p> + * Because text flavors which do not support the charset parameter are + * encoded in a non-standard format, this method should not be called for + * such flavors. However, in order to maintain backward-compatibility, + * if this method is called for such a flavor, this method will treat the + * flavor as though it supports the charset parameter and attempt to + * decode it accordingly. See <code>selectBestTextFlavor</code> for a list + * of text flavors which do not support the charset parameter. + * + * @param transferable the <code>Transferable</code> whose data will be + * requested in this flavor + * + * @return a <code>Reader</code> to read the <code>Transferable</code>'s + * data + * + * @exception IllegalArgumentException if the representation class + * is not one of the seven listed above + * @exception IllegalArgumentException if the <code>Transferable</code> + * has <code>null</code> data + * @exception NullPointerException if the <code>Transferable</code> is + * <code>null</code> + * @exception UnsupportedEncodingException if this flavor's representation + * is <code>java.io.InputStream</code>, + * <code>java.nio.ByteBuffer</code>, or <code>[B</code> and + * this flavor's encoding is not supported by this + * implementation of the Java platform + * @exception UnsupportedFlavorException if the <code>Transferable</code> + * does not support this flavor + * @exception IOException if the data cannot be read because of an + * I/O error + * @see #selectBestTextFlavor + * @since 1.3 + */ + public Reader getReaderForText(Transferable transferable) + throws UnsupportedFlavorException, IOException + { + Object transferObject = transferable.getTransferData(this); + if (transferObject == null) { + throw new IllegalArgumentException + ("getTransferData() returned null"); + } + + if (transferObject instanceof Reader) { + return (Reader)transferObject; + } else if (transferObject instanceof String) { + return new StringReader((String)transferObject); + } else if (transferObject instanceof CharBuffer) { + CharBuffer buffer = (CharBuffer)transferObject; + int size = buffer.remaining(); + char[] chars = new char[size]; + buffer.get(chars, 0, size); + return new CharArrayReader(chars); + } else if (transferObject instanceof char[]) { + return new CharArrayReader((char[])transferObject); + } + + InputStream stream = null; + + if (transferObject instanceof InputStream) { + stream = (InputStream)transferObject; + } else if (transferObject instanceof ByteBuffer) { + ByteBuffer buffer = (ByteBuffer)transferObject; + int size = buffer.remaining(); + byte[] bytes = new byte[size]; + buffer.get(bytes, 0, size); + stream = new ByteArrayInputStream(bytes); + } else if (transferObject instanceof byte[]) { + stream = new ByteArrayInputStream((byte[])transferObject); + } + + if (stream == null) { + throw new IllegalArgumentException("transfer data is not Reader, String, CharBuffer, char array, InputStream, ByteBuffer, or byte array"); + } + + String encoding = getParameter("charset"); + return (encoding == null) + ? new InputStreamReader(stream) + : new InputStreamReader(stream, encoding); + } + + /** + * Returns the MIME type string for this <code>DataFlavor</code>. + * @return the MIME type string for this flavor + */ + public String getMimeType() { + return (mimeType != null) ? mimeType.toString() : null; + } + + /** + * Returns the <code>Class</code> which objects supporting this + * <code>DataFlavor</code> will return when this <code>DataFlavor</code> + * is requested. + * @return the <code>Class</code> which objects supporting this + * <code>DataFlavor</code> will return when this <code>DataFlavor</code> + * is requested + */ + public Class<?> getRepresentationClass() { + return representationClass; + } + + /** + * Returns the human presentable name for the data format that this + * <code>DataFlavor</code> represents. This name would be localized + * for different countries. + * @return the human presentable name for the data format that this + * <code>DataFlavor</code> represents + */ + public String getHumanPresentableName() { + return humanPresentableName; + } + + /** + * Returns the primary MIME type for this <code>DataFlavor</code>. + * @return the primary MIME type of this <code>DataFlavor</code> + */ + public String getPrimaryType() { + return (mimeType != null) ? mimeType.getPrimaryType() : null; + } + + /** + * Returns the sub MIME type of this <code>DataFlavor</code>. + * @return the Sub MIME type of this <code>DataFlavor</code> + */ + public String getSubType() { + return (mimeType != null) ? mimeType.getSubType() : null; + } + + /** + * Returns the human presentable name for this <code>DataFlavor</code> + * if <code>paramName</code> equals "humanPresentableName". Otherwise + * returns the MIME type value associated with <code>paramName</code>. + * + * @param paramName the parameter name requested + * @return the value of the name parameter, or <code>null</code> + * if there is no associated value + */ + public String getParameter(String paramName) { + if (paramName.equals("humanPresentableName")) { + return humanPresentableName; + } else { + return (mimeType != null) + ? mimeType.getParameter(paramName) : null; + } + } + + /** + * Sets the human presentable name for the data format that this + * <code>DataFlavor</code> represents. This name would be localized + * for different countries. + * @param humanPresentableName the new human presentable name + */ + public void setHumanPresentableName(String humanPresentableName) { + this.humanPresentableName = humanPresentableName; + } + + /** + * {@inheritDoc} + * <p> + * The equals comparison for the {@code DataFlavor} class is implemented + * as follows: Two <code>DataFlavor</code>s are considered equal if and + * only if their MIME primary type and subtype and representation class are + * equal. Additionally, if the primary type is "text", the subtype denotes + * a text flavor which supports the charset parameter, and the + * representation class is not <code>java.io.Reader</code>, + * <code>java.lang.String</code>, <code>java.nio.CharBuffer</code>, or + * <code>[C</code>, the <code>charset</code> parameter must also be equal. + * If a charset is not explicitly specified for one or both + * <code>DataFlavor</code>s, the platform default encoding is assumed. See + * <code>selectBestTextFlavor</code> for a list of text flavors which + * support the charset parameter. + * + * @param o the <code>Object</code> to compare with <code>this</code> + * @return <code>true</code> if <code>that</code> is equivalent to this + * <code>DataFlavor</code>; <code>false</code> otherwise + * @see #selectBestTextFlavor + */ + public boolean equals(Object o) { + return ((o instanceof DataFlavor) && equals((DataFlavor)o)); + } + + /** + * This method has the same behavior as {@link #equals(Object)}. + * The only difference being that it takes a {@code DataFlavor} instance + * as a parameter. + * + * @param that the <code>DataFlavor</code> to compare with + * <code>this</code> + * @return <code>true</code> if <code>that</code> is equivalent to this + * <code>DataFlavor</code>; <code>false</code> otherwise + * @see #selectBestTextFlavor + */ + public boolean equals(DataFlavor that) { + if (that == null) { + return false; + } + if (this == that) { + return true; + } + + if (!Objects.equals(this.getRepresentationClass(), that.getRepresentationClass())) { + return false; + } + + if (mimeType == null) { + if (that.mimeType != null) { + return false; + } + } else { + if (!mimeType.match(that.mimeType)) { + return false; + } + + if ("text".equals(getPrimaryType())) { + if (DataFlavorUtil.doesSubtypeSupportCharset(this) + && representationClass != null + && !isStandardTextRepresentationClass()) { + String thisCharset = + DataFlavorUtil.canonicalName(this.getParameter("charset")); + String thatCharset = + DataFlavorUtil.canonicalName(that.getParameter("charset")); + if (!Objects.equals(thisCharset, thatCharset)) { + return false; + } + } + + if ("html".equals(getSubType())) { + String thisDocument = this.getParameter("document"); + String thatDocument = that.getParameter("document"); + if (!Objects.equals(thisDocument, thatDocument)) { + return false; + } + } + } + } + + return true; + } + + /** + * Compares only the <code>mimeType</code> against the passed in + * <code>String</code> and <code>representationClass</code> is + * not considered in the comparison. + * + * If <code>representationClass</code> needs to be compared, then + * <code>equals(new DataFlavor(s))</code> may be used. + * @deprecated As inconsistent with <code>hashCode()</code> contract, + * use <code>isMimeTypeEqual(String)</code> instead. + * @param s the {@code mimeType} to compare. + * @return true if the String (MimeType) is equal; false otherwise or if + * {@code s} is {@code null} + */ + @Deprecated + public boolean equals(String s) { + if (s == null || mimeType == null) + return false; + return isMimeTypeEqual(s); + } + + /** + * Returns hash code for this <code>DataFlavor</code>. + * For two equal <code>DataFlavor</code>s, hash codes are equal. + * For the <code>String</code> + * that matches <code>DataFlavor.equals(String)</code>, it is not + * guaranteed that <code>DataFlavor</code>'s hash code is equal + * to the hash code of the <code>String</code>. + * + * @return a hash code for this <code>DataFlavor</code> + */ + public int hashCode() { + int total = 0; + + if (representationClass != null) { + total += representationClass.hashCode(); + } + + if (mimeType != null) { + String primaryType = mimeType.getPrimaryType(); + if (primaryType != null) { + total += primaryType.hashCode(); + } + + // Do not add subType.hashCode() to the total. equals uses + // MimeType.match which reports a match if one or both of the + // subTypes is '*', regardless of the other subType. + + if ("text".equals(primaryType)) { + if (DataFlavorUtil.doesSubtypeSupportCharset(this) + && representationClass != null + && !isStandardTextRepresentationClass()) { + String charset = DataFlavorUtil.canonicalName(getParameter("charset")); + if (charset != null) { + total += charset.hashCode(); + } + } + + if ("html".equals(getSubType())) { + String document = this.getParameter("document"); + if (document != null) { + total += document.hashCode(); + } + } + } + } + + return total; + } + + /** + * Identical to {@link #equals(DataFlavor)}. + * + * @param that the <code>DataFlavor</code> to compare with + * <code>this</code> + * @return <code>true</code> if <code>that</code> is equivalent to this + * <code>DataFlavor</code>; <code>false</code> otherwise + * @see #selectBestTextFlavor + * @since 1.3 + */ + public boolean match(DataFlavor that) { + return equals(that); + } + + /** + * Returns whether the string representation of the MIME type passed in + * is equivalent to the MIME type of this <code>DataFlavor</code>. + * Parameters are not included in the comparison. + * + * @param mimeType the string representation of the MIME type + * @return true if the string representation of the MIME type passed in is + * equivalent to the MIME type of this <code>DataFlavor</code>; + * false otherwise + * @throws NullPointerException if mimeType is <code>null</code> + */ + public boolean isMimeTypeEqual(String mimeType) { + // JCK Test DataFlavor0117: if 'mimeType' is null, throw NPE + if (mimeType == null) { + throw new NullPointerException("mimeType"); + } + if (this.mimeType == null) { + return false; + } + try { + return this.mimeType.match(new MimeType(mimeType)); + } catch (MimeTypeParseException mtpe) { + return false; + } + } + + /** + * Compares the <code>mimeType</code> of two <code>DataFlavor</code> + * objects. No parameters are considered. + * + * @param dataFlavor the <code>DataFlavor</code> to be compared + * @return true if the <code>MimeType</code>s are equal, + * otherwise false + */ + + public final boolean isMimeTypeEqual(DataFlavor dataFlavor) { + return isMimeTypeEqual(dataFlavor.mimeType); + } + + /** + * Compares the <code>mimeType</code> of two <code>DataFlavor</code> + * objects. No parameters are considered. + * + * @return true if the <code>MimeType</code>s are equal, + * otherwise false + */ + + private boolean isMimeTypeEqual(MimeType mtype) { + if (this.mimeType == null) { + return (mtype == null); + } + return mimeType.match(mtype); + } + + /** + * Checks if the representation class is one of the standard text + * representation classes. + * + * @return true if the representation class is one of the standard text + * representation classes, otherwise false + */ + private boolean isStandardTextRepresentationClass() { + return isRepresentationClassReader() + || String.class.equals(representationClass) + || isRepresentationClassCharBuffer() + || char[].class.equals(representationClass); + } + + /** + * Does the <code>DataFlavor</code> represent a serialized object? + * @return whether or not a serialized object is represented + */ + public boolean isMimeTypeSerializedObject() { + return isMimeTypeEqual(javaSerializedObjectMimeType); + } + + /** + * Returns the default representation class. + * @return the default representation class + */ + public final Class<?> getDefaultRepresentationClass() { + return ioInputStreamClass; + } + + /** + * Returns the name of the default representation class. + * @return the name of the default representation class + */ + public final String getDefaultRepresentationClassAsString() { + return getDefaultRepresentationClass().getName(); + } + + /** + * Does the <code>DataFlavor</code> represent a + * <code>java.io.InputStream</code>? + * @return whether or not this {@code DataFlavor} represent a + * {@code java.io.InputStream} + */ + public boolean isRepresentationClassInputStream() { + return ioInputStreamClass.isAssignableFrom(representationClass); + } + + /** + * Returns whether the representation class for this + * <code>DataFlavor</code> is <code>java.io.Reader</code> or a subclass + * thereof. + * @return whether or not the representation class for this + * {@code DataFlavor} is {@code java.io.Reader} or a subclass + * thereof + * + * @since 1.4 + */ + public boolean isRepresentationClassReader() { + return java.io.Reader.class.isAssignableFrom(representationClass); + } + + /** + * Returns whether the representation class for this + * <code>DataFlavor</code> is <code>java.nio.CharBuffer</code> or a + * subclass thereof. + * @return whether or not the representation class for this + * {@code DataFlavor} is {@code java.nio.CharBuffer} or a subclass + * thereof + * + * @since 1.4 + */ + public boolean isRepresentationClassCharBuffer() { + return java.nio.CharBuffer.class.isAssignableFrom(representationClass); + } + + /** + * Returns whether the representation class for this + * <code>DataFlavor</code> is <code>java.nio.ByteBuffer</code> or a + * subclass thereof. + * @return whether or not the representation class for this + * {@code DataFlavor} is {@code java.nio.ByteBuffer} or a subclass + * thereof + * + * @since 1.4 + */ + public boolean isRepresentationClassByteBuffer() { + return java.nio.ByteBuffer.class.isAssignableFrom(representationClass); + } + + /** + * Returns true if the representation class can be serialized. + * @return true if the representation class can be serialized + */ + + public boolean isRepresentationClassSerializable() { + return java.io.Serializable.class.isAssignableFrom(representationClass); + } + + /** + * Returns true if the representation class is <code>Remote</code>. + * @return true if the representation class is <code>Remote</code> + */ + public boolean isRepresentationClassRemote() { + return DataFlavorUtil.RMI.isRemote(representationClass); + } + + /** + * Returns true if the <code>DataFlavor</code> specified represents + * a serialized object. + * @return true if the <code>DataFlavor</code> specified represents + * a Serialized Object + */ + + public boolean isFlavorSerializedObjectType() { + return isRepresentationClassSerializable() && isMimeTypeEqual(javaSerializedObjectMimeType); + } + + /** + * Returns true if the <code>DataFlavor</code> specified represents + * a remote object. + * @return true if the <code>DataFlavor</code> specified represents + * a Remote Object + */ + + public boolean isFlavorRemoteObjectType() { + return isRepresentationClassRemote() + && isRepresentationClassSerializable() + && isMimeTypeEqual(javaRemoteObjectMimeType); + } + + + /** + * Returns true if the <code>DataFlavor</code> specified represents + * a list of file objects. + * @return true if the <code>DataFlavor</code> specified represents + * a List of File objects + */ + + public boolean isFlavorJavaFileListType() { + if (mimeType == null || representationClass == null) + return false; + return java.util.List.class.isAssignableFrom(representationClass) && + mimeType.match(javaFileListFlavor.mimeType); + + } + + /** + * Returns whether this <code>DataFlavor</code> is a valid text flavor for + * this implementation of the Java platform. Only flavors equivalent to + * <code>DataFlavor.stringFlavor</code> and <code>DataFlavor</code>s with + * a primary MIME type of "text" can be valid text flavors. + * <p> + * If this flavor supports the charset parameter, it must be equivalent to + * <code>DataFlavor.stringFlavor</code>, or its representation must be + * <code>java.io.Reader</code>, <code>java.lang.String</code>, + * <code>java.nio.CharBuffer</code>, <code>[C</code>, + * <code>java.io.InputStream</code>, <code>java.nio.ByteBuffer</code>, or + * <code>[B</code>. If the representation is + * <code>java.io.InputStream</code>, <code>java.nio.ByteBuffer</code>, or + * <code>[B</code>, then this flavor's <code>charset</code> parameter must + * be supported by this implementation of the Java platform. If a charset + * is not specified, then the platform default charset, which is always + * supported, is assumed. + * <p> + * If this flavor does not support the charset parameter, its + * representation must be <code>java.io.InputStream</code>, + * <code>java.nio.ByteBuffer</code>, or <code>[B</code>. + * <p> + * See <code>selectBestTextFlavor</code> for a list of text flavors which + * support the charset parameter. + * + * @return <code>true</code> if this <code>DataFlavor</code> is a valid + * text flavor as described above; <code>false</code> otherwise + * @see #selectBestTextFlavor + * @since 1.4 + */ + public boolean isFlavorTextType() { + return (DataFlavorUtil.isFlavorCharsetTextType(this) || + DataFlavorUtil.isFlavorNoncharsetTextType(this)); + } + + /** + * Serializes this <code>DataFlavor</code>. + */ + + public synchronized void writeExternal(ObjectOutput os) throws IOException { + if (mimeType != null) { + mimeType.setParameter("humanPresentableName", humanPresentableName); + os.writeObject(mimeType); + mimeType.removeParameter("humanPresentableName"); + } else { + os.writeObject(null); + } + + os.writeObject(representationClass); + } + + /** + * Restores this <code>DataFlavor</code> from a Serialized state. + */ + + public synchronized void readExternal(ObjectInput is) throws IOException , ClassNotFoundException { + String rcn = null; + mimeType = (MimeType)is.readObject(); + + if (mimeType != null) { + humanPresentableName = + mimeType.getParameter("humanPresentableName"); + mimeType.removeParameter("humanPresentableName"); + rcn = mimeType.getParameter("class"); + if (rcn == null) { + throw new IOException("no class parameter specified in: " + + mimeType); + } + } + + try { + representationClass = (Class)is.readObject(); + } catch (OptionalDataException ode) { + if (!ode.eof || ode.length != 0) { + throw ode; + } + // Ensure backward compatibility. + // Old versions didn't write the representation class to the stream. + if (rcn != null) { + representationClass = + DataFlavor.tryToLoadClass(rcn, getClass().getClassLoader()); + } + } + } + + /** + * Returns a clone of this <code>DataFlavor</code>. + * @return a clone of this <code>DataFlavor</code> + */ + + public Object clone() throws CloneNotSupportedException { + Object newObj = super.clone(); + if (mimeType != null) { + ((DataFlavor)newObj).mimeType = (MimeType)mimeType.clone(); + } + return newObj; + } // clone() + + /** + * Called on <code>DataFlavor</code> for every MIME Type parameter + * to allow <code>DataFlavor</code> subclasses to handle special + * parameters like the text/plain <code>charset</code> + * parameters, whose values are case insensitive. (MIME type parameter + * values are supposed to be case sensitive. + * <p> + * This method is called for each parameter name/value pair and should + * return the normalized representation of the <code>parameterValue</code>. + * + * This method is never invoked by this implementation from 1.1 onwards. + * + * @param parameterName the parameter name + * @param parameterValue the parameter value + * @return the parameter value + * @deprecated + */ + @Deprecated + protected String normalizeMimeTypeParameter(String parameterName, String parameterValue) { + return parameterValue; + } + + /** + * Called for each MIME type string to give <code>DataFlavor</code> subtypes + * the opportunity to change how the normalization of MIME types is + * accomplished. One possible use would be to add default + * parameter/value pairs in cases where none are present in the MIME + * type string passed in. + * + * This method is never invoked by this implementation from 1.1 onwards. + * + * @param mimeType the mime type + * @return the mime type + * @deprecated + */ + @Deprecated + protected String normalizeMimeType(String mimeType) { + return mimeType; + } + + /* + * fields + */ + + /* placeholder for caching any platform-specific data for flavor */ + + transient int atom; + + /* Mime Type of DataFlavor */ + + MimeType mimeType; + + private String humanPresentableName; + + /** Java class of objects this DataFlavor represents **/ + + private Class<?> representationClass; + +} // class DataFlavor
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/FlavorEvent.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003, 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package java.awt.datatransfer; + +import java.util.EventObject; + + +/** + * <code>FlavorEvent</code> is used to notify interested parties + * that available {@link DataFlavor}s have changed in the + * {@link Clipboard} (the event source). + * + * @see FlavorListener + * + * @author Alexander Gerasimov + * @since 1.5 + */ +public class FlavorEvent extends EventObject { + private static final long serialVersionUID = -5842664112252414548L; + + /** + * Constructs a <code>FlavorEvent</code> object. + * + * @param source the <code>Clipboard</code> that is the source of the event + * + * @throws IllegalArgumentException if the {@code source} is {@code null} + */ + public FlavorEvent(Clipboard source) { + super(source); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/FlavorListener.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package java.awt.datatransfer; + +import java.util.EventListener; + + +/** + * Defines an object which listens for {@link FlavorEvent}s. + * + * @author Alexander Gerasimov + * @since 1.5 + */ +public interface FlavorListener extends EventListener { + /** + * Invoked when the target {@link Clipboard} of the listener + * has changed its available {@link DataFlavor}s. + * <p> + * Some notifications may be redundant — they are not + * caused by a change of the set of DataFlavors available + * on the clipboard. + * For example, if the clipboard subsystem supposes that + * the system clipboard's contents has been changed but it + * can't ascertain whether its DataFlavors have been changed + * because of some exceptional condition when accessing the + * clipboard, the notification is sent to ensure from omitting + * a significant notification. Ordinarily, those redundant + * notifications should be occasional. + * + * @param e a <code>FlavorEvent</code> object + */ + void flavorsChanged(FlavorEvent e); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/FlavorMap.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1997, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.awt.datatransfer; + +import java.util.Map; + + +/** + * A two-way Map between "natives" (Strings), which correspond to platform- + * specific data formats, and "flavors" (DataFlavors), which correspond to + * platform-independent MIME types. FlavorMaps need not be symmetric, but + * typically are. + * + * + * @since 1.2 + */ +public interface FlavorMap { + + /** + * Returns a <code>Map</code> of the specified <code>DataFlavor</code>s to + * their corresponding <code>String</code> native. The returned + * <code>Map</code> is a modifiable copy of this <code>FlavorMap</code>'s + * internal data. Client code is free to modify the <code>Map</code> + * without affecting this object. + * + * @param flavors an array of <code>DataFlavor</code>s which will be the + * key set of the returned <code>Map</code>. If <code>null</code> is + * specified, a mapping of all <code>DataFlavor</code>s currently + * known to this <code>FlavorMap</code> to their corresponding + * <code>String</code> natives will be returned. + * @return a <code>java.util.Map</code> of <code>DataFlavor</code>s to + * <code>String</code> natives + */ + Map<DataFlavor,String> getNativesForFlavors(DataFlavor[] flavors); + + /** + * Returns a <code>Map</code> of the specified <code>String</code> natives + * to their corresponding <code>DataFlavor</code>. The returned + * <code>Map</code> is a modifiable copy of this <code>FlavorMap</code>'s + * internal data. Client code is free to modify the <code>Map</code> + * without affecting this object. + * + * @param natives an array of <code>String</code>s which will be the + * key set of the returned <code>Map</code>. If <code>null</code> is + * specified, a mapping of all <code>String</code> natives currently + * known to this <code>FlavorMap</code> to their corresponding + * <code>DataFlavor</code>s will be returned. + * @return a <code>java.util.Map</code> of <code>String</code> natives to + * <code>DataFlavor</code>s + */ + Map<String,DataFlavor> getFlavorsForNatives(String[] natives); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/FlavorTable.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2000, 2004, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.awt.datatransfer; + +import java.util.List; + + +/** + * A FlavorMap which relaxes the traditional 1-to-1 restriction of a Map. A + * flavor is permitted to map to any number of natives, and likewise a native + * is permitted to map to any number of flavors. FlavorTables need not be + * symmetric, but typically are. + * + * @author David Mendenhall + * + * @since 1.4 + */ +public interface FlavorTable extends FlavorMap { + + /** + * Returns a <code>List</code> of <code>String</code> natives to which the + * specified <code>DataFlavor</code> corresponds. The <code>List</code> + * will be sorted from best native to worst. That is, the first native will + * best reflect data in the specified flavor to the underlying native + * platform. The returned <code>List</code> is a modifiable copy of this + * <code>FlavorTable</code>'s internal data. Client code is free to modify + * the <code>List</code> without affecting this object. + * + * @param flav the <code>DataFlavor</code> whose corresponding natives + * should be returned. If <code>null</code> is specified, all + * natives currently known to this <code>FlavorTable</code> are + * returned in a non-deterministic order. + * @return a <code>java.util.List</code> of <code>java.lang.String</code> + * objects which are platform-specific representations of platform- + * specific data formats + */ + List<String> getNativesForFlavor(DataFlavor flav); + + /** + * Returns a <code>List</code> of <code>DataFlavor</code>s to which the + * specified <code>String</code> corresponds. The <code>List</code> will be + * sorted from best <code>DataFlavor</code> to worst. That is, the first + * <code>DataFlavor</code> will best reflect data in the specified + * native to a Java application. The returned <code>List</code> is a + * modifiable copy of this <code>FlavorTable</code>'s internal data. + * Client code is free to modify the <code>List</code> without affecting + * this object. + * + * @param nat the native whose corresponding <code>DataFlavor</code>s + * should be returned. If <code>null</code> is specified, all + * <code>DataFlavor</code>s currently known to this + * <code>FlavorTable</code> are returned in a non-deterministic + * order. + * @return a <code>java.util.List</code> of <code>DataFlavor</code> + * objects into which platform-specific data in the specified, + * platform-specific native can be translated + */ + List<DataFlavor> getFlavorsForNative(String nat); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/MimeType.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,394 @@ +/* + * Copyright (c) 1997, 2012, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.awt.datatransfer; + +import java.io.Externalizable; +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Locale; + + +/** + * A Multipurpose Internet Mail Extension (MIME) type, as defined + * in RFC 2045 and 2046. + * + * THIS IS *NOT* - REPEAT *NOT* - A PUBLIC CLASS! DataFlavor IS + * THE PUBLIC INTERFACE, AND THIS IS PROVIDED AS A ***PRIVATE*** + * (THAT IS AS IN *NOT* PUBLIC) HELPER CLASS! + */ +class MimeType implements Externalizable, Cloneable { + + /* + * serialization support + */ + + static final long serialVersionUID = -6568722458793895906L; + + /** + * Constructor for externalization; this constructor should not be + * called directly by an application, since the result will be an + * uninitialized, immutable <code>MimeType</code> object. + */ + public MimeType() { + } + + /** + * Builds a <code>MimeType</code> from a <code>String</code>. + * + * @param rawdata text used to initialize the <code>MimeType</code> + * @throws NullPointerException if <code>rawdata</code> is null + */ + public MimeType(String rawdata) throws MimeTypeParseException { + parse(rawdata); + } + + /** + * Builds a <code>MimeType</code> with the given primary and sub + * type but has an empty parameter list. + * + * @param primary the primary type of this <code>MimeType</code> + * @param sub the subtype of this <code>MimeType</code> + * @throws NullPointerException if either <code>primary</code> or + * <code>sub</code> is null + */ + public MimeType(String primary, String sub) throws MimeTypeParseException { + this(primary, sub, new MimeTypeParameterList()); + } + + /** + * Builds a <code>MimeType</code> with a pre-defined + * and valid (or empty) parameter list. + * + * @param primary the primary type of this <code>MimeType</code> + * @param sub the subtype of this <code>MimeType</code> + * @param mtpl the requested parameter list + * @throws NullPointerException if either <code>primary</code>, + * <code>sub</code> or <code>mtpl</code> is null + */ + public MimeType(String primary, String sub, MimeTypeParameterList mtpl) throws +MimeTypeParseException { + // check to see if primary is valid + if(isValidToken(primary)) { + primaryType = primary.toLowerCase(Locale.ENGLISH); + } else { + throw new MimeTypeParseException("Primary type is invalid."); + } + + // check to see if sub is valid + if(isValidToken(sub)) { + subType = sub.toLowerCase(Locale.ENGLISH); + } else { + throw new MimeTypeParseException("Sub type is invalid."); + } + + parameters = (MimeTypeParameterList)mtpl.clone(); + } + + public int hashCode() { + + // We sum up the hash codes for all of the strings. This + // way, the order of the strings is irrelevant + int code = 0; + code += primaryType.hashCode(); + code += subType.hashCode(); + code += parameters.hashCode(); + return code; + } // hashCode() + + /** + * <code>MimeType</code>s are equal if their primary types, + * subtypes, and parameters are all equal. No default values + * are taken into account. + * @param thatObject the object to be evaluated as a + * <code>MimeType</code> + * @return <code>true</code> if <code>thatObject</code> is + * a <code>MimeType</code>; otherwise returns <code>false</code> + */ + public boolean equals(Object thatObject) { + if (!(thatObject instanceof MimeType)) { + return false; + } + MimeType that = (MimeType)thatObject; + boolean isIt = + ((this.primaryType.equals(that.primaryType)) && + (this.subType.equals(that.subType)) && + (this.parameters.equals(that.parameters))); + return isIt; + } // equals() + + /** + * A routine for parsing the MIME type out of a String. + * + * @throws NullPointerException if <code>rawdata</code> is null + */ + private void parse(String rawdata) throws MimeTypeParseException { + int slashIndex = rawdata.indexOf('/'); + int semIndex = rawdata.indexOf(';'); + if((slashIndex < 0) && (semIndex < 0)) { + // neither character is present, so treat it + // as an error + throw new MimeTypeParseException("Unable to find a sub type."); + } else if((slashIndex < 0) && (semIndex >= 0)) { + // we have a ';' (and therefore a parameter list), + // but no '/' indicating a sub type is present + throw new MimeTypeParseException("Unable to find a sub type."); + } else if((slashIndex >= 0) && (semIndex < 0)) { + // we have a primary and sub type but no parameter list + primaryType = rawdata.substring(0,slashIndex). + trim().toLowerCase(Locale.ENGLISH); + subType = rawdata.substring(slashIndex + 1). + trim().toLowerCase(Locale.ENGLISH); + parameters = new MimeTypeParameterList(); + } else if (slashIndex < semIndex) { + // we have all three items in the proper sequence + primaryType = rawdata.substring(0, slashIndex). + trim().toLowerCase(Locale.ENGLISH); + subType = rawdata.substring(slashIndex + 1, + semIndex).trim().toLowerCase(Locale.ENGLISH); + parameters = new +MimeTypeParameterList(rawdata.substring(semIndex)); + } else { + // we have a ';' lexically before a '/' which means we have a primary type + // & a parameter list but no sub type + throw new MimeTypeParseException("Unable to find a sub type."); + } + + // now validate the primary and sub types + + // check to see if primary is valid + if(!isValidToken(primaryType)) { + throw new MimeTypeParseException("Primary type is invalid."); + } + + // check to see if sub is valid + if(!isValidToken(subType)) { + throw new MimeTypeParseException("Sub type is invalid."); + } + } + + /** + * Retrieve the primary type of this object. + */ + public String getPrimaryType() { + return primaryType; + } + + /** + * Retrieve the sub type of this object. + */ + public String getSubType() { + return subType; + } + + /** + * Retrieve a copy of this object's parameter list. + */ + public MimeTypeParameterList getParameters() { + return (MimeTypeParameterList)parameters.clone(); + } + + /** + * Retrieve the value associated with the given name, or null if there + * is no current association. + */ + public String getParameter(String name) { + return parameters.get(name); + } + + /** + * Set the value to be associated with the given name, replacing + * any previous association. + * + * @throw IllegalArgumentException if parameter or value is illegal + */ + public void setParameter(String name, String value) { + parameters.set(name, value); + } + + /** + * Remove any value associated with the given name. + * + * @throw IllegalArgumentException if parameter may not be deleted + */ + public void removeParameter(String name) { + parameters.remove(name); + } + + /** + * Return the String representation of this object. + */ + public String toString() { + return getBaseType() + parameters.toString(); + } + + /** + * Return a String representation of this object + * without the parameter list. + */ + public String getBaseType() { + return primaryType + "/" + subType; + } + + /** + * Returns <code>true</code> if the primary type and the + * subtype of this object are the same as the specified + * <code>type</code>; otherwise returns <code>false</code>. + * + * @param type the type to compare to <code>this</code>'s type + * @return <code>true</code> if the primary type and the + * subtype of this object are the same as the + * specified <code>type</code>; otherwise returns + * <code>false</code> + */ + public boolean match(MimeType type) { + if (type == null) + return false; + return primaryType.equals(type.getPrimaryType()) + && (subType.equals("*") + || type.getSubType().equals("*") + || (subType.equals(type.getSubType()))); + } + + /** + * Returns <code>true</code> if the primary type and the + * subtype of this object are the same as the content type + * described in <code>rawdata</code>; otherwise returns + * <code>false</code>. + * + * @param rawdata the raw data to be examined + * @return <code>true</code> if the primary type and the + * subtype of this object are the same as the content type + * described in <code>rawdata</code>; otherwise returns + * <code>false</code>; if <code>rawdata</code> is + * <code>null</code>, returns <code>false</code> + */ + public boolean match(String rawdata) throws MimeTypeParseException { + if (rawdata == null) + return false; + return match(new MimeType(rawdata)); + } + + /** + * The object implements the writeExternal method to save its contents + * by calling the methods of DataOutput for its primitive values or + * calling the writeObject method of ObjectOutput for objects, strings + * and arrays. + * @exception IOException Includes any I/O exceptions that may occur + */ + public void writeExternal(ObjectOutput out) throws IOException { + String s = toString(); // contains ASCII chars only + // one-to-one correspondence between ASCII char and byte in UTF string + if (s.length() <= 65535) { // 65535 is max length of UTF string + out.writeUTF(s); + } else { + out.writeByte(0); + out.writeByte(0); + out.writeInt(s.length()); + out.write(s.getBytes()); + } + } + + /** + * The object implements the readExternal method to restore its + * contents by calling the methods of DataInput for primitive + * types and readObject for objects, strings and arrays. The + * readExternal method must read the values in the same sequence + * and with the same types as were written by writeExternal. + * @exception ClassNotFoundException If the class for an object being + * restored cannot be found. + */ + public void readExternal(ObjectInput in) throws IOException, +ClassNotFoundException { + String s = in.readUTF(); + if (s == null || s.length() == 0) { // long mime type + byte[] ba = new byte[in.readInt()]; + in.readFully(ba); + s = new String(ba); + } + try { + parse(s); + } catch(MimeTypeParseException e) { + throw new IOException(e.toString()); + } + } + + /** + * Returns a clone of this object. + * @return a clone of this object + */ + + public Object clone() { + MimeType newObj = null; + try { + newObj = (MimeType)super.clone(); + } catch (CloneNotSupportedException cannotHappen) { + } + newObj.parameters = (MimeTypeParameterList)parameters.clone(); + return newObj; + } + + private String primaryType; + private String subType; + private MimeTypeParameterList parameters; + + // below here be scary parsing related things + + /** + * Determines whether or not a given character belongs to a legal token. + */ + private static boolean isTokenChar(char c) { + return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0); + } + + /** + * Determines whether or not a given string is a legal token. + * + * @throws NullPointerException if <code>s</code> is null + */ + private boolean isValidToken(String s) { + int len = s.length(); + if(len > 0) { + for (int i = 0; i < len; ++i) { + char c = s.charAt(i); + if (!isTokenChar(c)) { + return false; + } + } + return true; + } else { + return false; + } + } + + /** + * A string that holds all the special chars. + */ + + private static final String TSPECIALS = "()<>@,;:\\\"/[]?="; + +} // class MimeType
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/MimeTypeParameterList.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,404 @@ +/* + * Copyright (c) 1997, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.awt.datatransfer; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + + +/** + * An object that encapsulates the parameter list of a MimeType + * as defined in RFC 2045 and 2046. + * + * @author jeff.dunn@eng.sun.com + */ +class MimeTypeParameterList implements Cloneable { + + /** + * Default constructor. + */ + public MimeTypeParameterList() { + parameters = new Hashtable<>(); + } + + public MimeTypeParameterList(String rawdata) + throws MimeTypeParseException + { + parameters = new Hashtable<>(); + + // now parse rawdata + parse(rawdata); + } + + public int hashCode() { + int code = Integer.MAX_VALUE/45; // "random" value for empty lists + String paramName = null; + Enumeration<String> enum_ = this.getNames(); + + while (enum_.hasMoreElements()) { + paramName = enum_.nextElement(); + code += paramName.hashCode(); + code += this.get(paramName).hashCode(); + } + + return code; + } // hashCode() + + /** + * Two parameter lists are considered equal if they have exactly + * the same set of parameter names and associated values. The + * order of the parameters is not considered. + */ + public boolean equals(Object thatObject) { + //System.out.println("MimeTypeParameterList.equals("+this+","+thatObject+")"); + if (!(thatObject instanceof MimeTypeParameterList)) { + return false; + } + MimeTypeParameterList that = (MimeTypeParameterList)thatObject; + if (this.size() != that.size()) { + return false; + } + String name = null; + String thisValue = null; + String thatValue = null; + Set<Map.Entry<String, String>> entries = parameters.entrySet(); + Iterator<Map.Entry<String, String>> iterator = entries.iterator(); + Map.Entry<String, String> entry = null; + while (iterator.hasNext()) { + entry = iterator.next(); + name = entry.getKey(); + thisValue = entry.getValue(); + thatValue = that.parameters.get(name); + if ((thisValue == null) || (thatValue == null)) { + // both null -> equal, only one null -> not equal + if (thisValue != thatValue) { + return false; + } + } else if (!thisValue.equals(thatValue)) { + return false; + } + } // while iterator + + return true; + } // equals() + + /** + * A routine for parsing the parameter list out of a String. + */ + protected void parse(String rawdata) throws MimeTypeParseException { + int length = rawdata.length(); + if(length > 0) { + int currentIndex = skipWhiteSpace(rawdata, 0); + int lastIndex = 0; + + if(currentIndex < length) { + char currentChar = rawdata.charAt(currentIndex); + while ((currentIndex < length) && (currentChar == ';')) { + String name; + String value; + boolean foundit; + + // eat the ';' + ++currentIndex; + + // now parse the parameter name + + // skip whitespace + currentIndex = skipWhiteSpace(rawdata, currentIndex); + + if(currentIndex < length) { + // find the end of the token char run + lastIndex = currentIndex; + currentChar = rawdata.charAt(currentIndex); + while((currentIndex < length) && isTokenChar(currentChar)) { + ++currentIndex; + currentChar = rawdata.charAt(currentIndex); + } + name = rawdata.substring(lastIndex, currentIndex).toLowerCase(); + + // now parse the '=' that separates the name from the value + + // skip whitespace + currentIndex = skipWhiteSpace(rawdata, currentIndex); + + if((currentIndex < length) && (rawdata.charAt(currentIndex) == '=')) { + // eat it and parse the parameter value + ++currentIndex; + + // skip whitespace + currentIndex = skipWhiteSpace(rawdata, currentIndex); + + if(currentIndex < length) { + // now find out whether or not we have a quoted value + currentChar = rawdata.charAt(currentIndex); + if(currentChar == '"') { + // yup it's quoted so eat it and capture the quoted string + ++currentIndex; + lastIndex = currentIndex; + + if(currentIndex < length) { + // find the next unescaped quote + foundit = false; + while((currentIndex < length) && !foundit) { + currentChar = rawdata.charAt(currentIndex); + if(currentChar == '\\') { + // found an escape sequence so pass this and the next character + currentIndex += 2; + } else if(currentChar == '"') { + // found it! + foundit = true; + } else { + ++currentIndex; + } + } + if(currentChar == '"') { + value = unquote(rawdata.substring(lastIndex, currentIndex)); + // eat the quote + ++currentIndex; + } else { + throw new MimeTypeParseException("Encountered unterminated quoted parameter value."); + } + } else { + throw new MimeTypeParseException("Encountered unterminated quoted parameter value."); + } + } else if(isTokenChar(currentChar)) { + // nope it's an ordinary token so it ends with a non-token char + lastIndex = currentIndex; + foundit = false; + while((currentIndex < length) && !foundit) { + currentChar = rawdata.charAt(currentIndex); + + if(isTokenChar(currentChar)) { + ++currentIndex; + } else { + foundit = true; + } + } + value = rawdata.substring(lastIndex, currentIndex); + } else { + // it ain't a value + throw new MimeTypeParseException("Unexpected character encountered at index " + currentIndex); + } + + // now put the data into the hashtable + parameters.put(name, value); + } else { + throw new MimeTypeParseException("Couldn't find a value for parameter named " + name); + } + } else { + throw new MimeTypeParseException("Couldn't find the '=' that separates a parameter name from its value."); + } + } else { + throw new MimeTypeParseException("Couldn't find parameter name"); + } + + // setup the next iteration + currentIndex = skipWhiteSpace(rawdata, currentIndex); + if(currentIndex < length) { + currentChar = rawdata.charAt(currentIndex); + } + } + if(currentIndex < length) { + throw new MimeTypeParseException("More characters encountered in input than expected."); + } + } + } + } + + /** + * return the number of name-value pairs in this list. + */ + public int size() { + return parameters.size(); + } + + /** + * Determine whether or not this list is empty. + */ + public boolean isEmpty() { + return parameters.isEmpty(); + } + + /** + * Retrieve the value associated with the given name, or null if there + * is no current association. + */ + public String get(String name) { + return parameters.get(name.trim().toLowerCase()); + } + + /** + * Set the value to be associated with the given name, replacing + * any previous association. + */ + public void set(String name, String value) { + parameters.put(name.trim().toLowerCase(), value); + } + + /** + * Remove any value associated with the given name. + */ + public void remove(String name) { + parameters.remove(name.trim().toLowerCase()); + } + + /** + * Retrieve an enumeration of all the names in this list. + */ + public Enumeration<String> getNames() { + return parameters.keys(); + } + + public String toString() { + // Heuristic: 8 characters per field + StringBuilder buffer = new StringBuilder(parameters.size() * 16); + + Enumeration<String> keys = parameters.keys(); + while(keys.hasMoreElements()) + { + buffer.append("; "); + + String key = keys.nextElement(); + buffer.append(key); + buffer.append('='); + buffer.append(quote(parameters.get(key))); + } + + return buffer.toString(); + } + + /** + * @return a clone of this object + */ + @SuppressWarnings("unchecked") // Cast from clone + public Object clone() { + MimeTypeParameterList newObj = null; + try { + newObj = (MimeTypeParameterList)super.clone(); + } catch (CloneNotSupportedException cannotHappen) { + } + newObj.parameters = (Hashtable<String, String>)parameters.clone(); + return newObj; + } + + private Hashtable<String, String> parameters; + + // below here be scary parsing related things + + /** + * Determine whether or not a given character belongs to a legal token. + */ + private static boolean isTokenChar(char c) { + return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0); + } + + /** + * return the index of the first non white space character in + * rawdata at or after index i. + */ + private static int skipWhiteSpace(String rawdata, int i) { + int length = rawdata.length(); + if (i < length) { + char c = rawdata.charAt(i); + while ((i < length) && Character.isWhitespace(c)) { + ++i; + c = rawdata.charAt(i); + } + } + + return i; + } + + /** + * A routine that knows how and when to quote and escape the given value. + */ + private static String quote(String value) { + boolean needsQuotes = false; + + // check to see if we actually have to quote this thing + int length = value.length(); + for(int i = 0; (i < length) && !needsQuotes; ++i) { + needsQuotes = !isTokenChar(value.charAt(i)); + } + + if(needsQuotes) { + StringBuilder buffer = new StringBuilder((int)(length * 1.5)); + + // add the initial quote + buffer.append('"'); + + // add the properly escaped text + for(int i = 0; i < length; ++i) { + char c = value.charAt(i); + if((c == '\\') || (c == '"')) { + buffer.append('\\'); + } + buffer.append(c); + } + + // add the closing quote + buffer.append('"'); + + return buffer.toString(); + } + else + { + return value; + } + } + + /** + * A routine that knows how to strip the quotes and escape sequences from the given value. + */ + private static String unquote(String value) { + int valueLength = value.length(); + StringBuilder buffer = new StringBuilder(valueLength); + + boolean escaped = false; + for(int i = 0; i < valueLength; ++i) { + char currentChar = value.charAt(i); + if(!escaped && (currentChar != '\\')) { + buffer.append(currentChar); + } else if(escaped) { + buffer.append(currentChar); + escaped = false; + } else { + escaped = true; + } + } + + return buffer.toString(); + } + + /** + * A string that holds all the special chars. + */ + private static final String TSPECIALS = "()<>@,;:\\\"/[]?="; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/MimeTypeParseException.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997, 2006, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.awt.datatransfer; + + +/** + * A class to encapsulate MimeType parsing related exceptions + * + * @serial exclude + * @since 1.3 + */ +public class MimeTypeParseException extends Exception { + + // use serialVersionUID from JDK 1.2.2 for interoperability + private static final long serialVersionUID = -5604407764691570741L; + + /** + * Constructs a MimeTypeParseException with no specified detail message. + */ + public MimeTypeParseException() { + super(); + } + + /** + * Constructs a MimeTypeParseException with the specified detail message. + * + * @param s the detail message. + */ + public MimeTypeParseException(String s) { + super(s); + } +} // class MimeTypeParseException
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/StringSelection.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 1996, 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.awt.datatransfer; + +import java.io.*; + + +/** + * A <code>Transferable</code> which implements the capability required + * to transfer a <code>String</code>. + * + * This <code>Transferable</code> properly supports + * <code>DataFlavor.stringFlavor</code> + * and all equivalent flavors. Support for + * <code>DataFlavor.plainTextFlavor</code> + * and all equivalent flavors is <b>deprecated</b>. No other + * <code>DataFlavor</code>s are supported. + * + * @see java.awt.datatransfer.DataFlavor#stringFlavor + * @see java.awt.datatransfer.DataFlavor#plainTextFlavor + */ +public class StringSelection implements Transferable, ClipboardOwner { + + private static final int STRING = 0; + private static final int PLAIN_TEXT = 1; + + @SuppressWarnings("deprecation") + private static final DataFlavor[] flavors = { + DataFlavor.stringFlavor, + DataFlavor.plainTextFlavor // deprecated + }; + + private String data; + + /** + * Creates a <code>Transferable</code> capable of transferring + * the specified <code>String</code>. + * @param data the string to be transferred + */ + public StringSelection(String data) { + this.data = data; + } + + /** + * Returns an array of flavors in which this <code>Transferable</code> + * can provide the data. <code>DataFlavor.stringFlavor</code> + * is properly supported. + * Support for <code>DataFlavor.plainTextFlavor</code> is + * <b>deprecated</b>. + * + * @return an array of length two, whose elements are <code>DataFlavor. + * stringFlavor</code> and <code>DataFlavor.plainTextFlavor</code> + */ + public DataFlavor[] getTransferDataFlavors() { + // returning flavors itself would allow client code to modify + // our internal behavior + return flavors.clone(); + } + + /** + * Returns whether the requested flavor is supported by this + * <code>Transferable</code>. + * + * @param flavor the requested flavor for the data + * @return true if <code>flavor</code> is equal to + * <code>DataFlavor.stringFlavor</code> or + * <code>DataFlavor.plainTextFlavor</code>; false if <code>flavor</code> + * is not one of the above flavors + * @throws NullPointerException if flavor is <code>null</code> + */ + public boolean isDataFlavorSupported(DataFlavor flavor) { + // JCK Test StringSelection0003: if 'flavor' is null, throw NPE + for (int i = 0; i < flavors.length; i++) { + if (flavor.equals(flavors[i])) { + return true; + } + } + return false; + } + + /** + * Returns the <code>Transferable</code>'s data in the requested + * <code>DataFlavor</code> if possible. If the desired flavor is + * <code>DataFlavor.stringFlavor</code>, or an equivalent flavor, + * the <code>String</code> representing the selection is + * returned. If the desired flavor is + * <code>DataFlavor.plainTextFlavor</code>, + * or an equivalent flavor, a <code>Reader</code> is returned. + * <b>Note:</b> The behavior of this method for + * <code>DataFlavor.plainTextFlavor</code> + * and equivalent <code>DataFlavor</code>s is inconsistent with the + * definition of <code>DataFlavor.plainTextFlavor</code>. + * + * @param flavor the requested flavor for the data + * @return the data in the requested flavor, as outlined above + * @throws UnsupportedFlavorException if the requested data flavor is + * not equivalent to either <code>DataFlavor.stringFlavor</code> + * or <code>DataFlavor.plainTextFlavor</code> + * @throws IOException if an IOException occurs while retrieving the data. + * By default, StringSelection never throws this exception, but a + * subclass may. + * @throws NullPointerException if flavor is <code>null</code> + * @see java.io.Reader + */ + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException + { + // JCK Test StringSelection0007: if 'flavor' is null, throw NPE + if (flavor.equals(flavors[STRING])) { + return (Object)data; + } else if (flavor.equals(flavors[PLAIN_TEXT])) { + return new StringReader(data == null ? "" : data); + } else { + throw new UnsupportedFlavorException(flavor); + } + } + + public void lostOwnership(Clipboard clipboard, Transferable contents) { + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/SystemFlavorMap.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,1094 @@ +/* + * Copyright (c) 1997, 2015, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.awt.datatransfer; + +import sun.datatransfer.DataFlavorUtil; +import sun.datatransfer.DesktopDatatransferService; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.ref.SoftReference; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * The SystemFlavorMap is a configurable map between "natives" (Strings), which + * correspond to platform-specific data formats, and "flavors" (DataFlavors), + * which correspond to platform-independent MIME types. This mapping is used + * by the data transfer subsystem to transfer data between Java and native + * applications, and between Java applications in separate VMs. + * + * @since 1.2 + */ +public final class SystemFlavorMap implements FlavorMap, FlavorTable { + + /** + * Constant prefix used to tag Java types converted to native platform + * type. + */ + private static String JavaMIME = "JAVA_DATAFLAVOR:"; + + private static final Object FLAVOR_MAP_KEY = new Object(); + + /** + * The list of valid, decoded text flavor representation classes, in order + * from best to worst. + */ + private static final String[] UNICODE_TEXT_CLASSES = { + "java.io.Reader", "java.lang.String", "java.nio.CharBuffer", "\"[C\"" + }; + + /** + * The list of valid, encoded text flavor representation classes, in order + * from best to worst. + */ + private static final String[] ENCODED_TEXT_CLASSES = { + "java.io.InputStream", "java.nio.ByteBuffer", "\"[B\"" + }; + + /** + * A String representing text/plain MIME type. + */ + 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"; + + /** + * Maps native Strings to Lists of DataFlavors (or base type Strings for + * text DataFlavors). + * Do not use the field directly, use getNativeToFlavor() instead. + */ + private final Map<String, LinkedHashSet<DataFlavor>> nativeToFlavor = new HashMap<>(); + + /** + * Accessor to nativeToFlavor map. Since we use lazy initialization we must + * use this accessor instead of direct access to the field which may not be + * initialized yet. This method will initialize the field if needed. + * + * @return nativeToFlavor + */ + private Map<String, LinkedHashSet<DataFlavor>> getNativeToFlavor() { + if (!isMapInitialized) { + initSystemFlavorMap(); + } + return nativeToFlavor; + } + + /** + * Maps DataFlavors (or base type Strings for text DataFlavors) to Lists of + * native Strings. + * Do not use the field directly, use getFlavorToNative() instead. + */ + private final Map<DataFlavor, LinkedHashSet<String>> flavorToNative = new HashMap<>(); + + /** + * Accessor to flavorToNative map. Since we use lazy initialization we must + * use this accessor instead of direct access to the field which may not be + * initialized yet. This method will initialize the field if needed. + * + * @return flavorToNative + */ + private synchronized Map<DataFlavor, LinkedHashSet<String>> getFlavorToNative() { + if (!isMapInitialized) { + initSystemFlavorMap(); + } + return flavorToNative; + } + + /** + * Maps a text DataFlavor primary mime-type to the native. Used only to store + * standard mappings registered in the flavormap.properties + * Do not use this field directly, use getTextTypeToNative() instead. + */ + private Map<String, LinkedHashSet<String>> textTypeToNative = new HashMap<>(); + + /** + * Shows if the object has been initialized. + */ + private boolean isMapInitialized = false; + + /** + * An accessor to textTypeToNative map. Since we use lazy initialization we + * must use this accessor instead of direct access to the field which may not + * be initialized yet. This method will initialize the field if needed. + * + * @return textTypeToNative + */ + private synchronized Map<String, LinkedHashSet<String>> getTextTypeToNative() { + if (!isMapInitialized) { + initSystemFlavorMap(); + // From this point the map should not be modified + textTypeToNative = Collections.unmodifiableMap(textTypeToNative); + } + return textTypeToNative; + } + + /** + * Caches the result of getNativesForFlavor(). Maps DataFlavors to + * SoftReferences which reference LinkedHashSet of String natives. + */ + private final SoftCache<DataFlavor, String> nativesForFlavorCache = new SoftCache<>(); + + /** + * Caches the result getFlavorsForNative(). Maps String natives to + * SoftReferences which reference LinkedHashSet of DataFlavors. + */ + private final SoftCache<String, DataFlavor> flavorsForNativeCache = new SoftCache<>(); + + /** + * Dynamic mapping generation used for text mappings should not be applied + * to the DataFlavors and String natives for which the mappings have been + * explicitly specified with setFlavorsForNative() or + * setNativesForFlavor(). This keeps all such keys. + */ + private Set<Object> disabledMappingGenerationKeys = new HashSet<>(); + + /** + * Returns the default FlavorMap for this thread's ClassLoader. + * + * @return the default FlavorMap for this thread's ClassLoader + */ + public static FlavorMap getDefaultFlavorMap() { + return DataFlavorUtil.getDesktopService().getFlavorMap(SystemFlavorMap::new); + } + + private SystemFlavorMap() { + } + + /** + * Initializes a SystemFlavorMap by reading flavormap.properties + * For thread-safety must be called under lock on this. + */ + private void initSystemFlavorMap() { + if (isMapInitialized) { + return; + } + isMapInitialized = true; + + InputStream is = SystemFlavorMap.class.getResourceAsStream("/sun/datatransfer/resources/flavormap.properties"); + if (is == null) { + throw new InternalError("Default flavor mapping not found"); + } + + try (InputStreamReader isr = new InputStreamReader(is); + BufferedReader reader = new BufferedReader(isr)) { + String line; + while ((line = reader.readLine()) != null) { + line = line.trim(); + if (line.startsWith("#") || line.isEmpty()) continue; + while (line.endsWith("\\")) { + line = line.substring(0, line.length() - 1) + reader.readLine().trim(); + } + int delimiterPosition = line.indexOf('='); + String key = line.substring(0, delimiterPosition).replace("\\ ", " "); + String[] values = line.substring(delimiterPosition + 1, line.length()).split(","); + for (String value : values) { + try { + value = loadConvert(value); + MimeType mime = new MimeType(value); + if ("text".equals(mime.getPrimaryType())) { + String charset = mime.getParameter("charset"); + if (DataFlavorUtil.doesSubtypeSupportCharset(mime.getSubType(), charset)) + { + // We need to store the charset and eoln + // parameters, if any, so that the + // DataTransferer will have this information + // for conversion into the native format. + DesktopDatatransferService desktopService = + DataFlavorUtil.getDesktopService(); + if (desktopService.isDesktopPresent()) { + desktopService.registerTextFlavorProperties( + key, charset, + mime.getParameter("eoln"), + mime.getParameter("terminators")); + } + } + + // But don't store any of these parameters in the + // DataFlavor itself for any text natives (even + // non-charset ones). The SystemFlavorMap will + // synthesize the appropriate mappings later. + mime.removeParameter("charset"); + mime.removeParameter("class"); + mime.removeParameter("eoln"); + mime.removeParameter("terminators"); + value = mime.toString(); + } + } catch (MimeTypeParseException e) { + e.printStackTrace(); + continue; + } + + DataFlavor flavor; + try { + flavor = new DataFlavor(value); + } catch (Exception e) { + try { + flavor = new DataFlavor(value, null); + } catch (Exception ee) { + ee.printStackTrace(); + continue; + } + } + + final LinkedHashSet<DataFlavor> dfs = new LinkedHashSet<>(); + dfs.add(flavor); + + if ("text".equals(flavor.getPrimaryType())) { + dfs.addAll(convertMimeTypeToDataFlavors(value)); + store(flavor.mimeType.getBaseType(), key, getTextTypeToNative()); + } + + for (DataFlavor df : dfs) { + store(df, key, getFlavorToNative()); + store(key, df, getNativeToFlavor()); + } + } + } + } catch (IOException e) { + throw new InternalError("Error reading default flavor mapping", e); + } + } + + // Copied from java.util.Properties + private static String loadConvert(String theString) { + char aChar; + int len = theString.length(); + StringBuilder outBuffer = new StringBuilder(len); + + for (int x = 0; x < len; ) { + aChar = theString.charAt(x++); + if (aChar == '\\') { + aChar = theString.charAt(x++); + if (aChar == 'u') { + // Read the xxxx + int value = 0; + for (int i = 0; i < 4; i++) { + aChar = theString.charAt(x++); + switch (aChar) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + value = (value << 4) + aChar - '0'; + break; + } + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': { + value = (value << 4) + 10 + aChar - 'a'; + break; + } + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': { + value = (value << 4) + 10 + aChar - 'A'; + break; + } + default: { + throw new IllegalArgumentException( + "Malformed \\uxxxx encoding."); + } + } + } + outBuffer.append((char)value); + } else { + if (aChar == 't') { + aChar = '\t'; + } else if (aChar == 'r') { + aChar = '\r'; + } else if (aChar == 'n') { + aChar = '\n'; + } else if (aChar == 'f') { + aChar = '\f'; + } + outBuffer.append(aChar); + } + } else { + outBuffer.append(aChar); + } + } + return outBuffer.toString(); + } + + /** + * Stores the listed object under the specified hash key in map. Unlike a + * standard map, the listed object will not replace any object already at + * the appropriate Map location, but rather will be appended to a List + * stored in that location. + */ + private <H, L> void store(H hashed, L listed, Map<H, LinkedHashSet<L>> map) { + LinkedHashSet<L> list = map.get(hashed); + if (list == null) { + list = new LinkedHashSet<>(1); + map.put(hashed, list); + } + if (!list.contains(listed)) { + list.add(listed); + } + } + + /** + * Semantically equivalent to 'nativeToFlavor.get(nat)'. This method + * handles the case where 'nat' is not found in 'nativeToFlavor'. In that + * case, a new DataFlavor is synthesized, stored, and returned, if and + * only if the specified native is encoded as a Java MIME type. + */ + private LinkedHashSet<DataFlavor> nativeToFlavorLookup(String nat) { + LinkedHashSet<DataFlavor> flavors = getNativeToFlavor().get(nat); + + if (nat != null && !disabledMappingGenerationKeys.contains(nat)) { + DesktopDatatransferService desktopService = DataFlavorUtil.getDesktopService(); + if (desktopService.isDesktopPresent()) { + LinkedHashSet<DataFlavor> platformFlavors = + desktopService.getPlatformMappingsForNative(nat); + if (!platformFlavors.isEmpty()) { + if (flavors != null) { + // Prepending the platform-specific mappings ensures + // that the flavors added with + // addFlavorForUnencodedNative() are at the end of + // list. + platformFlavors.addAll(flavors); + } + flavors = platformFlavors; + } + } + } + + if (flavors == null && isJavaMIMEType(nat)) { + String decoded = decodeJavaMIMEType(nat); + DataFlavor flavor = null; + + try { + flavor = new DataFlavor(decoded); + } catch (Exception e) { + System.err.println("Exception \"" + e.getClass().getName() + + ": " + e.getMessage() + + "\"while constructing DataFlavor for: " + + decoded); + } + + if (flavor != null) { + flavors = new LinkedHashSet<>(1); + getNativeToFlavor().put(nat, flavors); + flavors.add(flavor); + flavorsForNativeCache.remove(nat); + + LinkedHashSet<String> natives = getFlavorToNative().get(flavor); + if (natives == null) { + natives = new LinkedHashSet<>(1); + getFlavorToNative().put(flavor, natives); + } + natives.add(nat); + nativesForFlavorCache.remove(flavor); + } + } + + return (flavors != null) ? flavors : new LinkedHashSet<>(0); + } + + /** + * Semantically equivalent to 'flavorToNative.get(flav)'. This method + * handles the case where 'flav' is not found in 'flavorToNative' depending + * on the value of passes 'synthesize' parameter. If 'synthesize' is + * SYNTHESIZE_IF_NOT_FOUND a native is synthesized, stored, and returned by + * encoding the DataFlavor's MIME type. Otherwise an empty List is returned + * and 'flavorToNative' remains unaffected. + */ + private LinkedHashSet<String> flavorToNativeLookup(final DataFlavor flav, + final boolean synthesize) { + + LinkedHashSet<String> natives = getFlavorToNative().get(flav); + + if (flav != null && !disabledMappingGenerationKeys.contains(flav)) { + DesktopDatatransferService desktopService = DataFlavorUtil.getDesktopService(); + if (desktopService.isDesktopPresent()) { + LinkedHashSet<String> platformNatives = + desktopService.getPlatformMappingsForFlavor(flav); + if (!platformNatives.isEmpty()) { + if (natives != null) { + // Prepend the platform-specific mappings to ensure + // that the natives added with + // addUnencodedNativeForFlavor() are at the end of + // list. + platformNatives.addAll(natives); + } + natives = platformNatives; + } + } + } + + if (natives == null) { + if (synthesize) { + String encoded = encodeDataFlavor(flav); + natives = new LinkedHashSet<>(1); + getFlavorToNative().put(flav, natives); + natives.add(encoded); + + LinkedHashSet<DataFlavor> flavors = getNativeToFlavor().get(encoded); + if (flavors == null) { + flavors = new LinkedHashSet<>(1); + getNativeToFlavor().put(encoded, flavors); + } + flavors.add(flav); + + nativesForFlavorCache.remove(flav); + flavorsForNativeCache.remove(encoded); + } else { + natives = new LinkedHashSet<>(0); + } + } + + return new LinkedHashSet<>(natives); + } + + /** + * Returns a <code>List</code> of <code>String</code> natives to which the + * specified <code>DataFlavor</code> can be translated by the data transfer + * subsystem. The <code>List</code> will be sorted from best native to + * worst. That is, the first native will best reflect data in the specified + * flavor to the underlying native platform. + * <p> + * If the specified <code>DataFlavor</code> is previously unknown to the + * data transfer subsystem and the data transfer subsystem is unable to + * translate this <code>DataFlavor</code> to any existing native, then + * invoking this method will establish a + * mapping in both directions between the specified <code>DataFlavor</code> + * and an encoded version of its MIME type as its native. + * + * @param flav the <code>DataFlavor</code> whose corresponding natives + * should be returned. If <code>null</code> is specified, all + * natives currently known to the data transfer subsystem are + * returned in a non-deterministic order. + * @return a <code>java.util.List</code> of <code>java.lang.String</code> + * objects which are platform-specific representations of platform- + * specific data formats + * + * @see #encodeDataFlavor + * @since 1.4 + */ + @Override + public synchronized List<String> getNativesForFlavor(DataFlavor flav) { + LinkedHashSet<String> retval = nativesForFlavorCache.check(flav); + if (retval != null) { + return new ArrayList<>(retval); + } + + if (flav == null) { + retval = new LinkedHashSet<>(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. + retval = flavorToNativeLookup(flav, false); + } else if (DataFlavorUtil.isFlavorCharsetTextType(flav)) { + retval = new LinkedHashSet<>(0); + + // For text/* flavors, flavor-to-native mappings specified in + // flavormap.properties are stored per flavor's base type. + if ("text".equals(flav.getPrimaryType())) { + LinkedHashSet<String> textTypeNatives = + getTextTypeToNative().get(flav.mimeType.getBaseType()); + if (textTypeNatives != null) { + retval.addAll(textTypeNatives); + } + } + + // Also include text/plain natives, but don't duplicate Strings + LinkedHashSet<String> textTypeNatives = + getTextTypeToNative().get(TEXT_PLAIN_BASE_TYPE); + if (textTypeNatives != null) { + retval.addAll(textTypeNatives); + } + + if (retval.isEmpty()) { + retval = flavorToNativeLookup(flav, true); + } else { + // In this branch it is guaranteed that natives explicitly + // listed for flav's MIME type were added with + // addUnencodedNativeForFlavor(), so they have lower priority. + retval.addAll(flavorToNativeLookup(flav, false)); + } + } else if (DataFlavorUtil.isFlavorNoncharsetTextType(flav)) { + retval = getTextTypeToNative().get(flav.mimeType.getBaseType()); + + if (retval == null || retval.isEmpty()) { + retval = flavorToNativeLookup(flav, true); + } else { + // In this branch it is guaranteed that natives explicitly + // listed for flav's MIME type were added with + // addUnencodedNativeForFlavor(), so they have lower priority. + retval.addAll(flavorToNativeLookup(flav, false)); + } + } else { + retval = flavorToNativeLookup(flav, true); + } + + nativesForFlavorCache.put(flav, retval); + // Create a copy, because client code can modify the returned list. + return new ArrayList<>(retval); + } + + /** + * Returns a <code>List</code> of <code>DataFlavor</code>s to which the + * specified <code>String</code> native can be translated by the data + * transfer subsystem. The <code>List</code> will be sorted from best + * <code>DataFlavor</code> to worst. That is, the first + * <code>DataFlavor</code> will best reflect data in the specified + * native to a Java application. + * <p> + * If the specified native is previously unknown to the data transfer + * subsystem, and that native has been properly encoded, then invoking this + * method will establish a mapping in both directions between the specified + * native and a <code>DataFlavor</code> whose MIME type is a decoded + * version of the native. + * <p> + * If the specified native is not a properly encoded native and the + * mappings for this native have not been altered with + * <code>setFlavorsForNative</code>, then the contents of the + * <code>List</code> is platform dependent, but <code>null</code> + * cannot be returned. + * + * @param nat the native whose corresponding <code>DataFlavor</code>s + * should be returned. If <code>null</code> is specified, all + * <code>DataFlavor</code>s currently known to the data transfer + * subsystem are returned in a non-deterministic order. + * @return a <code>java.util.List</code> of <code>DataFlavor</code> + * objects into which platform-specific data in the specified, + * platform-specific native can be translated + * + * @see #encodeJavaMIMEType + * @since 1.4 + */ + @Override + public synchronized List<DataFlavor> getFlavorsForNative(String nat) { + LinkedHashSet<DataFlavor> returnValue = flavorsForNativeCache.check(nat); + if (returnValue != null) { + return new ArrayList<>(returnValue); + } else { + returnValue = new LinkedHashSet<>(); + } + + if (nat == null) { + for (String n : getNativesForFlavor(null)) { + returnValue.addAll(getFlavorsForNative(n)); + } + } else { + final LinkedHashSet<DataFlavor> flavors = nativeToFlavorLookup(nat); + if (disabledMappingGenerationKeys.contains(nat)) { + return new ArrayList<>(flavors); + } + + final LinkedHashSet<DataFlavor> flavorsWithSynthesized = + nativeToFlavorLookup(nat); + + for (DataFlavor df : flavorsWithSynthesized) { + returnValue.add(df); + if ("text".equals(df.getPrimaryType())) { + String baseType = df.mimeType.getBaseType(); + returnValue.addAll(convertMimeTypeToDataFlavors(baseType)); + } + } + } + flavorsForNativeCache.put(nat, returnValue); + return new ArrayList<>(returnValue); + } + + @SuppressWarnings("deprecation") + private static Set<DataFlavor> convertMimeTypeToDataFlavors( + final String baseType) { + + final Set<DataFlavor> returnValue = new LinkedHashSet<>(); + + String subType = null; + + try { + final MimeType mimeType = new MimeType(baseType); + subType = mimeType.getSubType(); + } catch (MimeTypeParseException mtpe) { + // Cannot happen, since we checked all mappings + // on load from flavormap.properties. + } + + if (DataFlavorUtil.doesSubtypeSupportCharset(subType, null)) { + if (TEXT_PLAIN_BASE_TYPE.equals(baseType)) + { + returnValue.add(DataFlavor.stringFlavor); + } + + 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(mt); + } catch (ClassNotFoundException cannotHappen) { + } + returnValue.add(toAdd); + } + } + + for (String charset : DataFlavorUtil.standardEncodings()) { + + 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 (df.equals(DataFlavor.plainTextFlavor)) { + df = DataFlavor.plainTextFlavor; + } + } catch (ClassNotFoundException cannotHappen) { + } + + returnValue.add(df); + } + } + } + + if (TEXT_PLAIN_BASE_TYPE.equals(baseType)) + { + returnValue.add(DataFlavor.plainTextFlavor); + } + } else { + // Non-charset text natives should be treated as + // opaque, 8-bit data in any of its various + // representations. + for (String encodedTextClassName : ENCODED_TEXT_CLASSES) { + DataFlavor toAdd = null; + try { + toAdd = new DataFlavor(baseType + + ";class=" + encodedTextClassName); + } catch (ClassNotFoundException cannotHappen) { + } + returnValue.add(toAdd); + } + } + return returnValue; + } + + private static final String [] htmlDocumentTypes = + 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 : htmlDocumentTypes) { + returnValues.add(mimeType + ";document=" + documentType); + } + } else { + returnValues.add(mimeType); + } + + return returnValues; + } + + /** + * Returns a <code>Map</code> of the specified <code>DataFlavor</code>s to + * their most preferred <code>String</code> native. Each native value will + * be the same as the first native in the List returned by + * <code>getNativesForFlavor</code> for the specified flavor. + * <p> + * If a specified <code>DataFlavor</code> is previously unknown to the + * data transfer subsystem, then invoking this method will establish a + * mapping in both directions between the specified <code>DataFlavor</code> + * and an encoded version of its MIME type as its native. + * + * @param flavors an array of <code>DataFlavor</code>s which will be the + * key set of the returned <code>Map</code>. If <code>null</code> is + * specified, a mapping of all <code>DataFlavor</code>s known to the + * data transfer subsystem to their most preferred + * <code>String</code> natives will be returned. + * @return a <code>java.util.Map</code> of <code>DataFlavor</code>s to + * <code>String</code> natives + * + * @see #getNativesForFlavor + * @see #encodeDataFlavor + */ + @Override + public synchronized Map<DataFlavor,String> getNativesForFlavors(DataFlavor[] flavors) + { + // Use getNativesForFlavor to generate extra natives for text flavors + // and stringFlavor + + if (flavors == null) { + List<DataFlavor> flavor_list = getFlavorsForNative(null); + flavors = new DataFlavor[flavor_list.size()]; + flavor_list.toArray(flavors); + } + + Map<DataFlavor, String> retval = new HashMap<>(flavors.length, 1.0f); + for (DataFlavor flavor : flavors) { + List<String> natives = getNativesForFlavor(flavor); + String nat = (natives.isEmpty()) ? null : natives.get(0); + retval.put(flavor, nat); + } + + return retval; + } + + /** + * Returns a <code>Map</code> of the specified <code>String</code> natives + * to their most preferred <code>DataFlavor</code>. Each + * <code>DataFlavor</code> value will be the same as the first + * <code>DataFlavor</code> in the List returned by + * <code>getFlavorsForNative</code> for the specified native. + * <p> + * If a specified native is previously unknown to the data transfer + * subsystem, and that native has been properly encoded, then invoking this + * method will establish a mapping in both directions between the specified + * native and a <code>DataFlavor</code> whose MIME type is a decoded + * version of the native. + * + * @param natives an array of <code>String</code>s which will be the + * key set of the returned <code>Map</code>. If <code>null</code> is + * specified, a mapping of all supported <code>String</code> natives + * to their most preferred <code>DataFlavor</code>s will be + * returned. + * @return a <code>java.util.Map</code> of <code>String</code> natives to + * <code>DataFlavor</code>s + * + * @see #getFlavorsForNative + * @see #encodeJavaMIMEType + */ + @Override + public synchronized Map<String,DataFlavor> getFlavorsForNatives(String[] natives) + { + // Use getFlavorsForNative to generate extra flavors for text natives + if (natives == null) { + List<String> nativesList = getNativesForFlavor(null); + natives = new String[nativesList.size()]; + nativesList.toArray(natives); + } + + Map<String, DataFlavor> retval = new HashMap<>(natives.length, 1.0f); + for (String aNative : natives) { + List<DataFlavor> flavors = getFlavorsForNative(aNative); + DataFlavor flav = (flavors.isEmpty())? null : flavors.get(0); + retval.put(aNative, flav); + } + return retval; + } + + /** + * Adds a mapping from the specified <code>DataFlavor</code> (and all + * <code>DataFlavor</code>s equal to the specified <code>DataFlavor</code>) + * to the specified <code>String</code> native. + * Unlike <code>getNativesForFlavor</code>, the mapping will only be + * established in one direction, and the native will not be encoded. To + * establish a two-way mapping, call + * <code>addFlavorForUnencodedNative</code> as well. The new mapping will + * be of lower priority than any existing mapping. + * This method has no effect if a mapping from the specified or equal + * <code>DataFlavor</code> to the specified <code>String</code> native + * already exists. + * + * @param flav the <code>DataFlavor</code> key for the mapping + * @param nat the <code>String</code> native value for the mapping + * @throws NullPointerException if flav or nat is <code>null</code> + * + * @see #addFlavorForUnencodedNative + * @since 1.4 + */ + public synchronized void addUnencodedNativeForFlavor(DataFlavor flav, + String nat) { + Objects.requireNonNull(nat, "Null native not permitted"); + Objects.requireNonNull(flav, "Null flavor not permitted"); + + LinkedHashSet<String> natives = getFlavorToNative().get(flav); + if (natives == null) { + natives = new LinkedHashSet<>(1); + getFlavorToNative().put(flav, natives); + } + natives.add(nat); + nativesForFlavorCache.remove(flav); + } + + /** + * Discards the current mappings for the specified <code>DataFlavor</code> + * and all <code>DataFlavor</code>s equal to the specified + * <code>DataFlavor</code>, and creates new mappings to the + * specified <code>String</code> natives. + * Unlike <code>getNativesForFlavor</code>, the mappings will only be + * established in one direction, and the natives will not be encoded. To + * establish two-way mappings, call <code>setFlavorsForNative</code> + * as well. The first native in the array will represent the highest + * priority mapping. Subsequent natives will represent mappings of + * decreasing priority. + * <p> + * If the array contains several elements that reference equal + * <code>String</code> natives, this method will establish new mappings + * for the first of those elements and ignore the rest of them. + * <p> + * It is recommended that client code not reset mappings established by the + * data transfer subsystem. This method should only be used for + * application-level mappings. + * + * @param flav the <code>DataFlavor</code> key for the mappings + * @param natives the <code>String</code> native values for the mappings + * @throws NullPointerException if flav or natives is <code>null</code> + * or if natives contains <code>null</code> elements + * + * @see #setFlavorsForNative + * @since 1.4 + */ + public synchronized void setNativesForFlavor(DataFlavor flav, + String[] natives) { + Objects.requireNonNull(natives, "Null natives not permitted"); + Objects.requireNonNull(flav, "Null flavors not permitted"); + + getFlavorToNative().remove(flav); + for (String aNative : natives) { + addUnencodedNativeForFlavor(flav, aNative); + } + disabledMappingGenerationKeys.add(flav); + nativesForFlavorCache.remove(flav); + } + + /** + * Adds a mapping from a single <code>String</code> native to a single + * <code>DataFlavor</code>. Unlike <code>getFlavorsForNative</code>, the + * mapping will only be established in one direction, and the native will + * not be encoded. To establish a two-way mapping, call + * <code>addUnencodedNativeForFlavor</code> as well. The new mapping will + * be of lower priority than any existing mapping. + * This method has no effect if a mapping from the specified + * <code>String</code> native to the specified or equal + * <code>DataFlavor</code> already exists. + * + * @param nat the <code>String</code> native key for the mapping + * @param flav the <code>DataFlavor</code> value for the mapping + * @throws NullPointerException if nat or flav is <code>null</code> + * + * @see #addUnencodedNativeForFlavor + * @since 1.4 + */ + public synchronized void addFlavorForUnencodedNative(String nat, + DataFlavor flav) { + Objects.requireNonNull(nat, "Null native not permitted"); + Objects.requireNonNull(flav, "Null flavor not permitted"); + + LinkedHashSet<DataFlavor> flavors = getNativeToFlavor().get(nat); + if (flavors == null) { + flavors = new LinkedHashSet<>(1); + getNativeToFlavor().put(nat, flavors); + } + flavors.add(flav); + flavorsForNativeCache.remove(nat); + } + + /** + * Discards the current mappings for the specified <code>String</code> + * native, and creates new mappings to the specified + * <code>DataFlavor</code>s. Unlike <code>getFlavorsForNative</code>, the + * mappings will only be established in one direction, and the natives need + * not be encoded. To establish two-way mappings, call + * <code>setNativesForFlavor</code> as well. The first + * <code>DataFlavor</code> in the array will represent the highest priority + * mapping. Subsequent <code>DataFlavor</code>s will represent mappings of + * decreasing priority. + * <p> + * If the array contains several elements that reference equal + * <code>DataFlavor</code>s, this method will establish new mappings + * for the first of those elements and ignore the rest of them. + * <p> + * It is recommended that client code not reset mappings established by the + * data transfer subsystem. This method should only be used for + * application-level mappings. + * + * @param nat the <code>String</code> native key for the mappings + * @param flavors the <code>DataFlavor</code> values for the mappings + * @throws NullPointerException if nat or flavors is <code>null</code> + * or if flavors contains <code>null</code> elements + * + * @see #setNativesForFlavor + * @since 1.4 + */ + public synchronized void setFlavorsForNative(String nat, + DataFlavor[] flavors) { + Objects.requireNonNull(nat, "Null native not permitted"); + Objects.requireNonNull(flavors, "Null flavors not permitted"); + + getNativeToFlavor().remove(nat); + for (DataFlavor flavor : flavors) { + addFlavorForUnencodedNative(nat, flavor); + } + disabledMappingGenerationKeys.add(nat); + flavorsForNativeCache.remove(nat); + } + + /** + * Encodes a MIME type for use as a <code>String</code> native. The format + * of an encoded representation of a MIME type is implementation-dependent. + * The only restrictions are: + * <ul> + * <li>The encoded representation is <code>null</code> if and only if the + * MIME type <code>String</code> is <code>null</code>.</li> + * <li>The encoded representations for two non-<code>null</code> MIME type + * <code>String</code>s are equal if and only if these <code>String</code>s + * are equal according to <code>String.equals(Object)</code>.</li> + * </ul> + * <p> + * The reference implementation of this method returns the specified MIME + * type <code>String</code> prefixed with <code>JAVA_DATAFLAVOR:</code>. + * + * @param mimeType the MIME type to encode + * @return the encoded <code>String</code>, or <code>null</code> if + * mimeType is <code>null</code> + */ + public static String encodeJavaMIMEType(String mimeType) { + return (mimeType != null) + ? JavaMIME + mimeType + : null; + } + + /** + * Encodes a <code>DataFlavor</code> for use as a <code>String</code> + * native. The format of an encoded <code>DataFlavor</code> is + * implementation-dependent. The only restrictions are: + * <ul> + * <li>The encoded representation is <code>null</code> if and only if the + * specified <code>DataFlavor</code> is <code>null</code> or its MIME type + * <code>String</code> is <code>null</code>.</li> + * <li>The encoded representations for two non-<code>null</code> + * <code>DataFlavor</code>s with non-<code>null</code> MIME type + * <code>String</code>s are equal if and only if the MIME type + * <code>String</code>s of these <code>DataFlavor</code>s are equal + * according to <code>String.equals(Object)</code>.</li> + * </ul> + * <p> + * The reference implementation of this method returns the MIME type + * <code>String</code> of the specified <code>DataFlavor</code> prefixed + * with <code>JAVA_DATAFLAVOR:</code>. + * + * @param flav the <code>DataFlavor</code> to encode + * @return the encoded <code>String</code>, or <code>null</code> if + * flav is <code>null</code> or has a <code>null</code> MIME type + */ + public static String encodeDataFlavor(DataFlavor flav) { + return (flav != null) + ? SystemFlavorMap.encodeJavaMIMEType(flav.getMimeType()) + : null; + } + + /** + * Returns whether the specified <code>String</code> is an encoded Java + * MIME type. + * + * @param str the <code>String</code> to test + * @return <code>true</code> if the <code>String</code> is encoded; + * <code>false</code> otherwise + */ + public static boolean isJavaMIMEType(String str) { + return (str != null && str.startsWith(JavaMIME, 0)); + } + + /** + * Decodes a <code>String</code> native for use as a Java MIME type. + * + * @param nat the <code>String</code> to decode + * @return the decoded Java MIME type, or <code>null</code> if nat is not + * an encoded <code>String</code> native + */ + public static String decodeJavaMIMEType(String nat) { + return (isJavaMIMEType(nat)) + ? nat.substring(JavaMIME.length(), nat.length()).trim() + : null; + } + + /** + * Decodes a <code>String</code> native for use as a + * <code>DataFlavor</code>. + * + * @param nat the <code>String</code> to decode + * @return the decoded <code>DataFlavor</code>, or <code>null</code> if + * nat is not an encoded <code>String</code> native + * @throws ClassNotFoundException if the class of the data flavor + * is not loaded + */ + public static DataFlavor decodeDataFlavor(String nat) + throws ClassNotFoundException + { + String retval_str = SystemFlavorMap.decodeJavaMIMEType(nat); + return (retval_str != null) + ? new DataFlavor(retval_str) + : null; + } + + private static final class SoftCache<K, V> { + Map<K, SoftReference<LinkedHashSet<V>>> cache; + + public void put(K key, LinkedHashSet<V> value) { + if (cache == null) { + cache = new HashMap<>(1); + } + cache.put(key, new SoftReference<>(value)); + } + + public void remove(K key) { + if (cache == null) return; + cache.remove(null); + cache.remove(key); + } + + public LinkedHashSet<V> check(K key) { + if (cache == null) return null; + SoftReference<LinkedHashSet<V>> ref = cache.get(key); + if (ref != null) { + return ref.get(); + } + return null; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/Transferable.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1996, 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.awt.datatransfer; + +import java.io.IOException; + +/** + * Defines the interface for classes that can be used to provide data + * for a transfer operation. + * <p> + * For information on using data transfer with Swing, see + * <a href="http://docs.oracle.com/javase/tutorial/uiswing/dnd/index.html"> + * How to Use Drag and Drop and Data Transfer</a>, + * a section in <em>The Java Tutorial</em>, for more information. + * + * @author Amy Fowler + */ + +public interface Transferable { + + /** + * Returns an array of DataFlavor objects indicating the flavors the data + * can be provided in. The array should be ordered according to preference + * for providing the data (from most richly descriptive to least descriptive). + * @return an array of data flavors in which this data can be transferred + */ + public DataFlavor[] getTransferDataFlavors(); + + /** + * Returns whether or not the specified data flavor is supported for + * this object. + * @param flavor the requested flavor for the data + * @return boolean indicating whether or not the data flavor is supported + */ + public boolean isDataFlavorSupported(DataFlavor flavor); + + /** + * Returns an object which represents the data to be transferred. The class + * of the object returned is defined by the representation class of the flavor. + * + * @param flavor the requested flavor for the data + * @return an object which represents the data to be transferred + * @see DataFlavor#getRepresentationClass + * @exception IOException if the data is no longer available + * in the requested flavor. + * @exception UnsupportedFlavorException if the requested data flavor is + * not supported. + */ + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/UnsupportedFlavorException.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1996, 2000, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.awt.datatransfer; + +/** + * Signals that the requested data is not supported in this flavor. + * @see Transferable#getTransferData + * + * @author Amy Fowler + */ +public class UnsupportedFlavorException extends Exception { + + /* + * JDK 1.1 serialVersionUID + */ + private static final long serialVersionUID = 5383814944251665601L; + + /** + * Constructs an UnsupportedFlavorException. + * + * @param flavor the flavor object which caused the exception. May + * be <code>null</code>. + */ + public UnsupportedFlavorException(DataFlavor flavor) { + super((flavor != null) ? flavor.getHumanPresentableName() : null); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/package.html Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,64 @@ +<!-- + Copyright (c) 1998, 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. Oracle designates this + particular file as subject to the "Classpath" exception as provided + by Oracle in the LICENSE file that accompanied this code. + + 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. +--> + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<html> +<head><title></title></head> +<body bgcolor="white"> + +Provides interfaces and classes for transferring data +between and within applications. It defines the notion of a +"transferable" object, which is an object capable of being +transferred between or within applications. An object identifies +itself as being transferable by implementing the Transferable +interface. +<p> +It also provides a clipboard mechanism, which is an object that +temporarily holds a transferable object that can be transferred +between or within an application. The clipboard is typically used +for copy and paste operations. Although it is possible to create +a clipboard to use within an application, most applications will +use the system clipboard to ensure the data can be transferred +across applications running on the platform. + +<!-- +<h2>Package Specification</h2> + +##### FILL IN ANY SPECS NEEDED BY JAVA COMPATIBILITY KIT ##### +<ul> + <li><a href="">##### REFER TO ANY FRAMEMAKER SPECIFICATION HERE #####</a> +</ul> + +<h2>Related Documentation</h2> + +For overviews, tutorials, examples, guides, and tool documentation, please see: +<ul> + <li><a href="">##### REFER TO NON-SPEC DOCUMENTATION HERE #####</a> +</ul> +--> + +@since 1.1 +</body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/sun/datatransfer/DataFlavorUtil.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,841 @@ +/* + * Copyright (c) 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.datatransfer; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.FlavorMap; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.StandardCharsets; +import java.nio.charset.UnsupportedCharsetException; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.function.Supplier; + + +/** + * Utility class with different datatransfer helper functions + * + * @see 1.9 + */ +public class DataFlavorUtil { + + private DataFlavorUtil() { + // Avoid instantiation + } + + private static Comparator<String> getCharsetComparator() { + return CharsetComparator.INSTANCE; + } + + public static Comparator<DataFlavor> getDataFlavorComparator() { + return DataFlavorComparator.INSTANCE; + } + + public static Comparator<Long> getIndexOrderComparator(Map<Long, Integer> indexMap) { + return new IndexOrderComparator(indexMap); + } + + public static Comparator<DataFlavor> getTextFlavorComparator() { + return TextFlavorComparator.INSTANCE; + } + + /** + * Tracks whether a particular text/* MIME type supports the charset + * parameter. The Map is initialized with all of the standard MIME types + * listed in the DataFlavor.selectBestTextFlavor method comment. Additional + * entries may be added during the life of the JRE for text/<other> types. + */ + private static final Map<String, Boolean> textMIMESubtypeCharsetSupport; + + static { + Map<String, Boolean> tempMap = new HashMap<>(17); + tempMap.put("sgml", Boolean.TRUE); + tempMap.put("xml", Boolean.TRUE); + tempMap.put("html", Boolean.TRUE); + tempMap.put("enriched", Boolean.TRUE); + tempMap.put("richtext", Boolean.TRUE); + tempMap.put("uri-list", Boolean.TRUE); + tempMap.put("directory", Boolean.TRUE); + tempMap.put("css", Boolean.TRUE); + tempMap.put("calendar", Boolean.TRUE); + tempMap.put("plain", Boolean.TRUE); + tempMap.put("rtf", Boolean.FALSE); + tempMap.put("tab-separated-values", Boolean.FALSE); + tempMap.put("t140", Boolean.FALSE); + tempMap.put("rfc822-headers", Boolean.FALSE); + tempMap.put("parityfec", Boolean.FALSE); + textMIMESubtypeCharsetSupport = Collections.synchronizedMap(tempMap); + } + + /** + * Lazy initialization of Standard Encodings. + */ + private static class StandardEncodingsHolder { + private static final SortedSet<String> standardEncodings = load(); + + private static SortedSet<String> load() { + final SortedSet<String> tempSet = new TreeSet<>(getCharsetComparator().reversed()); + tempSet.add("US-ASCII"); + tempSet.add("ISO-8859-1"); + tempSet.add("UTF-8"); + tempSet.add("UTF-16BE"); + tempSet.add("UTF-16LE"); + tempSet.add("UTF-16"); + tempSet.add(Charset.defaultCharset().name()); + return Collections.unmodifiableSortedSet(tempSet); + } + } + + /** + * Returns a {@code SortedSet} of Strings which are a total order of the standard + * character sets supported by the JRE. The ordering follows the same principles as + * {@link java.awt.datatransfer.DataFlavor#selectBestTextFlavor(java.awt.datatransfer.DataFlavor[])}. + * So as to avoid loading all available character converters, optional, non-standard, + * character sets are not included. + */ + public static Set<String> standardEncodings() { + return StandardEncodingsHolder.standardEncodings; + } + + /** + * Converts an arbitrary text encoding to its canonical name. + */ + public static String canonicalName(String encoding) { + if (encoding == null) { + return null; + } + try { + return Charset.forName(encoding).name(); + } catch (IllegalCharsetNameException icne) { + return encoding; + } catch (UnsupportedCharsetException uce) { + return encoding; + } + } + + /** + * Tests only whether the flavor's MIME type supports the charset + * parameter. Must only be called for flavors with a primary type of + * "text". + */ + public static boolean doesSubtypeSupportCharset(DataFlavor flavor) { + String subType = flavor.getSubType(); + if (subType == null) { + return false; + } + + Boolean support = textMIMESubtypeCharsetSupport.get(subType); + + if (support != null) { + return support; + } + + boolean ret_val = (flavor.getParameter("charset") != null); + textMIMESubtypeCharsetSupport.put(subType, ret_val); + return ret_val; + } + public static boolean doesSubtypeSupportCharset(String subType, + String charset) + { + Boolean support = textMIMESubtypeCharsetSupport.get(subType); + + if (support != null) { + return support; + } + + boolean ret_val = (charset != null); + textMIMESubtypeCharsetSupport.put(subType, ret_val); + return ret_val; + } + + + /** + * Returns whether this flavor is a text type which supports the + * 'charset' parameter. + */ + public static boolean isFlavorCharsetTextType(DataFlavor flavor) { + // Although stringFlavor doesn't actually support the charset + // parameter (because its primary MIME type is not "text"), it should + // be treated as though it does. stringFlavor is semantically + // equivalent to "text/plain" data. + if (DataFlavor.stringFlavor.equals(flavor)) { + return true; + } + + if (!"text".equals(flavor.getPrimaryType()) || + !doesSubtypeSupportCharset(flavor)) + { + return false; + } + + Class<?> rep_class = flavor.getRepresentationClass(); + + if (flavor.isRepresentationClassReader() || + String.class.equals(rep_class) || + flavor.isRepresentationClassCharBuffer() || + char[].class.equals(rep_class)) + { + return true; + } + + if (!(flavor.isRepresentationClassInputStream() || + flavor.isRepresentationClassByteBuffer() || + byte[].class.equals(rep_class))) { + return false; + } + + String charset = flavor.getParameter("charset"); + + // null equals default encoding which is always supported + return (charset == null) || isEncodingSupported(charset); + } + + /** + * Returns whether this flavor is a text type which does not support the + * 'charset' parameter. + */ + public static boolean isFlavorNoncharsetTextType(DataFlavor flavor) { + if (!"text".equals(flavor.getPrimaryType()) || doesSubtypeSupportCharset(flavor)) { + return false; + } + + return (flavor.isRepresentationClassInputStream() || + flavor.isRepresentationClassByteBuffer() || + byte[].class.equals(flavor.getRepresentationClass())); + } + + /** + * If the specified flavor is a text flavor which supports the "charset" + * parameter, then this method returns that parameter, or the default + * charset if no such parameter was specified at construction. For non- + * text DataFlavors, and for non-charset text flavors, this method returns + * null. + */ + public static String getTextCharset(DataFlavor flavor) { + if (!isFlavorCharsetTextType(flavor)) { + return null; + } + + String encoding = flavor.getParameter("charset"); + + return (encoding != null) ? encoding : Charset.defaultCharset().name(); + } + + /** + * Determines whether this JRE can both encode and decode text in the + * specified encoding. + */ + private static boolean isEncodingSupported(String encoding) { + if (encoding == null) { + return false; + } + try { + return Charset.isSupported(encoding); + } catch (IllegalCharsetNameException icne) { + return false; + } + } + + /** + * Helper method to compare two objects by their Integer indices in the + * given map. If the map doesn't contain an entry for either of the + * objects, the fallback index will be used for the object instead. + * + * @param indexMap the map which maps objects into Integer indexes. + * @param obj1 the first object to be compared. + * @param obj2 the second object to be compared. + * @param fallbackIndex the Integer to be used as a fallback index. + * @return a negative integer, zero, or a positive integer as the + * first object is mapped to a less, equal to, or greater + * index than the second. + */ + static <T> int compareIndices(Map<T, Integer> indexMap, + T obj1, T obj2, + Integer fallbackIndex) { + Integer index1 = indexMap.getOrDefault(obj1, fallbackIndex); + Integer index2 = indexMap.getOrDefault(obj2, fallbackIndex); + return index1.compareTo(index2); + } + + /** + * An IndexedComparator which compares two String charsets. The comparison + * follows the rules outlined in DataFlavor.selectBestTextFlavor. In order + * to ensure that non-Unicode, non-ASCII, non-default charsets are sorted + * in alphabetical order, charsets are not automatically converted to their + * canonical forms. + */ + private static class CharsetComparator implements Comparator<String> { + static final CharsetComparator INSTANCE = new CharsetComparator(); + + private static final Map<String, Integer> charsets; + + private static final Integer DEFAULT_CHARSET_INDEX = 2; + private static final Integer OTHER_CHARSET_INDEX = 1; + private static final Integer WORST_CHARSET_INDEX = 0; + private static final Integer UNSUPPORTED_CHARSET_INDEX = Integer.MIN_VALUE; + + private static final String UNSUPPORTED_CHARSET = "UNSUPPORTED"; + + static { + Map<String, Integer> charsetsMap = new HashMap<>(8, 1.0f); + + // we prefer Unicode charsets + charsetsMap.put(canonicalName("UTF-16LE"), 4); + charsetsMap.put(canonicalName("UTF-16BE"), 5); + charsetsMap.put(canonicalName("UTF-8"), 6); + charsetsMap.put(canonicalName("UTF-16"), 7); + + // US-ASCII is the worst charset supported + charsetsMap.put(canonicalName("US-ASCII"), WORST_CHARSET_INDEX); + + charsetsMap.putIfAbsent(Charset.defaultCharset().name(), DEFAULT_CHARSET_INDEX); + + charsetsMap.put(UNSUPPORTED_CHARSET, UNSUPPORTED_CHARSET_INDEX); + + charsets = Collections.unmodifiableMap(charsetsMap); + } + + /** + * Compares charsets. Returns a negative integer, zero, or a positive + * integer as the first charset is worse than, equal to, or better than + * the second. + * <p> + * Charsets are ordered according to the following rules: + * <ul> + * <li>All unsupported charsets are equal. + * <li>Any unsupported charset is worse than any supported charset. + * <li>Unicode charsets, such as "UTF-16", "UTF-8", "UTF-16BE" and + * "UTF-16LE", are considered best. + * <li>After them, platform default charset is selected. + * <li>"US-ASCII" is the worst of supported charsets. + * <li>For all other supported charsets, the lexicographically less + * one is considered the better. + * </ul> + * + * @param charset1 the first charset to be compared + * @param charset2 the second charset to be compared. + * @return a negative integer, zero, or a positive integer as the + * first argument is worse, equal to, or better than the + * second. + */ + public int compare(String charset1, String charset2) { + charset1 = getEncoding(charset1); + charset2 = getEncoding(charset2); + + int comp = compareIndices(charsets, charset1, charset2, OTHER_CHARSET_INDEX); + + if (comp == 0) { + return charset2.compareTo(charset1); + } + + return comp; + } + + /** + * Returns encoding for the specified charset according to the + * following rules: + * <ul> + * <li>If the charset is <code>null</code>, then <code>null</code> will + * be returned. + * <li>Iff the charset specifies an encoding unsupported by this JRE, + * <code>UNSUPPORTED_CHARSET</code> will be returned. + * <li>If the charset specifies an alias name, the corresponding + * canonical name will be returned iff the charset is a known + * Unicode, ASCII, or default charset. + * </ul> + * + * @param charset the charset. + * @return an encoding for this charset. + */ + static String getEncoding(String charset) { + if (charset == null) { + return null; + } else if (!isEncodingSupported(charset)) { + return UNSUPPORTED_CHARSET; + } else { + // Only convert to canonical form if the charset is one + // of the charsets explicitly listed in the known charsets + // map. This will happen only for Unicode, ASCII, or default + // charsets. + String canonicalName = canonicalName(charset); + return (charsets.containsKey(canonicalName)) + ? canonicalName + : charset; + } + } + } + + /** + * An IndexedComparator which compares two DataFlavors. For text flavors, + * the comparison follows the rules outlined in + * DataFlavor.selectBestTextFlavor. For non-text flavors, unknown + * application MIME types are preferred, followed by known + * application/x-java-* MIME types. Unknown application types are preferred + * because if the user provides his own data flavor, it will likely be the + * most descriptive one. For flavors which are otherwise equal, the + * flavors' string representation are compared in the alphabetical order. + */ + private static class DataFlavorComparator implements Comparator<DataFlavor> { + + static final DataFlavorComparator INSTANCE = new DataFlavorComparator(); + + private static final Map<String, Integer> exactTypes; + private static final Map<String, Integer> primaryTypes; + private static final Map<Class<?>, Integer> nonTextRepresentations; + private static final Map<String, Integer> textTypes; + private static final Map<Class<?>, Integer> decodedTextRepresentations; + private static final Map<Class<?>, Integer> encodedTextRepresentations; + + private static final Integer UNKNOWN_OBJECT_LOSES = Integer.MIN_VALUE; + private static final Integer UNKNOWN_OBJECT_WINS = Integer.MAX_VALUE; + + static { + { + Map<String, Integer> exactTypesMap = new HashMap<>(4, 1.0f); + + // application/x-java-* MIME types + exactTypesMap.put("application/x-java-file-list", 0); + exactTypesMap.put("application/x-java-serialized-object", 1); + exactTypesMap.put("application/x-java-jvm-local-objectref", 2); + exactTypesMap.put("application/x-java-remote-object", 3); + + exactTypes = Collections.unmodifiableMap(exactTypesMap); + } + + { + Map<String, Integer> primaryTypesMap = new HashMap<>(1, 1.0f); + + primaryTypesMap.put("application", 0); + + primaryTypes = Collections.unmodifiableMap(primaryTypesMap); + } + + { + Map<Class<?>, Integer> nonTextRepresentationsMap = new HashMap<>(3, 1.0f); + + nonTextRepresentationsMap.put(java.io.InputStream.class, 0); + nonTextRepresentationsMap.put(java.io.Serializable.class, 1); + + nonTextRepresentationsMap.put(RMI.remoteClass(), 2); + + nonTextRepresentations = Collections.unmodifiableMap(nonTextRepresentationsMap); + } + + { + Map<String, Integer> textTypesMap = new HashMap<>(16, 1.0f); + + // plain text + textTypesMap.put("text/plain", 0); + + // stringFlavor + textTypesMap.put("application/x-java-serialized-object", 1); + + // misc + textTypesMap.put("text/calendar", 2); + textTypesMap.put("text/css", 3); + textTypesMap.put("text/directory", 4); + textTypesMap.put("text/parityfec", 5); + textTypesMap.put("text/rfc822-headers", 6); + textTypesMap.put("text/t140", 7); + textTypesMap.put("text/tab-separated-values", 8); + textTypesMap.put("text/uri-list", 9); + + // enriched + textTypesMap.put("text/richtext", 10); + textTypesMap.put("text/enriched", 11); + textTypesMap.put("text/rtf", 12); + + // markup + textTypesMap.put("text/html", 13); + textTypesMap.put("text/xml", 14); + textTypesMap.put("text/sgml", 15); + + textTypes = Collections.unmodifiableMap(textTypesMap); + } + + { + Map<Class<?>, Integer> decodedTextRepresentationsMap = new HashMap<>(4, 1.0f); + + decodedTextRepresentationsMap.put(char[].class, 0); + decodedTextRepresentationsMap.put(CharBuffer.class, 1); + decodedTextRepresentationsMap.put(String.class, 2); + decodedTextRepresentationsMap.put(Reader.class, 3); + + decodedTextRepresentations = + Collections.unmodifiableMap(decodedTextRepresentationsMap); + } + + { + Map<Class<?>, Integer> encodedTextRepresentationsMap = new HashMap<>(3, 1.0f); + + encodedTextRepresentationsMap.put(byte[].class, 0); + encodedTextRepresentationsMap.put(ByteBuffer.class, 1); + encodedTextRepresentationsMap.put(InputStream.class, 2); + + encodedTextRepresentations = + Collections.unmodifiableMap(encodedTextRepresentationsMap); + } + } + + + public int compare(DataFlavor flavor1, DataFlavor flavor2) { + if (flavor1.equals(flavor2)) { + return 0; + } + + int comp; + + String primaryType1 = flavor1.getPrimaryType(); + String subType1 = flavor1.getSubType(); + String mimeType1 = primaryType1 + "/" + subType1; + Class<?> class1 = flavor1.getRepresentationClass(); + + String primaryType2 = flavor2.getPrimaryType(); + String subType2 = flavor2.getSubType(); + String mimeType2 = primaryType2 + "/" + subType2; + Class<?> class2 = flavor2.getRepresentationClass(); + + if (flavor1.isFlavorTextType() && flavor2.isFlavorTextType()) { + // First, compare MIME types + comp = compareIndices(textTypes, mimeType1, mimeType2, UNKNOWN_OBJECT_LOSES); + if (comp != 0) { + return comp; + } + + // Only need to test one flavor because they both have the + // same MIME type. Also don't need to worry about accidentally + // passing stringFlavor because either + // 1. Both flavors are stringFlavor, in which case the + // equality test at the top of the function succeeded. + // 2. Only one flavor is stringFlavor, in which case the MIME + // type comparison returned a non-zero value. + if (doesSubtypeSupportCharset(flavor1)) { + // Next, prefer the decoded text representations of Reader, + // String, CharBuffer, and [C, in that order. + comp = compareIndices(decodedTextRepresentations, class1, + class2, UNKNOWN_OBJECT_LOSES); + if (comp != 0) { + return comp; + } + + // Next, compare charsets + comp = CharsetComparator.INSTANCE.compare(getTextCharset(flavor1), + getTextCharset(flavor2)); + if (comp != 0) { + return comp; + } + } + + // Finally, prefer the encoded text representations of + // InputStream, ByteBuffer, and [B, in that order. + comp = compareIndices(encodedTextRepresentations, class1, + class2, UNKNOWN_OBJECT_LOSES); + if (comp != 0) { + return comp; + } + } else { + // First, prefer application types. + comp = compareIndices(primaryTypes, primaryType1, primaryType2, + UNKNOWN_OBJECT_LOSES); + if (comp != 0) { + return comp; + } + + // Next prefer text types + if (flavor1.isFlavorTextType()) { + return 1; + } + + if (flavor2.isFlavorTextType()) { + return -1; + } + + // Next, look for application/x-java-* types. Prefer unknown + // MIME types because if the user provides his own data flavor, + // it will likely be the most descriptive one. + comp = compareIndices(exactTypes, mimeType1, mimeType2, + UNKNOWN_OBJECT_WINS); + if (comp != 0) { + return comp; + } + + // Finally, prefer the representation classes of Remote, + // Serializable, and InputStream, in that order. + comp = compareIndices(nonTextRepresentations, class1, class2, + UNKNOWN_OBJECT_LOSES); + if (comp != 0) { + return comp; + } + } + + // The flavours are not equal but still not distinguishable. + // Compare String representations in alphabetical order + return flavor1.getMimeType().compareTo(flavor2.getMimeType()); + } + } + + /* + * Given the Map that maps objects to Integer indices and a boolean value, + * this Comparator imposes a direct or reverse order on set of objects. + * <p> + * If the specified boolean value is SELECT_BEST, the Comparator imposes the + * direct index-based order: an object A is greater than an object B if and + * only if the index of A is greater than the index of B. An object that + * doesn't have an associated index is less or equal than any other object. + * <p> + * If the specified boolean value is SELECT_WORST, the Comparator imposes the + * reverse index-based order: an object A is greater than an object B if and + * only if A is less than B with the direct index-based order. + */ + private static class IndexOrderComparator implements Comparator<Long> { + private final Map<Long, Integer> indexMap; + private static final Integer FALLBACK_INDEX = Integer.MIN_VALUE; + + public IndexOrderComparator(Map<Long, Integer> indexMap) { + this.indexMap = indexMap; + } + + public int compare(Long obj1, Long obj2) { + return compareIndices(indexMap, obj1, obj2, FALLBACK_INDEX); + } + } + + private static class TextFlavorComparator extends DataFlavorComparator { + + static final TextFlavorComparator INSTANCE = new TextFlavorComparator(); + /** + * Compares two <code>DataFlavor</code> objects. Returns a negative + * integer, zero, or a positive integer as the first + * <code>DataFlavor</code> is worse than, equal to, or better than the + * second. + * <p> + * <code>DataFlavor</code>s are ordered according to the rules outlined + * for <code>selectBestTextFlavor</code>. + * + * @param flavor1 the first <code>DataFlavor</code> to be compared + * @param flavor2 the second <code>DataFlavor</code> to be compared + * @return a negative integer, zero, or a positive integer as the first + * argument is worse, equal to, or better than the second + * @throws ClassCastException if either of the arguments is not an + * instance of <code>DataFlavor</code> + * @throws NullPointerException if either of the arguments is + * <code>null</code> + * + * @see java.awt.datatransfer.DataFlavor#selectBestTextFlavor + */ + public int compare(DataFlavor flavor1, DataFlavor flavor2) { + if (flavor1.isFlavorTextType()) { + if (flavor2.isFlavorTextType()) { + return super.compare(flavor1, flavor2); + } else { + return 1; + } + } else if (flavor2.isFlavorTextType()) { + return -1; + } else { + return 0; + } + } + } + + /** + * A fallback implementation of {@link sun.datatransfer.DesktopDatatransferService} + * used if there is no desktop. + */ + private static final class DefaultDesktopDatatransferService implements DesktopDatatransferService { + static final DesktopDatatransferService INSTANCE = getDesktopService(); + + private static DesktopDatatransferService getDesktopService() { + ServiceLoader<DesktopDatatransferService> loader = + ServiceLoader.load(DesktopDatatransferService.class, null); + Iterator<DesktopDatatransferService> iterator = loader.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } else { + return new DefaultDesktopDatatransferService(); + } + } + + /** + * System singleton FlavorTable. + * Only used if there is no desktop + * to provide an appropriate FlavorMap. + */ + private volatile FlavorMap flavorMap; + + @Override + public void invokeOnEventThread(Runnable r) { + r.run(); + } + + @Override + public String getDefaultUnicodeEncoding() { + return StandardCharsets.UTF_8.name(); + } + + @Override + public FlavorMap getFlavorMap(Supplier<FlavorMap> supplier) { + FlavorMap map = flavorMap; + if (map == null) { + synchronized (this) { + map = flavorMap; + if (map == null) { + flavorMap = map = supplier.get(); + } + } + } + return map; + } + + @Override + public boolean isDesktopPresent() { + return false; + } + + @Override + public LinkedHashSet<DataFlavor> getPlatformMappingsForNative(String nat) { + return new LinkedHashSet<>(); + } + + @Override + public LinkedHashSet<String> getPlatformMappingsForFlavor(DataFlavor df) { + return new LinkedHashSet<>(); + } + + @Override + public void registerTextFlavorProperties(String nat, String charset, + String eoln, String terminators) { + // Not needed if desktop module is absent + } + } + + public static DesktopDatatransferService getDesktopService() { + return DefaultDesktopDatatransferService.INSTANCE; + } + + /** + * A class that provides access to java.rmi.Remote and java.rmi.MarshalledObject + * without creating a static dependency. + */ + public static class RMI { + private static final Class<?> remoteClass = getClass("java.rmi.Remote"); + private static final Class<?> marshallObjectClass = getClass("java.rmi.MarshalledObject"); + private static final Constructor<?> marshallCtor = getConstructor(marshallObjectClass, Object.class); + private static final Method marshallGet = getMethod(marshallObjectClass, "get"); + + private static Class<?> getClass(String name) { + try { + return Class.forName(name, true, null); + } catch (ClassNotFoundException e) { + return null; + } + } + + private static Constructor<?> getConstructor(Class<?> c, Class<?>... types) { + try { + return (c == null) ? null : c.getDeclaredConstructor(types); + } catch (NoSuchMethodException x) { + throw new AssertionError(x); + } + } + + private static Method getMethod(Class<?> c, String name, Class<?>... types) { + try { + return (c == null) ? null : c.getMethod(name, types); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + /** + * Returns java.rmi.Remote.class if RMI is present; otherwise {@code null}. + */ + static Class<?> remoteClass() { + return remoteClass; + } + + /** + * Returns {@code true} if the given class is java.rmi.Remote. + */ + public static boolean isRemote(Class<?> c) { + return (remoteClass != null) && remoteClass.isAssignableFrom(c); + } + + /** + * Returns a new MarshalledObject containing the serialized representation + * of the given object. + */ + public static Object newMarshalledObject(Object obj) throws IOException { + try { + return marshallCtor == null ? null : marshallCtor.newInstance(obj); + } catch (InstantiationException | IllegalAccessException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + if (cause instanceof IOException) + throw (IOException) cause; + throw new AssertionError(x); + } + } + + /** + * Returns a new copy of the contained marshalled object. + */ + public static Object getMarshalledObject(Object obj) + throws IOException, ClassNotFoundException { + try { + return marshallGet == null ? null : marshallGet.invoke(obj); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + if (cause instanceof IOException) + throw (IOException) cause; + if (cause instanceof ClassNotFoundException) + throw (ClassNotFoundException) cause; + throw new AssertionError(x); + } + } + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/share/classes/sun/datatransfer/DesktopDatatransferService.java Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.datatransfer; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.FlavorMap; +import java.util.LinkedHashSet; +import java.util.function.Supplier; + +/** + * Contains services which desktop provides to the datatransfer system + * to enrich it's functionality + * + * @author Petr Pchelko + * @since 1.9 + */ +public interface DesktopDatatransferService { + + /** + * If desktop is present - invokes a {@code Runnable} on + * the event dispatch thread. Otherwise invokes a {@code run()} + * method directly. + * + * @param r a {@code Runnable} to invoke + */ + void invokeOnEventThread(Runnable r); + + /** + * Get a platform-dependent default unicode encoding to use in + * datatransfer system. + * + * @return default unicode encoding + */ + String getDefaultUnicodeEncoding(); + + /** + * Takes an appropriate {@code FlavorMap} from the desktop. + * If no appropriate table is found - uses a provided supplier to + * instantiate a table. If the desktop is absent - creates and returns + * a system singleton. + * + * @param supplier a constructor that should be used to create a new instance of + * the {@code FlavorMap} + * @return a {@code FlavorMap} + */ + FlavorMap getFlavorMap(Supplier<FlavorMap> supplier); + + /** + * Checks if desktop is present + * + * @return {@code true} is the desktop is present + */ + boolean isDesktopPresent(); + + /** + * Returns platform-specific mappings for the specified native format. + * If there are no platform-specific mappings for this native, the method + * returns an empty {@code Set} + * + * @param nat a native format to return flavors for + * @return set of platform-specific mappings for a native format + */ + LinkedHashSet<DataFlavor> getPlatformMappingsForNative(String nat); + + /** + * Returns platform-specific mappings for the specified flavor. + * If there are no platform-specific mappings for this flavor, the method + * returns an empty {@code Set} + * + * @param df {@code DataFlavor} to return mappings for + * @return set of platform-specific mappings for a {@code DataFlavor} + */ + LinkedHashSet<String> getPlatformMappingsForFlavor(DataFlavor df); + + /** + * This method is called for text flavor mappings established while parsing + * the default flavor mappings file. It stores the "eoln" and "terminators" + * parameters which are not officially part of the MIME type. They are + * MIME parameters specific to the flavormap.properties file format. + */ + void registerTextFlavorProperties(String nat, String charset, + String eoln, String terminators); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/unix/classes/sun/datatransfer/resources/flavormap.properties Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,71 @@ +# +# This properties file is used to initialize the default +# java.awt.datatransfer.SystemFlavorMap. It contains the X11 platform-specific, +# default mappings between common X11 selection atoms and platform-independent +# MIME type strings, which will be converted into +# java.awt.datatransfer.DataFlavors. +# +# The standard format is: +# +# <native>=<MIME type>,<MIME type>, ... +# +# <native> should be a string identifier that the native platform will +# recognize as a valid data format. <MIME type> should specify both a MIME +# primary type and a MIME subtype separated by a '/'. The MIME type may include +# parameters, where each parameter is a key/value pair separated by '=', and +# where each parameter to the MIME type is separated by a ';'. +# +# Because SystemFlavorMap implements FlavorTable, developers are free to +# duplicate DataFlavor values and set multiple values for a single native by +# separating them with ",". If a mapping contains a duplicate key or value, +# earlier mappings which included this key or value will be preferred. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", and which support the charset parameter, should specify the exact +# format in which the native platform expects the data. The "charset" +# parameter specifies the char to byte encoding, the "eoln" parameter +# specifies the end-of-line marker, and the "terminators" parameter specifies +# the number of terminating NUL bytes. Note that "eoln" and "terminators" +# are not standardized MIME type parameters. They are specific to this file +# format ONLY. They will not appear in any of the DataFlavors returned by the +# SystemFlavorMap at the Java level. +# +# If the "charset" parameter is omitted, or has zero length, the platform +# default encoding is assumed. If the "eoln" parameter is omitted, or has +# zero length, "\n" is assumed. If the "terminators" parameter is omitted, +# or has a value less than zero, zero is assumed. +# +# Upon initialization, the data transfer subsystem will record the specified +# details of the native text format, but the default SystemFlavorMap will +# present a large set of synthesized DataFlavors which map, in both +# directions, to the native. After receiving data from the application in one +# of the synthetic DataFlavors, the data transfer subsystem will transform +# the data stream into the format specified in this file before passing the +# transformed stream to the native system. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", but which do not support the charset parameter, will be treated as +# opaque, 8-bit data. They will not undergo any transformation process, and +# any "charset", "eoln", or "terminators" parameters specified in this file +# will be ignored. +# +# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of +# text flavors which support the charset parameter. + +UTF8_STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 + +# The COMPOUND_TEXT support for inter-client text transfer is disabled by +# default. The reason is that many native applications prefer this format over +# other native text formats, but are unable to decode the textual data in this +# format properly. This results in java-to-native text transfer failures. +# To enable the COMPOUND_TEXT support for this JRE installation uncomment +# the line below. + +# COMPOUND_TEXT=text/plain;charset=x-compound-text;eoln="\n";terminators=0 + +TEXT=text/plain;eoln="\n";terminators=0 +STRING=text/plain;charset=iso8859-1;eoln="\n";terminators=0 +FILE_NAME=application/x-java-file-list;class=java.util.List +text/uri-list=application/x-java-file-list;class=java.util.List +PNG=image/x-java-image;class=java.awt.Image +JFIF=image/x-java-image;class=java.awt.Image
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.datatransfer/windows/classes/sun/datatransfer/resources/flavormap.properties Tue Feb 17 11:44:51 2015 -0800 @@ -0,0 +1,69 @@ +# +# This properties file is used to initialize the default +# java.awt.datatransfer.SystemFlavorMap. It contains the Win32 platform- +# specific, default mappings between common Win32 Clipboard atoms and platform- +# independent MIME type strings, which will be converted into +# java.awt.datatransfer.DataFlavors. +# +# The standard format is: +# +# <native>=<MIME type>,<MIME type>, ... +# +# <native> should be a string identifier that the native platform will +# recognize as a valid data format. <MIME type> should specify both a MIME +# primary type and a MIME subtype separated by a '/'. The MIME type may include +# parameters, where each parameter is a key/value pair separated by '=', and +# where each parameter to the MIME type is separated by a ';'. +# +# Because SystemFlavorMap implements FlavorTable, developers are free to +# duplicate DataFlavor values and set multiple values for a single native by +# separating them with ",". If a mapping contains a duplicate key or value, +# earlier mappings which included this key or value will be preferred.# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", and which support the charset parameter, should specify the exact +# format in which the native platform expects the data. The "charset" +# parameter specifies the char to byte encoding, the "eoln" parameter +# specifies the end-of-line marker, and the "terminators" parameter specifies +# the number of terminating NUL bytes. Note that "eoln" and "terminators" +# are not standardized MIME type parameters. They are specific to this file +# format ONLY. They will not appear in any of the DataFlavors returned by the +# SystemFlavorMap at the Java level. +# +# If the "charset" parameter is omitted, or has zero length, the platform +# default encoding is assumed. If the "eoln" parameter is omitted, or has +# zero length, "\n" is assumed. If the "terminators" parameter is omitted, +# or has a value less than zero, zero is assumed. +# +# Upon initialization, the data transfer subsystem will record the specified +# details of the native text format, but the default SystemFlavorMap will +# present a large set of synthesized DataFlavors which map, in both +# directions, to the native. After receiving data from the application in one +# of the synthetic DataFlavors, the data transfer subsystem will transform +# the data stream into the format specified in this file before passing the +# transformed stream to the native system. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", but which do not support the charset parameter, will be treated as +# opaque, 8-bit data. They will not undergo any transformation process, and +# any "charset", "eoln", or "terminators" parameters specified in this file +# will be ignored. +# +# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of +# text flavors which support the charset parameter. + +UNICODE\ TEXT=text/plain;charset=utf-16le;eoln="\r\n";terminators=2 +TEXT=text/plain;eoln="\r\n";terminators=1 +HTML\ Format=text/html;charset=utf-8;eoln="\r\n";terminators=1 +Rich\ Text\ Format=text/rtf +HDROP=application/x-java-file-list;class=java.util.List +PNG=image/x-java-image;class=java.awt.Image +JFIF=image/x-java-image;class=java.awt.Image +DIB=image/x-java-image;class=java.awt.Image +ENHMETAFILE=image/x-java-image;class=java.awt.Image +METAFILEPICT=image/x-java-image;class=java.awt.Image +LOCALE=application/x-java-text-encoding;class="[B" +UniformResourceLocator=application/x-java-url;class=java.net.URL,\ + text/uri-list;eoln="\r\n";terminators=1,\ + text/plain;eoln="\r\n";terminators=1 +FileGroupDescriptorW=application/x-java-file-list;class=java.util.List +FileGroupDescriptor=application/x-java-file-list;class=java.util.List
--- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaBorder.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaBorder.java Tue Feb 17 11:44:51 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -68,8 +68,9 @@ painter.state.set(size); } + @Override public Insets getBorderInsets(final Component c) { - return sizeVariant.margins; + return (Insets) sizeVariant.margins.clone(); } protected AquaBorder deriveBorderForSize(final Size size) { @@ -130,8 +131,10 @@ return (focusable != null && focusable instanceof JComponent && ((JComponent)focusable).hasFocus()); } + @Override public boolean isBorderOpaque() { return false; } + @Override public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int w, final int h) { painter.paint(g, c, x, y, w, h); }
--- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxUI.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxUI.java Tue Feb 17 11:44:51 2015 -0800 @@ -275,7 +275,7 @@ actionMap.put("aquaSelectNext", highlightNextAction); actionMap.put("aquaSelectPrevious", highlightPreviousAction); - actionMap.put("aquaEnterPressed", triggerSelectionAction); + actionMap.put("enterPressed", triggerSelectionAction); actionMap.put("aquaSpacePressed", toggleSelectionAction); actionMap.put("aquaSelectHome", highlightFirstAction);
--- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileChooserUI.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileChooserUI.java Tue Feb 17 11:44:51 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -1098,8 +1098,15 @@ super(f); } - public Component getTableCellRendererComponent(final JTable list, final Object value, final boolean isSelected, final boolean cellHasFocus, final int index, final int col) { - super.getTableCellRendererComponent(list, value, isSelected, false, index, col); // No focus border, thanks + public Component getTableCellRendererComponent(final JTable list, + final Object value, + final boolean isSelected, + final boolean cellHasFocus, + final int index, + final int col) { + super.getTableCellRendererComponent(list, value, isSelected, false, + index, + col); // No focus border, thanks final File file = (File)value; final JFileChooser fc = getFileChooser(); setText(fc.getName(file)); @@ -1115,8 +1122,14 @@ super(f); } - public Component getTableCellRendererComponent(final JTable list, final Object value, final boolean isSelected, final boolean cellHasFocus, final int index, final int col) { - super.getTableCellRendererComponent(list, value, isSelected, false, index, col); + public Component getTableCellRendererComponent(final JTable list, + final Object value, + final boolean isSelected, + final boolean cellHasFocus, + final int index, + final int col) { + super.getTableCellRendererComponent(list, value, isSelected, false, + index, col); final File file = (File)fFileList.getValueAt(index, 0); setEnabled(isSelectableInList(file)); final DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.SHORT); @@ -1132,14 +1145,17 @@ } } + @Override public Dimension getPreferredSize(final JComponent c) { - return PREF_SIZE; + return new Dimension(PREF_WIDTH, PREF_HEIGHT); } + @Override public Dimension getMinimumSize(final JComponent c) { - return MIN_SIZE; + return new Dimension(MIN_WIDTH, MIN_HEIGHT); } + @Override public Dimension getMaximumSize(final JComponent c) { return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); } @@ -1819,12 +1835,8 @@ private static final int PREF_WIDTH = 550; private static final int PREF_HEIGHT = 400; - private static final Dimension PREF_SIZE = new Dimension(PREF_WIDTH, PREF_HEIGHT); - private static final int MIN_WIDTH = 400; private static final int MIN_HEIGHT = 250; - private static final Dimension MIN_SIZE = new Dimension(MIN_WIDTH, MIN_HEIGHT); - private static final int LIST_MIN_WIDTH = 400; private static final int LIST_MIN_HEIGHT = 100; private static final Dimension LIST_MIN_SIZE = new Dimension(LIST_MIN_WIDTH, LIST_MIN_HEIGHT);
--- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java Tue Feb 17 11:44:51 2015 -0800 @@ -214,7 +214,7 @@ "PAGE_DOWN", "aquaSelectPageDown", "HOME", "aquaSelectHome", "END", "aquaSelectEnd", - "ENTER", "aquaEnterPressed", + "ENTER", "enterPressed", "UP", "aquaSelectPrevious", "KP_UP", "aquaSelectPrevious", "DOWN", "aquaSelectNext",
--- a/jdk/src/java.desktop/macosx/classes/sun/datatransfer/resources/flavormap.properties Tue Feb 17 10:48:24 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -# -# This properties file is used to initialize the default -# java.awt.datatransfer.SystemFlavorMap. It contains the Mac OS X platform-specific, -# default mappings between common Mac OS X selection atoms and platform-independent -# MIME type strings, which will be converted into -# java.awt.datatransfer.DataFlavors. -# -# The standard format is: -# -# <native>=<MIME type>,<MIME type>, ... -# -# <native> should be a string identifier that the native platform will -# recognize as a valid data format. <MIME type> should specify both a MIME -# primary type and a MIME subtype separated by a '/'. The MIME type may include -# parameters, where each parameter is a key/value pair separated by '=', and -# where each parameter to the MIME type is separated by a ';'. -# -# Because SystemFlavorMap implements FlavorTable, developers are free to -# duplicate DataFlavor values and set multiple values for a single native by -# separating them with ",". If a mapping contains a duplicate key or value, -# earlier mappings which included this key or value will be preferred. -# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", and which support the charset parameter, should specify the exact -# format in which the native platform expects the data. The "charset" -# parameter specifies the char to byte encoding, the "eoln" parameter -# specifies the end-of-line marker, and the "terminators" parameter specifies -# the number of terminating NUL bytes. Note that "eoln" and "terminators" -# are not standardized MIME type parameters. They are specific to this file -# format ONLY. They will not appear in any of the DataFlavors returned by the -# SystemFlavorMap at the Java level. -# -# If the "charset" parameter is omitted, or has zero length, the platform -# default encoding is assumed. If the "eoln" parameter is omitted, or has -# zero length, "\n" is assumed. If the "terminators" parameter is omitted, -# or has a value less than zero, zero is assumed. -# -# Upon initialization, the data transfer subsystem will record the specified -# details of the native text format, but the default SystemFlavorMap will -# present a large set of synthesized DataFlavors which map, in both -# directions, to the native. After receiving data from the application in one -# of the synthetic DataFlavors, the data transfer subsystem will transform -# the data stream into the format specified in this file before passing the -# transformed stream to the native system. -# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", but which do not support the charset parameter, will be treated as -# opaque, 8-bit data. They will not undergo any transformation process, and -# any "charset", "eoln", or "terminators" parameters specified in this file -# will be ignored. -# -# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of -# text flavors which support the charset parameter. - -UTF8_STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 - -# The COMPOUND_TEXT support for inter-client text transfer is disabled by -# default. The reason is that many native applications prefer this format over -# other native text formats, but are unable to decode the textual data in this -# format properly. This results in java-to-native text transfer failures. -# To enable the COMPOUND_TEXT support for this JRE installation uncomment -# the line below. - -# COMPOUND_TEXT=text/plain;charset=x-compound-text;eoln="\n";terminators=0 - -TEXT=text/plain;eoln="\n";terminators=0 -STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 -FILE_NAME=application/x-java-file-list;class=java.util.List -text/uri-list=application/x-java-file-list;class=java.util.List -PNG=image/x-java-image;class=java.awt.Image -JFIF=image/x-java-image;class=java.awt.Image -TIFF=image/x-java-image;class=java.awt.Image -RICH_TEXT=text/rtf -HTML=text/html;charset=utf-8;eoln="\r\n";terminators=1 -URL=application/x-java-url;class=java.net.URL,\ - text/uri-list;eoln="\r\n";terminators=1
--- a/jdk/src/java.desktop/macosx/classes/sun/font/CFont.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/macosx/classes/sun/font/CFont.java Tue Feb 17 11:44:51 2015 -0800 @@ -77,14 +77,72 @@ } private static native long createNativeFont(final String nativeFontName, - final int style, - final boolean isFakeItalic); + final int style); private static native void disposeNativeFont(final long nativeFontPtr); private boolean isFakeItalic; private String nativeFontName; private long nativeFontPtr; + private native float getWidthNative(final long nativeFontPtr); + private native float getWeightNative(final long nativeFontPtr); + + private int fontWidth = -1; + private int fontWeight = -1; + + @Override + public int getWidth() { + if (fontWidth == -1) { + // Apple use a range of -1 -> +1, where 0.0 is normal + // OpenType uses a % range from 50% -> 200% where 100% is normal + // and maps these onto the integer values 1->9. + // Since that is what Font2D.getWidth() expects, remap to that. + float fw = getWidthNative(getNativeFontPtr()); + if (fw == 0.0) { // short cut the common case + fontWidth = Font2D.FWIDTH_NORMAL; + return fontWidth; + } + fw += 1.0; fw *= 100.0; + if (fw <= 50.0) { + fontWidth = 1; + } else if (fw <= 62.5) { + fontWidth = 2; + } else if (fw <= 75.0) { + fontWidth = 3; + } else if (fw <= 87.5) { + fontWidth = 4; + } else if (fw <= 100.0) { + fontWidth = 5; + } else if (fw <= 112.5) { + fontWidth = 6; + } else if (fw <= 125.0) { + fontWidth = 7; + } else if (fw <= 150.0) { + fontWidth = 8; + } else { + fontWidth = 9; + } + } + return fontWidth; + } + + @Override + public int getWeight() { + if (fontWeight == -1) { + // Apple use a range of -1 -> +1, where 0 is medium/regular + // Map this on to the OpenType range of 100->900 where + // 500 is medium/regular. + // We'll actually map to 0->1000 but that's close enough. + float fw = getWeightNative(getNativeFontPtr()); + if (fw == 0) { + return Font2D.FWEIGHT_NORMAL; + } + fw += 1.0; fw *= 500; + fontWeight = (int)fw; + } + return fontWeight; + } + // this constructor is called from CFontWrapper.m public CFont(String name) { this(name, name); @@ -94,10 +152,11 @@ handle = new Font2DHandle(this); fullName = name; familyName = inFamilyName; - nativeFontName = inFamilyName; + nativeFontName = fullName; setStyle(); } + /* Called from CFontManager too */ public CFont(CFont other, String logicalFamilyName) { handle = new Font2DHandle(this); fullName = logicalFamilyName; @@ -109,6 +168,7 @@ public CFont createItalicVariant() { CFont font = new CFont(this, familyName); + font.nativeFontName = fullName; font.fullName = fullName + (style == Font.BOLD ? "" : "-") + "Italic-Derived"; font.style |= Font.ITALIC; @@ -118,7 +178,7 @@ protected synchronized long getNativeFontPtr() { if (nativeFontPtr == 0L) { - nativeFontPtr = createNativeFont(nativeFontName, style, isFakeItalic); + nativeFontPtr = createNativeFont(nativeFontName, style); } return nativeFontPtr; }
--- a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java Tue Feb 17 11:44:51 2015 -0800 @@ -252,13 +252,42 @@ final CFont font = new CFont(fontName, fontFamilyName); registerGenericFont(font); + } - if ((font.getStyle() & Font.ITALIC) == 0) { - registerGenericFont(font.createItalicVariant(), true); + void registerItalicDerived() { + FontFamily[] famArr = FontFamily.getAllFontFamilies(); + for (int i=0; i<famArr.length; i++) { + FontFamily family = famArr[i]; + + Font2D f2dPlain = family.getFont(Font.PLAIN); + if (f2dPlain != null && !(f2dPlain instanceof CFont)) continue; + Font2D f2dBold = family.getFont(Font.BOLD); + if (f2dBold != null && !(f2dBold instanceof CFont)) continue; + Font2D f2dItalic = family.getFont(Font.ITALIC); + if (f2dItalic != null && !(f2dItalic instanceof CFont)) continue; + Font2D f2dBoldItalic = family.getFont(Font.BOLD|Font.ITALIC); + if (f2dBoldItalic != null && !(f2dBoldItalic instanceof CFont)) continue; + + CFont plain = (CFont)f2dPlain; + CFont bold = (CFont)f2dBold; + CFont italic = (CFont)f2dItalic; + CFont boldItalic = (CFont)f2dBoldItalic; + + if (bold == null) bold = plain; + if (plain == null && bold == null) continue; + if (italic != null && boldItalic != null) continue; + if (plain != null && italic == null) { + registerGenericFont(plain.createItalicVariant(), true); + } + if (bold != null && boldItalic == null) { + registerGenericFont(bold.createItalicVariant(), true); + } } } Object waitForFontsToBeLoaded = new Object(); + private boolean loadedAllFonts = false; + public void loadFonts() { synchronized(waitForFontsToBeLoaded) @@ -267,7 +296,11 @@ java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Object>() { public Object run() { - loadNativeFonts(); + if (!loadedAllFonts) { + loadNativeFonts(); + registerItalicDerived(); + loadedAllFonts = true; + } return null; } }
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m Tue Feb 17 11:44:51 2015 -0800 @@ -890,9 +890,9 @@ // text, or 'text in progress'. We also need to send the event if we get an insert text out of the blue! // (i.e., when the user uses the Character palette or Inkwell), or when the string to insert is a complex // Unicode value. - NSUInteger utf8Length = [aString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + NSUInteger utf16Length = [aString lengthOfBytesUsingEncoding:NSUTF16StringEncoding]; - if ([self hasMarkedText] || !fProcessingKeystroke || (utf8Length > 1)) { + if ([self hasMarkedText] || !fProcessingKeystroke || (utf16Length > 2)) { JNIEnv *env = [ThreadUtilities getJNIEnv]; static JNF_MEMBER_CACHE(jm_selectPreviousGlyph, jc_CInputMethod, "selectPreviousGlyph", "()V");
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m Tue Feb 17 11:44:51 2015 -0800 @@ -35,15 +35,11 @@ #import "AWTStrike.h" #import "CoreTextSupport.h" - -#define DEBUG - @implementation AWTFont -- (id) initWithFont:(NSFont *)font isFakeItalic:(BOOL)isFakeItalic { +- (id) initWithFont:(NSFont *)font { self = [super init]; if (self) { - fIsFakeItalic = isFakeItalic; fFont = [font retain]; fNativeCGFont = CTFontCopyGraphicsFont((CTFontRef)font, NULL); } @@ -72,7 +68,6 @@ + (AWTFont *) awtFontForName:(NSString *)name style:(int)style - isFakeItalic:(BOOL)isFakeItalic { // create font with family & size NSFont *nsFont = [NSFont fontWithName:name size:1.0]; @@ -95,7 +90,7 @@ nsFont = [[NSFontManager sharedFontManager] convertFont:nsFont toHaveTrait:NSBoldFontMask]; } - return [[[AWTFont alloc] initWithFont:nsFont isFakeItalic:isFakeItalic] autorelease]; + return [[[AWTFont alloc] initWithFont:nsFont] autorelease]; } + (NSFont *) nsFontForJavaFont:(jobject)javaFont env:(JNIEnv *)env { @@ -354,7 +349,7 @@ JNIEXPORT jlong JNICALL Java_sun_font_CFont_createNativeFont (JNIEnv *env, jclass clazz, - jstring nativeFontName, jint style, jboolean isFakeItalic) + jstring nativeFontName, jint style) { AWTFont *awtFont = nil; @@ -362,8 +357,7 @@ awtFont = [AWTFont awtFontForName:JNFJavaToNSString(env, nativeFontName) - style:style - isFakeItalic:isFakeItalic]; // autoreleased + style:style]; // autoreleased if (awtFont) { CFRetain(awtFont); // GC @@ -376,6 +370,52 @@ /* * Class: sun_font_CFont + * Method: getWidthNative + * Signature: (J)F + */ +JNIEXPORT jfloat JNICALL +Java_sun_font_CFont_getWidthNative + (JNIEnv *env, jobject cfont, jlong awtFontPtr) +{ + float widthVal; +JNF_COCOA_ENTER(env); + + AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); + NSFont* nsFont = awtFont->fFont; + NSFontDescriptor *fontDescriptor = nsFont.fontDescriptor; + NSDictionary *fontTraits = [fontDescriptor objectForKey : NSFontTraitsAttribute]; + NSNumber *width = [fontTraits objectForKey : NSFontWidthTrait]; + widthVal = (float)[width floatValue]; + +JNF_COCOA_EXIT(env); + return (jfloat)widthVal; +} + +/* + * Class: sun_font_CFont + * Method: getWeightNative + * Signature: (J)F + */ +JNIEXPORT jfloat JNICALL +Java_sun_font_CFont_getWeightNative + (JNIEnv *env, jobject cfont, jlong awtFontPtr) +{ + float weightVal; +JNF_COCOA_ENTER(env); + + AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); + NSFont* nsFont = awtFont->fFont; + NSFontDescriptor *fontDescriptor = nsFont.fontDescriptor; + NSDictionary *fontTraits = [fontDescriptor objectForKey : NSFontTraitsAttribute]; + NSNumber *weight = [fontTraits objectForKey : NSFontWeightTrait]; + weightVal = (float)[weight floatValue]; + +JNF_COCOA_EXIT(env); + return (jfloat)weightVal; +} + +/* + * Class: sun_font_CFont * Method: disposeNativeFont * Signature: (J)V */
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java Tue Feb 17 11:44:51 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, 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 @@ -43,8 +43,6 @@ import java.awt.image.Raster; import java.awt.image.WritableRaster; -import java.awt.image.SampleModel; -import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.ColorModel; import java.awt.image.IndexColorModel; @@ -1048,7 +1046,13 @@ // Call the writer, who will call back for every scanline - processImageStarted(currentImage); + clearAbortRequest(); + cbLock.lock(); + try { + processImageStarted(currentImage); + } finally { + cbLock.unlock(); + } boolean aborted = false; @@ -1225,6 +1229,23 @@ } } + @Override + protected synchronized void clearAbortRequest() { + setThreadLock(); + try { + cbLock.check(); + if (abortRequested()) { + super.clearAbortRequest(); + // reset C structures + resetWriter(structPointer); + // reset the native destination + setDest(structPointer); + } + } finally { + clearThreadLock(); + } + } + private void resetInternalState() { // reset C structures resetWriter(structPointer); @@ -1652,7 +1673,7 @@ int vsamp0 = specs[0].VsamplingFactor; for (int i = 1; i < specs.length; i++) { if ((specs[i].HsamplingFactor != hsamp0) || - (specs[i].HsamplingFactor != hsamp0)) + (specs[i].VsamplingFactor != vsamp0)) return true; } return false;
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKFileChooserUI.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKFileChooserUI.java Tue Feb 17 11:44:51 2015 -0800 @@ -100,7 +100,8 @@ private static Dimension prefListSize = new Dimension(75, 150); private static Dimension PREF_SIZE = new Dimension(435, 360); - private static Dimension MIN_SIZE = new Dimension(200, 300); + private static final int MIN_WIDTH = 200; + private static final int MIN_HEIGHT = 300; private static Dimension ZERO_ACC_SIZE = new Dimension(1, 1); @@ -1052,6 +1053,7 @@ } } + @Override public Dimension getPreferredSize(JComponent c) { Dimension prefSize = new Dimension(PREF_SIZE); JComponent accessory = getFileChooser().getAccessory(); @@ -1067,10 +1069,12 @@ } } - public Dimension getMinimumSize(JComponent x) { - return new Dimension(MIN_SIZE); + @Override + public Dimension getMinimumSize(JComponent x) { + return new Dimension(MIN_WIDTH, MIN_HEIGHT); } + @Override public Dimension getMaximumSize(JComponent x) { return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); }
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java Tue Feb 17 11:44:51 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -65,8 +65,8 @@ private static Dimension WITH_ACCELERATOR_PREF_SIZE = new Dimension(650, 450); private static Dimension PREF_SIZE = new Dimension(350, 450); - private static Dimension MIN_SIZE = new Dimension(200, 300); - + private static final int MIN_WIDTH = 200; + private static final int MIN_HEIGHT = 300; private static Dimension PREF_ACC_SIZE = new Dimension(10, 10); private static Dimension ZERO_ACC_SIZE = new Dimension(1, 1); @@ -628,6 +628,7 @@ return scrollpane; } + @Override public Dimension getPreferredSize(JComponent c) { Dimension prefSize = (getFileChooser().getAccessory() != null) ? WITH_ACCELERATOR_PREF_SIZE : PREF_SIZE; @@ -640,10 +641,12 @@ } } - public Dimension getMinimumSize(JComponent x) { - return MIN_SIZE; + @Override + public Dimension getMinimumSize(JComponent x) { + return new Dimension(MIN_WIDTH, MIN_HEIGHT); } + @Override public Dimension getMaximumSize(JComponent x) { return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); }
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java Tue Feb 17 11:44:51 2015 -0800 @@ -93,7 +93,6 @@ private static int MIN_WIDTH = 425; private static int MIN_HEIGHT = 245; - private static Dimension MIN_SIZE = new Dimension(MIN_WIDTH, MIN_HEIGHT); private static int LIST_PREF_WIDTH = 444; private static int LIST_PREF_HEIGHT = 138; @@ -642,6 +641,7 @@ * @return a <code>Dimension</code> specifying the preferred * width and height of the file chooser */ + @Override public Dimension getPreferredSize(JComponent c) { int prefWidth = PREF_SIZE.width; Dimension d = c.getLayout().preferredLayoutSize(c); @@ -660,8 +660,9 @@ * @return a <code>Dimension</code> specifying the minimum * width and height of the file chooser */ + @Override public Dimension getMinimumSize(JComponent c) { - return MIN_SIZE; + return new Dimension(MIN_WIDTH, MIN_HEIGHT); } /** @@ -671,6 +672,7 @@ * @return a <code>Dimension</code> specifying the maximum * width and height of the file chooser */ + @Override public Dimension getMaximumSize(JComponent c) { return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); }
--- a/jdk/src/java.desktop/share/classes/java/awt/Component.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/share/classes/java/awt/Component.java Tue Feb 17 11:44:51 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, 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 @@ -1690,15 +1690,6 @@ /* do nothing */ } - /* - * Delete references from LightweightDispatcher of a heavyweight parent - */ - void clearLightweightDispatcherOnRemove(Component removedComponent) { - if (parent != null) { - parent.clearLightweightDispatcherOnRemove(removedComponent); - } - } - /** * @deprecated As of JDK version 1.1, * replaced by <code>setVisible(boolean)</code>. @@ -6242,7 +6233,7 @@ /** * Indicates whether a class or its superclasses override coalesceEvents. * Must be called with lock on coalesceMap and privileged. - * @see checkCoalsecing + * @see checkCoalescing */ private static boolean isCoalesceEventsOverriden(Class<?> clazz) { assert Thread.holdsLock(coalesceMap); @@ -7083,8 +7074,6 @@ } synchronized (getTreeLock()) { - clearLightweightDispatcherOnRemove(this); - if (isFocusOwner() && KeyboardFocusManager.isAutoFocusTransferEnabledFor(this)) { transferFocus(true); }
--- a/jdk/src/java.desktop/share/classes/java/awt/Container.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/share/classes/java/awt/Container.java Tue Feb 17 11:44:51 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, 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 @@ -41,6 +41,7 @@ import java.io.PrintStream; import java.io.PrintWriter; +import java.lang.ref.WeakReference; import java.security.AccessController; import java.util.EventListener; @@ -3321,16 +3322,6 @@ } } - @Override - void clearLightweightDispatcherOnRemove(Component removedComponent) { - if (dispatcher != null) { - dispatcher.removeReferences(removedComponent); - } else { - //It is a Lightweight Container, should clear parent`s Dispatcher - super.clearLightweightDispatcherOnRemove(removedComponent); - } - } - final Container getTraversalRoot() { if (isFocusCycleRoot()) { return findTraversalRoot(); @@ -4431,7 +4422,9 @@ LightweightDispatcher(Container nativeContainer) { this.nativeContainer = nativeContainer; - mouseEventTarget = null; + mouseEventTarget = new WeakReference<>(null); + targetLastEntered = new WeakReference<>(null); + targetLastEnteredDT = new WeakReference<>(null); eventMask = 0; } @@ -4442,9 +4435,9 @@ void dispose() { //System.out.println("Disposing lw dispatcher"); stopListeningForOtherDrags(); - mouseEventTarget = null; - targetLastEntered = null; - targetLastEnteredDT = null; + mouseEventTarget.clear(); + targetLastEntered.clear(); + targetLastEnteredDT.clear(); } /** @@ -4531,65 +4524,62 @@ trackMouseEnterExit(mouseOver, e); - // 4508327 : MOUSE_CLICKED should only go to the recipient of - // the accompanying MOUSE_PRESSED, so don't reset mouseEventTarget on a - // MOUSE_CLICKED. - if (!isMouseGrab(e) && id != MouseEvent.MOUSE_CLICKED) { - mouseEventTarget = (mouseOver != nativeContainer) ? mouseOver: null; - isCleaned = false; + Component met = mouseEventTarget.get(); + // 4508327 : MOUSE_CLICKED should only go to the recipient of + // the accompanying MOUSE_PRESSED, so don't reset mouseEventTarget on a + // MOUSE_CLICKED. + if (!isMouseGrab(e) && id != MouseEvent.MOUSE_CLICKED) { + met = (mouseOver != nativeContainer) ? mouseOver : null; + mouseEventTarget = new WeakReference<>(met); } - if (mouseEventTarget != null) { + if (met != null) { switch (id) { - case MouseEvent.MOUSE_ENTERED: - case MouseEvent.MOUSE_EXITED: - break; - case MouseEvent.MOUSE_PRESSED: - retargetMouseEvent(mouseEventTarget, id, e); - break; - case MouseEvent.MOUSE_RELEASED: - retargetMouseEvent(mouseEventTarget, id, e); - break; - case MouseEvent.MOUSE_CLICKED: - // 4508327: MOUSE_CLICKED should never be dispatched to a Component - // other than that which received the MOUSE_PRESSED event. If the - // mouse is now over a different Component, don't dispatch the event. - // The previous fix for a similar problem was associated with bug - // 4155217. - if (mouseOver == mouseEventTarget) { - retargetMouseEvent(mouseOver, id, e); - } - break; - case MouseEvent.MOUSE_MOVED: - retargetMouseEvent(mouseEventTarget, id, e); - break; - case MouseEvent.MOUSE_DRAGGED: - if (isMouseGrab(e)) { - retargetMouseEvent(mouseEventTarget, id, e); - } - break; - case MouseEvent.MOUSE_WHEEL: - // This may send it somewhere that doesn't have MouseWheelEvents - // enabled. In this case, Component.dispatchEventImpl() will - // retarget the event to a parent that DOES have the events enabled. - if (eventLog.isLoggable(PlatformLogger.Level.FINEST) && (mouseOver != null)) { - eventLog.finest("retargeting mouse wheel to " + + case MouseEvent.MOUSE_ENTERED: + case MouseEvent.MOUSE_EXITED: + break; + case MouseEvent.MOUSE_PRESSED: + retargetMouseEvent(met, id, e); + break; + case MouseEvent.MOUSE_RELEASED: + retargetMouseEvent(met, id, e); + break; + case MouseEvent.MOUSE_CLICKED: + // 4508327: MOUSE_CLICKED should never be dispatched to a Component + // other than that which received the MOUSE_PRESSED event. If the + // mouse is now over a different Component, don't dispatch the event. + // The previous fix for a similar problem was associated with bug + // 4155217. + if (mouseOver == met) { + retargetMouseEvent(mouseOver, id, e); + } + break; + case MouseEvent.MOUSE_MOVED: + retargetMouseEvent(met, id, e); + break; + case MouseEvent.MOUSE_DRAGGED: + if (isMouseGrab(e)) { + retargetMouseEvent(met, id, e); + } + break; + case MouseEvent.MOUSE_WHEEL: + // This may send it somewhere that doesn't have MouseWheelEvents + // enabled. In this case, Component.dispatchEventImpl() will + // retarget the event to a parent that DOES have the events enabled. + if (eventLog.isLoggable(PlatformLogger.Level.FINEST) && (mouseOver != null)) { + eventLog.finest("retargeting mouse wheel to " + mouseOver.getName() + ", " + mouseOver.getClass()); + } + retargetMouseEvent(mouseOver, id, e); + break; } - retargetMouseEvent(mouseOver, id, e); - break; + //Consuming of wheel events is implemented in "retargetMouseEvent". + if (id != MouseEvent.MOUSE_WHEEL) { + e.consume(); } - //Consuming of wheel events is implemented in "retargetMouseEvent". - if (id != MouseEvent.MOUSE_WHEEL) { - e.consume(); } - } else if (isCleaned && id != MouseEvent.MOUSE_WHEEL) { - //After mouseEventTarget was removed and cleaned should consume all events - //until new mouseEventTarget is found - e.consume(); - } - return e.isConsumed(); + return e.isConsumed(); } private boolean processDropTargetEvent(SunDropTargetEvent e) { @@ -4646,15 +4636,16 @@ // drag has an associated drop target. MOUSE_ENTERED comes when the // mouse is in the native container already. To propagate this event // properly we should null out targetLastEntered. - targetLastEnteredDT = null; + targetLastEnteredDT.clear(); } else if (id == MouseEvent.MOUSE_ENTERED) { isMouseDTInNativeContainer = true; } else if (id == MouseEvent.MOUSE_EXITED) { isMouseDTInNativeContainer = false; } - targetLastEnteredDT = retargetMouseEnterExit(targetOver, e, - targetLastEnteredDT, + Component tle = retargetMouseEnterExit(targetOver, e, + targetLastEnteredDT.get(), isMouseDTInNativeContainer); + targetLastEnteredDT = new WeakReference<>(tle); } /* @@ -4680,9 +4671,10 @@ isMouseInNativeContainer = false; stopListeningForOtherDrags(); } - targetLastEntered = retargetMouseEnterExit(targetOver, e, - targetLastEntered, + Component tle = retargetMouseEnterExit(targetOver, e, + targetLastEntered.get(), isMouseInNativeContainer); + targetLastEntered = new WeakReference<>(tle); } private Component retargetMouseEnterExit(Component targetOver, MouseEvent e, @@ -4944,22 +4936,17 @@ * is null, there are currently no events being forwarded to * a subcomponent. */ - private transient Component mouseEventTarget; + private transient WeakReference<Component> mouseEventTarget; /** * The last component entered by the {@code MouseEvent}. */ - private transient Component targetLastEntered; + private transient WeakReference<Component> targetLastEntered; /** * The last component entered by the {@code SunDropTargetEvent}. */ - private transient Component targetLastEnteredDT; - - /** - * Indicates whether {@code mouseEventTarget} was removed and nulled - */ - private transient boolean isCleaned; + private transient WeakReference<Component> targetLastEnteredDT; /** * Is the mouse over the native container. @@ -5000,17 +4987,4 @@ AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_WHEEL_EVENT_MASK; - - void removeReferences(Component removedComponent) { - if (mouseEventTarget == removedComponent) { - isCleaned = true; - mouseEventTarget = null; - } - if (targetLastEntered == removedComponent) { - targetLastEntered = null; - } - if (targetLastEnteredDT == removedComponent) { - targetLastEnteredDT = null; - } - } }
--- a/jdk/src/java.desktop/share/classes/java/awt/EventQueue.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/share/classes/java/awt/EventQueue.java Tue Feb 17 11:44:51 2015 -0800 @@ -182,7 +182,14 @@ private FwDispatcher fwDispatcher; - private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventQueue"); + private static volatile PlatformLogger eventLog; + + private static final PlatformLogger getEventLog() { + if(eventLog == null) { + eventLog = PlatformLogger.getLogger("java.awt.event.EventQueue"); + } + return eventLog; + } static { AWTAccessor.setEventQueueAccessor( @@ -762,8 +769,8 @@ dispatchThread.stopDispatching(); } } else { - if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { - eventLog.fine("Unable to dispatch event: " + event); + if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) { + getEventLog().fine("Unable to dispatch event: " + event); } } } @@ -860,8 +867,8 @@ * @since 1.2 */ public void push(EventQueue newEventQueue) { - if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { - eventLog.fine("EventQueue.push(" + newEventQueue + ")"); + if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) { + getEventLog().fine("EventQueue.push(" + newEventQueue + ")"); } pushPopLock.lock(); @@ -886,8 +893,8 @@ // Use getNextEventPrivate() as it doesn't call flushPendingEvents() newEventQueue.postEventPrivate(topQueue.getNextEventPrivate()); } catch (InterruptedException ie) { - if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { - eventLog.fine("Interrupted push", ie); + if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) { + getEventLog().fine("Interrupted push", ie); } } } @@ -925,8 +932,8 @@ * @since 1.2 */ protected void pop() throws EmptyStackException { - if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { - eventLog.fine("EventQueue.pop(" + this + ")"); + if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) { + getEventLog().fine("EventQueue.pop(" + this + ")"); } pushPopLock.lock(); @@ -948,8 +955,8 @@ try { prevQueue.postEventPrivate(topQueue.getNextEventPrivate()); } catch (InterruptedException ie) { - if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { - eventLog.fine("Interrupted pop", ie); + if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) { + getEventLog().fine("Interrupted pop", ie); } } }
--- a/jdk/src/java.desktop/share/classes/java/awt/MenuBar.java Tue Feb 17 10:48:24 2015 -0800 +++ b/jdk/src/java.desktop/share/classes/java/awt/MenuBar.java Tue Feb 17 11:44:51 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, 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 @@ -181,7 +181,7 @@ * removed from the menu bar, and replaced with the specified menu. * @param m the menu to be set as the help menu */ - public void setHelpMenu(Menu m) { + public void setHelpMenu(final Menu m) { synchronized (getTreeLock()) { if (helpMenu == m) { return; @@ -189,11 +189,11 @@ if (helpMenu != null) { remove(helpMenu); } - if (m.parent != this) { - add(m); - } helpMenu = m; if (m != null) { + if (m.parent != this) { + add(m); + } m.isHelpMenu = true; m.parent = this; MenuBarPeer peer = (MenuBarPeer)this.peer; @@ -242,7 +242,7 @@ * @param index the position of the menu to be removed. * @see java.awt.MenuBar#add(java.awt.Menu) */ - public void remove(int index) { + public void remove(final int index) { synchronized (getTreeLock()) { Menu m = getMenu(index); menus.removeElementAt(index); @@ -252,6 +252,10 @@ m.parent = null; peer.delMenu(index); } + if (helpMenu == m) { + helpMenu = null; + m.isHelpMenu = false; + } } }
--- a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/Clipboard.java Tue Feb 17 10:48:24 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,352 +0,0 @@ -/* - * Copyright (c) 1996, 2014, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package java.awt.datatransfer; - -import sun.datatransfer.DataFlavorUtil; - -import java.util.Objects; -import java.util.Set; -import java.util.HashSet; -import java.util.Arrays; - -import java.io.IOException; - -/** - * A class that implements a mechanism to transfer data using - * cut/copy/paste operations. - * <p> - * {@link FlavorListener}s may be registered on an instance of the - * Clipboard class to be notified about changes to the set of - * {@link DataFlavor}s available on this clipboard (see - * {@link #addFlavorListener}). - * - * @see java.awt.Toolkit#getSystemClipboard - * @see java.awt.Toolkit#getSystemSelection - * - * @author Amy Fowler - * @author Alexander Gerasimov - */ -public class Clipboard { - - String name; - - /** - * The owner of the clipboard. - */ - protected ClipboardOwner owner; - /** - * Contents of the clipboard. - */ - protected Transferable contents; - - /** - * An aggregate of flavor listeners registered on this local clipboard. - * - * @since 1.5 - */ - private Set<FlavorListener> flavorListeners; - - /** - * A set of <code>DataFlavor</code>s that is available on - * this local clipboard. It is used for tracking changes - * of <code>DataFlavor</code>s available on this clipboard. - * - * @since 1.5 - */ - private Set<DataFlavor> currentDataFlavors; - - /** - * Creates a clipboard object. - * @param name for the clipboard - * @see java.awt.Toolkit#getSystemClipboard - */ - public Clipboard(String name) { - this.name = name; - } - - /** - * Returns the name of this clipboard object. - * @return the name of this clipboard object - * - * @see java.awt.Toolkit#getSystemClipboard - */ - public String getName() { - return name; - } - - /** - * Sets the current contents of the clipboard to the specified - * transferable object and registers the specified clipboard owner - * as the owner of the new contents. - * <p> - * If there is an existing owner different from the argument - * <code>owner</code>, that owner is notified that it no longer - * holds ownership of the clipboard contents via an invocation - * of <code>ClipboardOwner.lostOwnership()</code> on that owner. - * An implementation of <code>setContents()</code> is free not - * to invoke <code>lostOwnership()</code> directly from this method. - * For example, <code>lostOwnership()</code> may be invoked later on - * a different thread. The same applies to <code>FlavorListener</code>s - * registered on this clipboard. - * <p> - * The method throws <code>IllegalStateException</code> if the clipboard - * is currently unavailable. For example, on some platforms, the system - * clipboard is unavailable while it is accessed by another application. - * - * @param contents the transferable object representing the - * clipboard content - * @param owner the object which owns the clipboard content - * @throws IllegalStateException if the clipboard is currently unavailable - * @see java.awt.Toolkit#getSystemClipboard - */ - public synchronized void setContents(Transferable contents, ClipboardOwner owner) { - final ClipboardOwner oldOwner = this.owner; - final Transferable oldContents = this.contents; - - this.owner = owner; - this.contents = contents; - - if (oldOwner != null && oldOwner != owner) { - DataFlavorUtil.getDesktopService().invokeOnEventThread(() -> - oldOwner.lostOwnership(Clipboard.this, oldContents)); - } - fireFlavorsChanged(); - } - - /** - * Returns a transferable object representing the current contents - * of the clipboard. If the clipboard currently has no contents, - * it returns <code>null</code>. The parameter Object requestor is - * not currently used. The method throws - * <code>IllegalStateException</code> if the clipboard is currently - * unavailable. For example, on some platforms, the system clipboard is - * unavailable while it is accessed by another application. - * - * @param requestor the object requesting the clip data (not used) - * @return the current transferable object on the clipboard - * @throws IllegalStateException if the clipboard is currently unavailable - * @see java.awt.Toolkit#getSystemClipboard - */ - public synchronized Transferable getContents(Object requestor) { - return contents; - } - - - /** - * Returns an array of <code>DataFlavor</code>s in which the current - * contents of this clipboard can be provided. If there are no - * <code>DataFlavor</code>s available, this method returns a zero-length - * array. - * - * @return an array of <code>DataFlavor</code>s in which the current - * contents of this clipboard can be provided - * - * @throws IllegalStateException if this clipboard is currently unavailable - * - * @since 1.5 - */ - public DataFlavor[] getAvailableDataFlavors() { - Transferable cntnts = getContents(null); - if (cntnts == null) { - return new DataFlavor[0]; - } - return cntnts.getTransferDataFlavors(); - } - - /** - * Returns whether or not the current contents of this clipboard can be - * provided in the specified <code>DataFlavor</code>. - * - * @param flavor the requested <code>DataFlavor</code> for the contents - * - * @return <code>true</code> if the current contents of this clipboard - * can be provided in the specified <code>DataFlavor</code>; - * <code>false</code> otherwise - * - * @throws NullPointerException if <code>flavor</code> is <code>null</code> - * @throws IllegalStateException if this clipboard is currently unavailable - * - * @since 1.5 - */ - public boolean isDataFlavorAvailable(DataFlavor flavor) { - if (flavor == null) { - throw new NullPointerException("flavor"); - } - - Transferable cntnts = getContents(null); - if (cntnts == null) { - return false; - } - return cntnts.isDataFlavorSupported(flavor); - } - - /** - * Returns an object representing the current contents of this clipboard - * in the specified <code>DataFlavor</code>. - * The class of the object returned is defined by the representation - * class of <code>flavor</code>. - * - * @param flavor the requested <code>DataFlavor</code> for the contents - * - * @return an object representing the current contents of this clipboard - * in the specified <code>DataFlavor</code> - * - * @throws NullPointerException if <code>flavor</code> is <code>null</code> - * @throws IllegalStateException if this clipboard is currently unavailable - * @throws UnsupportedFlavorException if the requested <code>DataFlavor</code> - * is not available - * @throws IOException if the data in the requested <code>DataFlavor</code> - * can not be retrieved - * - * @see DataFlavor#getRepresentationClass - * - * @since 1.5 - */ - public Object getData(DataFlavor flavor) - throws UnsupportedFlavorException, IOException { - if (flavor == null) { - throw new NullPointerException("flavor"); - } - - Transferable cntnts = getContents(null); - if (cntnts == null) { - throw new UnsupportedFlavorException(flavor); - } - return cntnts.getTransferData(flavor); - } - - - /** - * Registers the specified <code>FlavorListener</code> to receive - * <code>FlavorEvent</code>s from this clipboard. - * If <code>listener</code> is <code>null</code>, no exception - * is thrown and no action is performed. - * - * @param listener the listener to be added - * - * @see #removeFlavorListener - * @see #getFlavorListeners - * @see FlavorListener - * @see FlavorEvent - * @since 1.5 - */ - public synchronized void addFlavorListener(FlavorListener listener) { - if (listener == null) { - return; - } - - if (flavorListeners == null) { - flavorListeners = new HashSet<>(); - currentDataFlavors = getAvailableDataFlavorSet(); - } - - flavorListeners.add(listener); - } - - /** - * Removes the specified <code>FlavorListener</code> so that it no longer - * receives <code>FlavorEvent</code>s from this <code>Clipboard</code>. - * This method performs no function, nor does it throw an exception, if - * the listener specified by the argument was not previously added to this - * <code>Clipboard</code>. - * If <code>listener</code> is <code>null</code>, no exception - * is thrown and no action is performed. - * - * @param listener the listener to be removed - * - * @see #addFlavorListener - * @see #getFlavorListeners - * @see FlavorListener - * @see FlavorEvent - * @since 1.5 - */ - public synchronized void removeFlavorListener(FlavorListener listener) { - if (listener == null || flavorListeners == null) { - return; - } - flavorListeners.remove(listener); - } - - /** - * Returns an array of all the <code>FlavorListener</code>s currently - * registered on this <code>Clipboard</code>. - * - * @return all of this clipboard's <code>FlavorListener</code>s or an empty - * array if no listeners are currently registered - * @see #addFlavorListener - * @see #removeFlavorListener - * @see FlavorListener - * @see FlavorEvent - * @since 1.5 - */ - public synchronized FlavorListener[] getFlavorListeners() { - return flavorListeners == null ? new FlavorListener[0] : - flavorListeners.toArray(new FlavorListener[flavorListeners.size()]); - } - - /** - * Checks change of the <code>DataFlavor</code>s and, if necessary, - * notifies all listeners that have registered interest for notification - * on <code>FlavorEvent</code>s. - * - * @since 1.5 - */ - private void fireFlavorsChanged() { - if (flavorListeners == null) { - return; - } - - Set<DataFlavor> prevDataFlavors = currentDataFlavors; - currentDataFlavors = getAvailableDataFlavorSet(); - if (Objects.equals(prevDataFlavors, currentDataFlavors)) { - return; - } - flavorListeners.forEach(listener -> - DataFlavorUtil.getDesktopService().invokeOnEventThread(() -> - listener.flavorsChanged(new FlavorEvent(Clipboard.this)))); - } - - /** - * Returns a set of <code>DataFlavor</code>s currently available - * on this clipboard. - * - * @return a set of <code>DataFlavor</code>s currently available - * on this clipboard - * - * @since 1.5 - */ - private Set<DataFlavor> getAvailableDataFlavorSet() { - Set<DataFlavor> set = new HashSet<>(); - Transferable contents = getContents(null); - if (contents != null) { - DataFlavor[] flavors = contents.getTransferDataFlavors(); - if (flavors != null) { - set.addAll(Arrays.asList(flavors)); - } - } - return set; - } -}
--- a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/ClipboardOwner.java Tue Feb 17 10:48:24 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 1996, 2002, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package java.awt.datatransfer; - -/** - * Defines the interface for classes that will provide data to - * a clipboard. An instance of this interface becomes the owner - * of the contents of a clipboard (clipboard owner) if it is - * passed as an argument to - * {@link java.awt.datatransfer.Clipboard#setContents} method of - * the clipboard and this method returns successfully. - * The instance remains the clipboard owner until another application - * or another object within this application asserts ownership - * of this clipboard. - * - * @see java.awt.datatransfer.Clipboard - * - * @author Amy Fowler - */ - -public interface ClipboardOwner { - - /** - * Notifies this object that it is no longer the clipboard owner. - * This method will be called when another application or another - * object within this application asserts ownership of the clipboard. - * - * @param clipboard the clipboard that is no longer owned - * @param contents the contents which this owner had placed on the clipboard - */ - public void lostOwnership(Clipboard clipboard, Transferable contents); - -}
--- a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/DataFlavor.java Tue Feb 17 10:48:24 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1433 +0,0 @@ -/* - * Copyright (c) 1996, 2014, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package java.awt.datatransfer; - -import sun.datatransfer.DataFlavorUtil; -import sun.reflect.misc.ReflectUtil; - -import java.io.ByteArrayInputStream; -import java.io.CharArrayReader; -import java.io.Externalizable; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.io.OptionalDataException; -import java.io.Reader; -import java.io.StringReader; -import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.util.Arrays; -import java.util.Collections; -import java.util.Objects; - -import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; - -/** - * A {@code DataFlavor} provides meta information about data. {@code DataFlavor} - * is typically used to access data on the clipboard, or during - * a drag and drop operation. - * <p> - * An instance of {@code DataFlavor} encapsulates a content type as - * defined in <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a> - * and <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a>. - * A content type is typically referred to as a MIME type. - * <p> - * A content type consists of a media type (referred - * to as the primary type), a subtype, and optional parameters. See - * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a> - * for details on the syntax of a MIME type. - * <p> - * The JRE data transfer implementation interprets the parameter "class" - * of a MIME type as <B>a representation class</b>. - * The representation class reflects the class of the object being - * transferred. In other words, the representation class is the type of - * object returned by {@link Transferable#getTransferData}. - * For example, the MIME type of {@link #imageFlavor} is - * {@code "image/x-java-image;class=java.awt.Image"}, - * the primary type is {@code image}, the subtype is - * {@code x-java-image}, and the representation class is - * {@code java.awt.Image}. When {@code getTransferData} is invoked - * with a {@code DataFlavor} of {@code imageFlavor}, an instance of - * {@code java.awt.Image} is returned. - * It's important to note that {@code DataFlavor} does no error checking - * against the representation class. It is up to consumers of - * {@code DataFlavor}, such as {@code Transferable}, to honor the representation - * class. - * <br> - * Note, if you do not specify a representation class when - * creating a {@code DataFlavor}, the default - * representation class is used. See appropriate documentation for - * {@code DataFlavor}'s constructors. - * <p> - * Also, {@code DataFlavor} instances with the "text" primary - * MIME type may have a "charset" parameter. Refer to - * <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a> and - * {@link #selectBestTextFlavor} for details on "text" MIME types - * and the "charset" parameter. - * <p> - * Equality of {@code DataFlavors} is determined by the primary type, - * subtype, and representation class. Refer to {@link #equals(DataFlavor)} for - * details. When determining equality, any optional parameters are ignored. - * For example, the following produces two {@code DataFlavors} that - * are considered identical: - * <pre> - * DataFlavor flavor1 = new DataFlavor(Object.class, "X-test/test; class=<java.lang.Object>; foo=bar"); - * DataFlavor flavor2 = new DataFlavor(Object.class, "X-test/test; class=<java.lang.Object>; x=y"); - * // The following returns true. - * flavor1.equals(flavor2); - * </pre> - * As mentioned, {@code flavor1} and {@code flavor2} are considered identical. - * As such, asking a {@code Transferable} for either {@code DataFlavor} returns - * the same results. - * <p> - * For more information on using data transfer with Swing see - * the <a href="http://docs.oracle.com/javase/tutorial/uiswing/dnd/index.html"> - * How to Use Drag and Drop and Data Transfer</a>, - * section in <em>Java Tutorial</em>. - * - * @author Blake Sullivan - * @author Laurence P. G. Cable - * @author Jeff Dunn - */ -public class DataFlavor implements Externalizable, Cloneable { - - private static final long serialVersionUID = 8367026044764648243L; - private static final Class<InputStream> ioInputStreamClass = InputStream.class; - - /** - * Tries to load a class from: the bootstrap loader, the system loader, - * the context loader (if one is present) and finally the loader specified. - * - * @param className the name of the class to be loaded - * @param fallback the fallback loader - * @return the class loaded - * @exception ClassNotFoundException if class is not found - */ - protected final static Class<?> tryToLoadClass(String className, - ClassLoader fallback) - throws ClassNotFoundException - { - ReflectUtil.checkPackageAccess(className); - try { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(GET_CLASSLOADER_PERMISSION); - } - ClassLoader loader = ClassLoader.getSystemClassLoader(); - try { - // bootstrap class loader and system class loader if present - return Class.forName(className, true, loader); - } - catch (ClassNotFoundException exception) { - // thread context class loader if and only if present - loader = Thread.currentThread().getContextClassLoader(); - if (loader != null) { - try { - return Class.forName(className, true, loader); - } - catch (ClassNotFoundException e) { - // fallback to user's class loader - } - } - } - } catch (SecurityException exception) { - // ignore secured class loaders - } - return Class.forName(className, true, fallback); - } - - /* - * private initializer - */ - static private DataFlavor createConstant(Class<?> rc, String prn) { - try { - return new DataFlavor(rc, prn); - } catch (Exception e) { - return null; - } - } - - /* - * private initializer - */ - static private DataFlavor createConstant(String mt, String prn) { - try { - return new DataFlavor(mt, prn); - } catch (Exception e) { - return null; - } - } - - /* - * 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: - * <pre> - * representationClass = java.lang.String - * mimeType = "application/x-java-serialized-object" - * </pre> - */ - public static final DataFlavor stringFlavor = createConstant(java.lang.String.class, "Unicode String"); - - /** - * The <code>DataFlavor</code> representing a Java Image class, - * where: - * <pre> - * representationClass = java.awt.Image - * mimeType = "image/x-java-image" - * </pre> - */ - public static final DataFlavor imageFlavor = createConstant("image/x-java-image; class=java.awt.Image", "Image"); - - /** - * The <code>DataFlavor</code> representing plain text with Unicode - * encoding, where: - * <pre> - * representationClass = InputStream - * mimeType = "text/plain; charset=unicode" - * </pre> - * This <code>DataFlavor</code> has been <b>deprecated</b> because - * (1) Its representation is an InputStream, an 8-bit based representation, - * while Unicode is a 16-bit character set; and (2) The charset "unicode" - * is not well-defined. "unicode" implies a particular platform's - * implementation of Unicode, not a cross-platform implementation. - * - * @deprecated as of 1.3. Use <code>DataFlavor.getReaderForText(Transferable)</code> - * instead of <code>Transferable.getTransferData(DataFlavor.plainTextFlavor)</code>. - */ - @Deprecated - public static final DataFlavor plainTextFlavor = createConstant("text/plain; charset=unicode; class=java.io.InputStream", "Plain Text"); - - /** - * A MIME Content-Type of application/x-java-serialized-object represents - * a graph of Java object(s) that have been made persistent. - * - * The representation class associated with this <code>DataFlavor</code> - * identifies the Java type of an object returned as a reference - * from an invocation <code>java.awt.datatransfer.getTransferData</code>. - */ - public static final String javaSerializedObjectMimeType = "application/x-java-serialized-object"; - - /** - * To transfer a list of files to/from Java (and the underlying - * platform) a <code>DataFlavor</code> of this type/subtype and - * representation class of <code>java.util.List</code> is used. - * Each element of the list is required/guaranteed to be of type - * <code>java.io.File</code>. - */ - public static final DataFlavor javaFileListFlavor = createConstant("application/x-java-file-list;class=java.util.List", null); - - /** - * To transfer a reference to an arbitrary Java object reference that - * has no associated MIME Content-type, across a <code>Transferable</code> - * interface WITHIN THE SAME JVM, a <code>DataFlavor</code> - * with this type/subtype is used, with a <code>representationClass</code> - * equal to the type of the class/interface being passed across the - * <code>Transferable</code>. - * <p> - * The object reference returned from - * <code>Transferable.getTransferData</code> for a <code>DataFlavor</code> - * with this MIME Content-Type is required to be - * an instance of the representation Class of the <code>DataFlavor</code>. - */ - public static final String javaJVMLocalObjectMimeType = "application/x-java-jvm-local-objectref"; - - /** - * In order to pass a live link to a Remote object via a Drag and Drop - * <code>ACTION_LINK</code> operation a Mime Content Type of - * application/x-java-remote-object should be used, - * where the representation class of the <code>DataFlavor</code> - * represents the type of the <code>Remote</code> interface to be - * transferred. - */ - 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 - * <code>Externalizable</code> interface. It is not - * intended for public (client) use. - * - * @since 1.2 - */ - public DataFlavor() { - super(); - } - - /** - * Constructs a fully specified <code>DataFlavor</code>. - * - * @exception NullPointerException if either <code>primaryType</code>, - * <code>subType</code> or <code>representationClass</code> is null - */ - private DataFlavor(String primaryType, String subType, MimeTypeParameterList params, Class<?> representationClass, String humanPresentableName) { - super(); - if (primaryType == null) { - throw new NullPointerException("primaryType"); - } - if (subType == null) { - throw new NullPointerException("subType"); - } - if (representationClass == null) { - throw new NullPointerException("representationClass"); - } - - if (params == null) params = new MimeTypeParameterList(); - - params.set("class", representationClass.getName()); - - if (humanPresentableName == null) { - humanPresentableName = params.get("humanPresentableName"); - - if (humanPresentableName == null) - humanPresentableName = primaryType + "/" + subType; - } - - try { - mimeType = new MimeType(primaryType, subType, params); - } catch (MimeTypeParseException mtpe) { - throw new IllegalArgumentException("MimeType Parse Exception: " + mtpe.getMessage()); - } - - this.representationClass = representationClass; - this.humanPresentableName = humanPresentableName; - - mimeType.removeParameter("humanPresentableName"); - } - - /** - * Constructs a <code>DataFlavor</code> that represents a Java class. - * <p> - * The returned <code>DataFlavor</code> will have the following - * characteristics: - * <pre> - * representationClass = representationClass - * mimeType = application/x-java-serialized-object - * </pre> - * @param representationClass the class used to transfer data in this flavor - * @param humanPresentableName the human-readable string used to identify - * this flavor; if this parameter is <code>null</code> - * then the value of the MIME Content Type is used - * @exception NullPointerException if <code>representationClass</code> is null - */ - public DataFlavor(Class<?> representationClass, String humanPresentableName) { - this("application", "x-java-serialized-object", null, representationClass, humanPresentableName); - if (representationClass == null) { - throw new NullPointerException("representationClass"); - } - } - - /** - * Constructs a <code>DataFlavor</code> that represents a - * <code>MimeType</code>. - * <p> - * The returned <code>DataFlavor</code> will have the following - * characteristics: - * <p> - * If the <code>mimeType</code> is - * "application/x-java-serialized-object; class=<representation class>", - * the result is the same as calling - * <code>new DataFlavor(Class.forName(<representation class>)</code>. - * <p> - * Otherwise: - * <pre> - * representationClass = InputStream - * mimeType = mimeType - * </pre> - * @param mimeType the string used to identify the MIME type for this flavor; - * if the <code>mimeType</code> does not specify a - * "class=" parameter, or if the class is not successfully - * loaded, then an <code>IllegalArgumentException</code> - * is thrown - * @param humanPresentableName the human-readable string used to identify - * this flavor; if this parameter is <code>null</code> - * then the value of the MIME Content Type is used - * @exception IllegalArgumentException if <code>mimeType</code> is - * invalid or if the class is not successfully loaded - * @exception NullPointerException if <code>mimeType</code> is null - */ - public DataFlavor(String mimeType, String humanPresentableName) { - super(); - if (mimeType == null) { - throw new NullPointerException("mimeType"); - } - try { - initialize(mimeType, humanPresentableName, this.getClass().getClassLoader()); - } catch (MimeTypeParseException mtpe) { - throw new IllegalArgumentException("failed to parse:" + mimeType); - } catch (ClassNotFoundException cnfe) { - throw new IllegalArgumentException("can't find specified class: " + cnfe.getMessage()); - } - } - - /** - * Constructs a <code>DataFlavor</code> that represents a - * <code>MimeType</code>. - * <p> - * The returned <code>DataFlavor</code> will have the following - * characteristics: - * <p> - * If the mimeType is - * "application/x-java-serialized-object; class=<representation class>", - * the result is the same as calling - * <code>new DataFlavor(Class.forName(<representation class>)</code>. - * <p> - * Otherwise: - * <pre> - * representationClass = InputStream - * mimeType = mimeType - * </pre> - * @param mimeType the string used to identify the MIME type for this flavor - * @param humanPresentableName the human-readable string used to - * identify this flavor - * @param classLoader the class loader to use - * @exception ClassNotFoundException if the class is not loaded - * @exception IllegalArgumentException if <code>mimeType</code> is - * invalid - * @exception NullPointerException if <code>mimeType</code> is null - */ - public DataFlavor(String mimeType, String humanPresentableName, ClassLoader classLoader) throws ClassNotFoundException { - super(); - if (mimeType == null) { - throw new NullPointerException("mimeType"); - } - try { - initialize(mimeType, humanPresentableName, classLoader); - } catch (MimeTypeParseException mtpe) { - throw new IllegalArgumentException("failed to parse:" + mimeType); - } - } - - /** - * Constructs a <code>DataFlavor</code> from a <code>mimeType</code> string. - * The string can specify a "class=<fully specified Java class name>" - * parameter to create a <code>DataFlavor</code> with the desired - * representation class. If the string does not contain "class=" parameter, - * <code>java.io.InputStream</code> is used as default. - * - * @param mimeType the string used to identify the MIME type for this flavor; - * if the class specified by "class=" parameter is not - * successfully loaded, then an - * <code>ClassNotFoundException</code> is thrown - * @exception ClassNotFoundException if the class is not loaded - * @exception IllegalArgumentException if <code>mimeType</code> is - * invalid - * @exception NullPointerException if <code>mimeType</code> is null - */ - public DataFlavor(String mimeType) throws ClassNotFoundException { - super(); - if (mimeType == null) { - throw new NullPointerException("mimeType"); - } - try { - initialize(mimeType, null, this.getClass().getClassLoader()); - } catch (MimeTypeParseException mtpe) { - throw new IllegalArgumentException("failed to parse:" + mimeType); - } - } - - /** - * Common initialization code called from various constructors. - * - * @param mimeType the MIME Content Type (must have a class= param) - * @param humanPresentableName the human Presentable Name or - * <code>null</code> - * @param classLoader the fallback class loader to resolve against - * - * @throws MimeTypeParseException - * @throws ClassNotFoundException - * @throws NullPointerException if <code>mimeType</code> is null - * - * @see #tryToLoadClass - */ - private void initialize(String mimeType, String humanPresentableName, ClassLoader classLoader) throws MimeTypeParseException, ClassNotFoundException { - if (mimeType == null) { - throw new NullPointerException("mimeType"); - } - - this.mimeType = new MimeType(mimeType); // throws - - String rcn = getParameter("class"); - - if (rcn == null) { - if ("application/x-java-serialized-object".equals(this.mimeType.getBaseType())) - - throw new IllegalArgumentException("no representation class specified for:" + mimeType); - else - representationClass = java.io.InputStream.class; // default - } else { // got a class name - representationClass = DataFlavor.tryToLoadClass(rcn, classLoader); - } - - this.mimeType.setParameter("class", representationClass.getName()); - - if (humanPresentableName == null) { - humanPresentableName = this.mimeType.getParameter("humanPresentableName"); - if (humanPresentableName == null) - humanPresentableName = this.mimeType.getPrimaryType() + "/" + this.mimeType.getSubType(); - } - - this.humanPresentableName = humanPresentableName; // set it. - - this.mimeType.removeParameter("humanPresentableName"); // just in case - } - - /** - * String representation of this <code>DataFlavor</code> and its - * parameters. The resulting <code>String</code> contains the name of - * the <code>DataFlavor</code> class, this flavor's MIME type, and its - * representation class. If this flavor has a primary MIME type of "text", - * supports the charset parameter, and has an encoded representation, the - * flavor's charset is also included. See <code>selectBestTextFlavor</code> - * for a list of text flavors which support the charset parameter. - * - * @return string representation of this <code>DataFlavor</code> - * @see #selectBestTextFlavor - */ - public String toString() { - String string = getClass().getName(); - string += "["+paramString()+"]"; - return string; - } - - private String paramString() { - String params = ""; - params += "mimetype="; - if (mimeType == null) { - params += "null"; - } else { - params += mimeType.getBaseType(); - } - params += ";representationclass="; - if (representationClass == null) { - params += "null"; - } else { - params += representationClass.getName(); - } - if (DataFlavorUtil.isFlavorCharsetTextType(this) && - (isRepresentationClassInputStream() || - isRepresentationClassByteBuffer() || - byte[].class.equals(representationClass))) - { - params += ";charset=" + DataFlavorUtil.getTextCharset(this); - } - return params; - } - - /** - * Returns a <code>DataFlavor</code> representing plain text with Unicode - * encoding, where: - * <pre> - * representationClass = java.io.InputStream - * mimeType = "text/plain; - * charset=<platform default Unicode encoding>" - * </pre> - * Sun's implementation for Microsoft Windows uses the encoding <code>utf-16le</code>. - * Sun's implementation for Solaris and Linux uses the encoding - * <code>iso-10646-ucs-2</code>. - * - * @return a <code>DataFlavor</code> representing plain text - * with Unicode encoding - * @since 1.3 - */ - public static final DataFlavor getTextPlainUnicodeFlavor() { - return new DataFlavor( - "text/plain;charset=" + DataFlavorUtil.getDesktopService().getDefaultUnicodeEncoding() - +";class=java.io.InputStream", "Plain Text"); - } - - /** - * Selects the best text <code>DataFlavor</code> from an array of <code> - * DataFlavor</code>s. Only <code>DataFlavor.stringFlavor</code>, and - * equivalent flavors, and flavors that have a primary MIME type of "text", - * are considered for selection. - * <p> - * Flavors are first sorted by their MIME types in the following order: - * <ul> - * <li>"text/sgml" - * <li>"text/xml" - * <li>"text/html" - * <li>"text/rtf" - * <li>"text/enriched" - * <li>"text/richtext" - * <li>"text/uri-list" - * <li>"text/tab-separated-values" - * <li>"text/t140" - * <li>"text/rfc822-headers" - * <li>"text/parityfec" - * <li>"text/directory" - * <li>"text/css" - * <li>"text/calendar" - * <li>"application/x-java-serialized-object" - * <li>"text/plain" - * <li>"text/<other>" - * </ul> - * <p>For example, "text/sgml" will be selected over - * "text/html", and <code>DataFlavor.stringFlavor</code> will be chosen - * over <code>DataFlavor.plainTextFlavor</code>. - * <p> - * If two or more flavors share the best MIME type in the array, then that - * MIME type will be checked to see if it supports the charset parameter. - * <p> - * The following MIME types support, or are treated as though they support, - * the charset parameter: - * <ul> - * <li>"text/sgml" - * <li>"text/xml" - * <li>"text/html" - * <li>"text/enriched" - * <li>"text/richtext" - * <li>"text/uri-list" - * <li>"text/directory" - * <li>"text/css" - * <li>"text/calendar" - * <li>"application/x-java-serialized-object" - * <li>"text/plain" - * </ul> - * The following MIME types do not support, or are treated as though they - * do not support, the charset parameter: - * <ul> - * <li>"text/rtf" - * <li>"text/tab-separated-values" - * <li>"text/t140" - * <li>"text/rfc822-headers" - * <li>"text/parityfec" - * </ul> - * For "text/<other>" MIME types, the first time the JRE needs to - * determine whether the MIME type supports the charset parameter, it will - * check whether the parameter is explicitly listed in an arbitrarily - * chosen <code>DataFlavor</code> which uses that MIME type. If so, the JRE - * will assume from that point on that the MIME type supports the charset - * parameter and will not check again. If the parameter is not explicitly - * listed, the JRE will assume from that point on that the MIME type does - * not support the charset parameter and will not check again. Because - * this check is performed on an arbitrarily chosen - * <code>DataFlavor</code>, developers must ensure that all - * <code>DataFlavor</code>s with a "text/<other>" MIME type specify - * the charset parameter if it is supported by that MIME type. Developers - * should never rely on the JRE to substitute the platform's default - * charset for a "text/<other>" DataFlavor. Failure to adhere to this - * restriction will lead to undefined behavior. - * <p> - * If the best MIME type in the array does not support the charset - * parameter, the flavors which share that MIME type will then be sorted by - * their representation classes in the following order: - * <code>java.io.InputStream</code>, <code>java.nio.ByteBuffer</code>, - * <code>[B</code>, <all others>. - * <p> - * If two or more flavors share the best representation class, or if no - * flavor has one of the three specified representations, then one of those - * flavors will be chosen non-deterministically. - * <p> - * If the best MIME type in the array does support the charset parameter, - * the flavors which share that MIME type will then be sorted by their - * representation classes in the following order: - * <code>java.io.Reader</code>, <code>java.lang.String</code>, - * <code>java.nio.CharBuffer</code>, <code>[C</code>, <all others>. - * <p> - * If two or more flavors share the best representation class, and that - * representation is one of the four explicitly listed, then one of those - * flavors will be chosen non-deterministically. If, however, no flavor has - * one of the four specified representations, the flavors will then be - * sorted by their charsets. Unicode charsets, such as "UTF-16", "UTF-8", - * "UTF-16BE", "UTF-16LE", and their aliases, are considered best. After - * them, the platform default charset and its aliases are selected. - * "US-ASCII" and its aliases are worst. All other charsets are chosen in - * alphabetical order, but only charsets supported by this implementation - * of the Java platform will be considered. - * <p> - * If two or more flavors share the best charset, the flavors will then - * again be sorted by their representation classes in the following order: - * <code>java.io.InputStream</code>, <code>java.nio.ByteBuffer</code>, - * <code>[B</code>, <all others>. - * <p> - * If two or more flavors share the best representation class, or if no - * flavor has one of the three specified representations, then one of those - * flavors will be chosen non-deterministically. - * - * @param availableFlavors an array of available <code>DataFlavor</code>s - * @return the best (highest fidelity) flavor according to the rules - * specified above, or <code>null</code>, - * if <code>availableFlavors</code> is <code>null</code>, - * has zero length, or contains no text flavors - * @since 1.3 - */ - public static final DataFlavor selectBestTextFlavor( - DataFlavor[] availableFlavors) { - if (availableFlavors == null || availableFlavors.length == 0) { - return null; - } - - DataFlavor bestFlavor = Collections.max(Arrays.asList(availableFlavors), - DataFlavorUtil.getTextFlavorComparator()); - - if (!bestFlavor.isFlavorTextType()) { - return null; - } - - return bestFlavor; - } - - /** - * Gets a Reader for a text flavor, decoded, if necessary, for the expected - * charset (encoding). The supported representation classes are - * <code>java.io.Reader</code>, <code>java.lang.String</code>, - * <code>java.nio.CharBuffer</code>, <code>[C</code>, - * <code>java.io.InputStream</code>, <code>java.nio.ByteBuffer</code>, - * and <code>[B</code>. - * <p> - * Because text flavors which do not support the charset parameter are - * encoded in a non-standard format, this method should not be called for - * such flavors. However, in order to maintain backward-compatibility, - * if this method is called for such a flavor, this method will treat the - * flavor as though it supports the charset parameter and attempt to - * decode it accordingly. See <code>selectBestTextFlavor</code> for a list - * of text flavors which do not support the charset parameter. - * - * @param transferable the <code>Transferable</code> whose data will be - * requested in this flavor - * - * @return a <code>Reader</code> to read the <code>Transferable</code>'s - * data - * - * @exception IllegalArgumentException if the representation class - * is not one of the seven listed above - * @exception IllegalArgumentException if the <code>Transferable</code> - * has <code>null</code> data - * @exception NullPointerException if the <code>Transferable</code> is - * <code>null</code> - * @exception UnsupportedEncodingException if this flavor's representation - * is <code>java.io.InputStream</code>, - * <code>java.nio.ByteBuffer</code>, or <code>[B</code> and - * this flavor's encoding is not supported by this - * implementation of the Java platform - * @exception UnsupportedFlavorException if the <code>Transferable</code> - * does not support this flavor - * @exception IOException if the data cannot be read because of an - * I/O error - * @see #selectBestTextFlavor - * @since 1.3 - */ - public Reader getReaderForText(Transferable transferable) - throws UnsupportedFlavorException, IOException - { - Object transferObject = transferable.getTransferData(this); - if (transferObject == null) { - throw new IllegalArgumentException - ("getTransferData() returned null"); - } - - if (transferObject instanceof Reader) { - return (Reader)transferObject; - } else if (transferObject instanceof String) { - return new StringReader((String)transferObject); - } else if (transferObject instanceof CharBuffer) { - CharBuffer buffer = (CharBuffer)transferObject; - int size = buffer.remaining(); - char[] chars = new char[size]; - buffer.get(chars, 0, size); - return new CharArrayReader(chars); - } else if (transferObject instanceof char[]) { - return new CharArrayReader((char[])transferObject); - } - - InputStream stream = null; - - if (transferObject instanceof InputStream) { - stream = (InputStream)transferObject; - } else if (transferObject instanceof ByteBuffer) { - ByteBuffer buffer = (ByteBuffer)transferObject; - int size = buffer.remaining(); - byte[] bytes = new byte[size]; - buffer.get(bytes, 0, size); - stream = new ByteArrayInputStream(bytes); - } else if (transferObject instanceof byte[]) { - stream = new ByteArrayInputStream((byte[])transferObject); - } - - if (stream == null) { - throw new IllegalArgumentException("transfer data is not Reader, String, CharBuffer, char array, InputStream, ByteBuffer, or byte array"); - } - - String encoding = getParameter("charset"); - return (encoding == null) - ? new InputStreamReader(stream) - : new InputStreamReader(stream, encoding); - } - - /** - * Returns the MIME type string for this <code>DataFlavor</code>. - * @return the MIME type string for this flavor - */ - public String getMimeType() { - return (mimeType != null) ? mimeType.toString() : null; - } - - /** - * Returns the <code>Class</code> which objects supporting this - * <code>DataFlavor</code> will return when this <code>DataFlavor</code> - * is requested. - * @return the <code>Class</code> which objects supporting this - * <code>DataFlavor</code> will return when this <code>DataFlavor</code> - * is requested - */ - public Class<?> getRepresentationClass() { - return representationClass; - } - - /** - * Returns the human presentable name for the data format that this - * <code>DataFlavor</code> represents. This name would be localized - * for different countries. - * @return the human presentable name for the data format that this - * <code>DataFlavor</code> represents - */ - public String getHumanPresentableName() { - return humanPresentableName; - } - - /** - * Returns the primary MIME type for this <code>DataFlavor</code>. - * @return the primary MIME type of this <code>DataFlavor</code> - */ - public String getPrimaryType() { - return (mimeType != null) ? mimeType.getPrimaryType() : null; - } - - /** - * Returns the sub MIME type of this <code>DataFlavor</code>. - * @return the Sub MIME type of this <code>DataFlavor</code> - */ - public String getSubType() { - return (mimeType != null) ? mimeType.getSubType() : null; - } - - /** - * Returns the human presentable name for this <code>DataFlavor</code> - * if <code>paramName</code> equals "humanPresentableName". Otherwise - * returns the MIME type value associated with <code>paramName</code>. - * - * @param paramName the parameter name requested - * @return the value of the name parameter, or <code>null</code> - * if there is no associated value - */ - public String getParameter(String paramName) { - if (paramName.equals("humanPresentableName")) { - return humanPresentableName; - } else { - return (mimeType != null) - ? mimeType.getParameter(paramName) : null; - } - } - - /** - * Sets the human presentable name for the data format that this - * <code>DataFlavor</code> represents. This name would be localized - * for different countries. - * @param humanPresentableName the new human presentable name - */ - public void setHumanPresentableName(String humanPresentableName) { - this.humanPresentableName = humanPresentableName; - } - - /** - * {@inheritDoc} - * <p> - * The equals comparison for the {@code DataFlavor} class is implemented - * as follows: Two <code>DataFlavor</code>s are considered equal if and - * only if their MIME primary type and subtype and representation class are - * equal. Additionally, if the primary type is "text", the subtype denotes - * a text flavor which supports the charset parameter, and the - * representation class is not <code>java.io.Reader</code>, - * <code>java.lang.String</code>, <code>java.nio.CharBuffer</code>, or - * <code>[C</code>, the <code>charset</code> parameter must also be equal. - * If a charset is not explicitly specified for one or both - * <code>DataFlavor</code>s, the platform default encoding is assumed. See - * <code>selectBestTextFlavor</code> for a list of text flavors which - * support the charset parameter. - * - * @param o the <code>Object</code> to compare with <code>this</code> - * @return <code>true</code> if <code>that</code> is equivalent to this - * <code>DataFlavor</code>; <code>false</code> otherwise - * @see #selectBestTextFlavor - */ - public boolean equals(Object o) { - return ((o instanceof DataFlavor) && equals((DataFlavor)o)); - } - - /** - * This method has the same behavior as {@link #equals(Object)}. - * The only difference being that it takes a {@code DataFlavor} instance - * as a parameter. - * - * @param that the <code>DataFlavor</code> to compare with - * <code>this</code> - * @return <code>true</code> if <code>that</code> is equivalent to this - * <code>DataFlavor</code>; <code>false</code> otherwise - * @see #selectBestTextFlavor - */ - public boolean equals(DataFlavor that) { - if (that == null) { - return false; - } - if (this == that) { - return true; - } - - if (!Objects.equals(this.getRepresentationClass(), that.getRepresentationClass())) { - return false; - } - - if (mimeType == null) { - if (that.mimeType != null) { - return false; - } - } else { - if (!mimeType.match(that.mimeType)) { - return false; - } - - if ("text".equals(getPrimaryType())) { - if (DataFlavorUtil.doesSubtypeSupportCharset(this) - && representationClass != null - && !isStandardTextRepresentationClass()) { - String thisCharset = - DataFlavorUtil.canonicalName(this.getParameter("charset")); - String thatCharset = - DataFlavorUtil.canonicalName(that.getParameter("charset")); - if (!Objects.equals(thisCharset, thatCharset)) { - return false; - } - } - - if ("html".equals(getSubType())) { - String thisDocument = this.getParameter("document"); - String thatDocument = that.getParameter("document"); - if (!Objects.equals(thisDocument, thatDocument)) { - return false; - } - } - } - } - - return true; - } - - /** - * Compares only the <code>mimeType</code> against the passed in - * <code>String</code> and <code>representationClass</code> is - * not considered in the comparison. - * - * If <code>representationClass</code> needs to be compared, then - * <code>equals(new DataFlavor(s))</code> may be used. - * @deprecated As inconsistent with <code>hashCode()</code> contract, - * use <code>isMimeTypeEqual(String)</code> instead. - * @param s the {@code mimeType} to compare. - * @return true if the String (MimeType) is equal; false otherwise or if - * {@code s} is {@code null} - */ - @Deprecated - public boolean equals(String s) { - if (s == null || mimeType == null) - return false; - return isMimeTypeEqual(s); - } - - /** - * Returns hash code for this <code>DataFlavor</code>. - * For two equal <code>DataFlavor</code>s, hash codes are equal. - * For the <code>String</code> - * that matches <code>DataFlavor.equals(String)</code>, it is not - * guaranteed that <code>DataFlavor</code>'s hash code is equal - * to the hash code of the <code>String</code>. - * - * @return a hash code for this <code>DataFlavor</code> - */ - public int hashCode() { - int total = 0; - - if (representationClass != null) { - total += representationClass.hashCode(); - } - - if (mimeType != null) { - String primaryType = mimeType.getPrimaryType(); - if (primaryType != null) { - total += primaryType.hashCode(); - } - - // Do not add subType.hashCode() to the total. equals uses - // MimeType.match which reports a match if one or both of the - // subTypes is '*', regardless of the other subType. - - if ("text".equals(primaryType)) { - if (DataFlavorUtil.doesSubtypeSupportCharset(this) - && representationClass != null - && !isStandardTextRepresentationClass()) { - String charset = DataFlavorUtil.canonicalName(getParameter("charset")); - if (charset != null) { - total += charset.hashCode(); - } - } - - if ("html".equals(getSubType())) { - String document = this.getParameter("document"); - if (document != null) { - total += document.hashCode(); - } - } - } - } - - return total; - } - - /** - * Identical to {@link #equals(DataFlavor)}. - * - * @param that the <code>DataFlavor</code> to compare with - * <code>this</code> - * @return <code>true</code> if <code>that</code> is equivalent to this - * <code>DataFlavor</code>; <code>false</code> otherwise - * @see #selectBestTextFlavor - * @since 1.3 - */ - public boolean match(DataFlavor that) { - return equals(that); - } - - /** - * Returns whether the string representation of the MIME type passed in - * is equivalent to the MIME type of this <code>DataFlavor</code>. - * Parameters are not included in the comparison. - * - * @param mimeType the string representation of the MIME type - * @return true if the string representation of the MIME type passed in is - * equivalent to the MIME type of this <code>DataFlavor</code>; - * false otherwise - * @throws NullPointerException if mimeType is <code>null</code> - */ - public boolean isMimeTypeEqual(String mimeType) { - // JCK Test DataFlavor0117: if 'mimeType' is null, throw NPE - if (mimeType == null) { - throw new NullPointerException("mimeType"); - } - if (this.mimeType == null) { - return false; - } - try { - return this.mimeType.match(new MimeType(mimeType)); - } catch (MimeTypeParseException mtpe) { - return false; - } - } - - /** - * Compares the <code>mimeType</code> of two <code>DataFlavor</code> - * objects. No parameters are considered. - * - * @param dataFlavor the <code>DataFlavor</code> to be compared - * @return true if the <code>MimeType</code>s are equal, - * otherwise false - */ - - public final boolean isMimeTypeEqual(DataFlavor dataFlavor) { - return isMimeTypeEqual(dataFlavor.mimeType); - } - - /** - * Compares the <code>mimeType</code> of two <code>DataFlavor</code> - * objects. No parameters are considered. - * - * @return true if the <code>MimeType</code>s are equal, - * otherwise false - */ - - private boolean isMimeTypeEqual(MimeType mtype) { - if (this.mimeType == null) { - return (mtype == null); - } - return mimeType.match(mtype); - } - - /** - * Checks if the representation class is one of the standard text - * representation classes. - * - * @return true if the representation class is one of the standard text - * representation classes, otherwise false - */ - private boolean isStandardTextRepresentationClass() { - return isRepresentationClassReader() - || String.class.equals(representationClass) - || isRepresentationClassCharBuffer() - || char[].class.equals(representationClass); - } - - /** - * Does the <code>DataFlavor</code> represent a serialized object? - * @return whether or not a serialized object is represented - */ - public boolean isMimeTypeSerializedObject() { - return isMimeTypeEqual(javaSerializedObjectMimeType); - } - - /** - * Returns the default representation class. - * @return the default representation class - */ - public final Class<?> getDefaultRepresentationClass() { - return ioInputStreamClass; - } - - /** - * Returns the name of the default representation class. - * @return the name of the default representation class - */ - public final String getDefaultRepresentationClassAsString() { - return getDefaultRepresentationClass().getName(); - } - - /** - * Does the <code>DataFlavor</code> represent a - * <code>java.io.InputStream</code>? - * @return whether or not this {@code DataFlavor} represent a - * {@code java.io.InputStream} - */ - public boolean isRepresentationClassInputStream() { - return ioInputStreamClass.isAssignableFrom(representationClass); - } - - /** - * Returns whether the representation class for this - * <code>DataFlavor</code> is <code>java.io.Reader</code> or a subclass - * thereof. - * @return whether or not the representation class for this - * {@code DataFlavor} is {@code java.io.Reader} or a subclass - * thereof - * - * @since 1.4 - */ - public boolean isRepresentationClassReader() { - return java.io.Reader.class.isAssignableFrom(representationClass); - } - - /** - * Returns whether the representation class for this - * <code>DataFlavor</code> is <code>java.nio.CharBuffer</code> or a - * subclass thereof. - * @return whether or not the representation class for this - * {@code DataFlavor} is {@code java.nio.CharBuffer} or a subclass - * thereof - * - * @since 1.4 - */ - public boolean isRepresentationClassCharBuffer() { - return java.nio.CharBuffer.class.isAssignableFrom(representationClass); - } - - /** - * Returns whether the representation class for this - * <code>DataFlavor</code> is <code>java.nio.ByteBuffer</code> or a - * subclass thereof. - * @return whether or not the representation class for this - * {@code DataFlavor} is {@code java.nio.ByteBuffer} or a subclass - * thereof - * - * @since 1.4 - */ - public boolean isRepresentationClassByteBuffer() { - return java.nio.ByteBuffer.class.isAssignableFrom(representationClass); - } - - /** - * Returns true if the representation class can be serialized. - * @return true if the representation class can be serialized - */ - - public boolean isRepresentationClassSerializable() { - return java.io.Serializable.class.isAssignableFrom(representationClass); - } - - /** - * Returns true if the representation class is <code>Remote</code>. - * @return true if the representation class is <code>Remote</code> - */ - public boolean isRepresentationClassRemote() { - return DataFlavorUtil.RMI.isRemote(representationClass); - } - - /** - * Returns true if the <code>DataFlavor</code> specified represents - * a serialized object. - * @return true if the <code>DataFlavor</code> specified represents - * a Serialized Object - */ - - public boolean isFlavorSerializedObjectType() { - return isRepresentationClassSerializable() && isMimeTypeEqual(javaSerializedObjectMimeType); - } - - /** - * Returns true if the <code>DataFlavor</code> specified represents - * a remote object. - * @return true if the <code>DataFlavor</code> specified represents - * a Remote Object - */ - - public boolean isFlavorRemoteObjectType() { - return isRepresentationClassRemote() - && isRepresentationClassSerializable() - && isMimeTypeEqual(javaRemoteObjectMimeType); - } - - - /** - * Returns true if the <code>DataFlavor</code> specified represents - * a list of file objects. - * @return true if the <code>DataFlavor</code> specified represents - * a List of File objects - */ - - public boolean isFlavorJavaFileListType() { - if (mimeType == null || representationClass == null) - return false; - return java.util.List.class.isAssignableFrom(representationClass) && - mimeType.match(javaFileListFlavor.mimeType); - - } - - /** - * Returns whether this <code>DataFlavor</code> is a valid text flavor for - * this implementation of the Java platform. Only flavors equivalent to - * <code>DataFlavor.stringFlavor</code> and <code>DataFlavor</code>s with - * a primary MIME type of "text" can be valid text flavors. - * <p> - * If this flavor supports the charset parameter, it must be equivalent to - * <code>DataFlavor.stringFlavor</code>, or its representation must be - * <code>java.io.Reader</code>, <code>java.lang.String</code>, - * <code>java.nio.CharBuffer</code>, <code>[C</code>, - * <code>java.io.InputStream</code>, <code>java.nio.ByteBuffer</code>, or - * <code>[B</code>. If the representation is - * <code>java.io.InputStream</code>, <code>java.nio.ByteBuffer</code>, or - * <code>[B</code>, then this flavor's <code>charset</code> parameter must - * be supported by this implementation of the Java platform. If a charset - * is not specified, then the platform default charset, which is always - * supported, is assumed. - * <p> - * If this flavor does not support the charset parameter, its - * representation must be <code>java.io.InputStream</code>, - * <code>java.nio.ByteBuffer</code>, or <code>[B</code>. - * <p> - * See <code>selectBestTextFlavor</code> for a list of text flavors which - * support the charset parameter. - * - * @return <code>true</code> if this <code>DataFlavor</code> is a valid - * text flavor as described above; <code>false</code> otherwise - * @see #selectBestTextFlavor - * @since 1.4 - */ - public boolean isFlavorTextType() { - return (DataFlavorUtil.isFlavorCharsetTextType(this) || - DataFlavorUtil.isFlavorNoncharsetTextType(this)); - } - - /** - * Serializes this <code>DataFlavor</code>. - */ - - public synchronized void writeExternal(ObjectOutput os) throws IOException { - if (mimeType != null) { - mimeType.setParameter("humanPresentableName", humanPresentableName); - os.writeObject(mimeType); - mimeType.removeParameter("humanPresentableName"); - } else { - os.writeObject(null); - } - - os.writeObject(representationClass); - } - - /** - * Restores this <code>DataFlavor</code> from a Serialized state. - */ - - public synchronized void readExternal(ObjectInput is) throws IOException , ClassNotFoundException { - String rcn = null; - mimeType = (MimeType)is.readObject(); - - if (mimeType != null) { - humanPresentableName = - mimeType.getParameter("humanPresentableName"); - mimeType.removeParameter("humanPresentableName"); - rcn = mimeType.getParameter("class"); - if (rcn == null) { - throw new IOException("no class parameter specified in: " + - mimeType); - } - } - - try { - representationClass = (Class)is.readObject(); - } catch (OptionalDataException ode) { - if (!ode.eof || ode.length != 0) { - throw ode; - } - // Ensure backward compatibility. - // Old versions didn't write the representation class to the stream. - if (rcn != null) { - representationClass = - DataFlavor.tryToLoadClass(rcn, getClass().getClassLoader()); - } - } - } - - /** - * Returns a clone of this <code>DataFlavor</code>. - * @return a clone of this <code>DataFlavor</code> - */ - - public Object clone() throws CloneNotSupportedException { - Object newObj = super.clone(); - if (mimeType != null) { - ((DataFlavor)newObj).mimeType = (MimeType)mimeType.clone(); - } - return newObj; - } // clone() - - /** - * Called on <code>DataFlavor</code> for every MIME Type parameter - * to allow <code>DataFlavor</code> subclasses to handle special - * parameters like the text/plain <code>charset</code> - * parameters, whose values are case insensitive. (MIME type parameter - * values are supposed to be case sensitive. - * <p> - * This method is called for each parameter name/value pair and should - * return the normalized representation of the <code>parameterValue</code>. - * - * This method is never invoked by this implementation from 1.1 onwards. - * - * @param parameterName the parameter name - * @param parameterValue the parameter value - * @return the parameter value - * @deprecated - */ - @Deprecated - protected String normalizeMimeTypeParameter(String parameterName, String parameterValue) { - return parameterValue; - } - - /** - * Called for each MIME type string to give <code>DataFlavor</code> subtypes - * the opportunity to change how the normalization of MIME types is - * accomplished. One possible use would be to add default - * parameter/value pairs in cases where none are present in the MIME - * type string passed in. - * - * This method is never invoked by this implementation from 1.1 onwards. - * - * @param mimeType the mime type - * @return the mime type - * @deprecated - */ - @Deprecated - protected String normalizeMimeType(String mimeType) { - return mimeType; - } - - /* - * fields - */ - - /* placeholder for caching any platform-specific data for flavor */ - - transient int atom; - - /* Mime Type of DataFlavor */ - - MimeType mimeType; - - private String humanPresentableName; - - /** Java class of objects this DataFlavor represents **/ - - private Class<?> representationClass; - -} // class DataFlavor
--- a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/FlavorEvent.java Tue Feb 17 10:48:24 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2003, 2014, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package java.awt.datatransfer; - -import java.util.EventObject; - - -/** - * <code>FlavorEvent</code> is used to notify interested parties - * that available {@link DataFlavor}s have changed in the - * {@link Clipboard} (the event source). - * - * @see FlavorListener - * - * @author Alexander Gerasimov - * @since 1.5 - */ -public class FlavorEvent extends EventObject { - private static final long serialVersionUID = -5842664112252414548L; - - /** - * Constructs a <code>FlavorEvent</code> object. - * - * @param source the <code>Clipboard</code> that is the source of the event - * - * @throws IllegalArgumentException if the {@code source} is {@code null} - */ - public FlavorEvent(Clipboard source) { - super(source); - } -}
--- a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/FlavorListener.java Tue Feb 17 10:48:24 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2003, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package java.awt.datatransfer; - -import java.util.EventListener; - - -/** - * Defines an object which listens for {@link FlavorEvent}s. - * - * @author Alexander Gerasimov - * @since 1.5 - */ -public interface FlavorListener extends EventListener { - /** - * Invoked when the target {@link Clipboard} of the listener - * has changed its available {@link DataFlavor}s. - * <p> - * Some notifications may be redundant — they are not - * caused by a change of the set of DataFlavors available - * on the clipboard. - * For example, if the clipboard subsystem supposes that - * the system clipboard's contents has been changed but it - * can't ascertain whether its DataFlavors have been changed - * because of some exceptional condition when accessing the - * clipboard, the notification is sent to ensure from omitting - * a significant notification. Ordinarily, those redundant - * notifications should be occasional. - * - * @param e a <code>FlavorEvent</code> object - */ - void flavorsChanged(FlavorEvent e); -}
--- a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/FlavorMap.java Tue Feb 17 10:48:24 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * Copyright (c) 1997, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package java.awt.datatransfer; - -import java.util.Map; - - -/** - * A two-way Map between "natives" (Strings), which correspond to platform- - * specific data formats, and "flavors" (DataFlavors), which correspond to - * platform-independent MIME types. FlavorMaps need not be symmetric, but - * typically are. - * - * - * @since 1.2 - */ -public interface FlavorMap { - - /** - * Returns a <code>Map</code> of the specified <code>DataFlavor</code>s to - * their corresponding <code>String</code> native. The returned - * <code>Map</code> is a modifiable copy of this <code>FlavorMap</code>'s - * internal data. Client code is free to modify the <code>Map</code> - * without affecting this object. - * - * @param flavors an array of <code>DataFlavor</code>s which will be the - * key set of the returned <code>Map</code>. If <code>null</code> is - * specified, a mapping of all <code>DataFlavor</code>s currently - * known to this <code>FlavorMap</code> to their corresponding - * <code>String</code> natives will be returned. - * @return a <code>java.util.Map</code> of <code>DataFlavor</code>s to - * <code>String</code> natives - */ - Map<DataFlavor,String> getNativesForFlavors(DataFlavor[] flavors); - - /** - * Returns a <code>Map</code> of the specified <code>String</code> natives - * to their corresponding <code>DataFlavor</code>. The returned - * <code>Map</code> is a modifiable copy of this <code>FlavorMap</code>'s - * internal data. Client code is free to modify the <code>Map</code> - * without affecting this object. - * - * @param natives an array of <code>String</code>s which will be the - * key set of the returned <code>Map</code>. If <code>null</code> is - * specified, a mapping of all <code>String</code> natives currently - * known to this <code>FlavorMap</code> to their corresponding - * <code>DataFlavor</code>s will be returned. - * @return a <code>java.util.Map</code> of <code>String</code> natives to - * <code>DataFlavor</code>s - */ - Map<String,DataFlavor> getFlavorsForNatives(String[] natives); -}
--- a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/FlavorTable.java Tue Feb 17 10:48:24 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2000, 2004, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package java.awt.datatransfer; - -import java.util.List; - - -/** - * A FlavorMap which relaxes the traditional 1-to-1 restriction of a Map. A - * flavor is permitted to map to any number of natives, and likewise a native - * is permitted to map to any number of flavors. FlavorTables need not be - * symmetric, but typically are. - * - * @author David Mendenhall - * - * @since 1.4 - */ -public interface FlavorTable extends FlavorMap { - - /** - * Returns a <code>List</code> of <code>String</code> natives to which the - * specified <code>DataFlavor</code> corresponds. The <code>List</code> - * will be sorted from best native to worst. That is, the first native will - * best reflect data in the specified flavor to the underlying native - * platform. The returned <code>List</code> is a modifiable copy of this - * <code>FlavorTable</code>'s internal data. Client code is free to modify - * the <code>List</code> without affecting this object. - * - * @param flav the <code>DataFlavor</code> whose corresponding natives - * should be returned. If <code>null</code> is specified, all - * natives currently known to this <code>FlavorTable</code> are - * returned in a non-deterministic order. - * @return a <code>java.util.List</code> of <code>java.lang.String</code> - * objects which are platform-specific representations of platform- - * specific data formats - */ - List<String> getNativesForFlavor(DataFlavor flav); - - /** - * Returns a <code>List</code> of <code>DataFlavor</code>s to which the - * specified <code>String</code> corresponds. The <code>List</code> will be - * sorted from best <code>DataFlavor</code> to worst. That is, the first - * <code>DataFlavor</code> will best reflect data in the specified - * native to a Java application. The returned <code>List</code> is a - * modifiable copy of this <code>FlavorTable</code>'s internal data. - * Client code is free to modify the <code>List</code> without affecting - * this object. - * - * @param nat the native whose corresponding <code>DataFlavor</code>s - * should be returned. If <code>null</code> is specified, all - * <code>DataFlavor</code>s currently known to this - * <code>FlavorTable</code> are returned in a non-deterministic - * order. - * @return a <code>java.util.List</code> of <code>DataFlavor</code> - * objects into which platform-specific data in the specified, - * platform-specific native can be translated - */ - List<DataFlavor> getFlavorsForNative(String nat); -}
--- a/jdk/src/java.desktop/share/classes/java/awt/datatransfer/MimeType.java Tue Feb 17 10:48:24 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,394 +0,0 @@ -/* - * Copyright (c) 1997, 2012, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package java.awt.datatransfer; - -import java.io.Externalizable; -import java.io.ObjectOutput; -import java.io.ObjectInput; -import java.io.IOException; -import java.util.Enumeration; -import java.util.Locale; - - -/** - * A Multipurpose Internet Mail Extension (MIME) type, as defined - * in RFC 2045 and 2046. - * - * THIS IS *NOT* - REPEAT *NOT* - A PUBLIC CLASS! DataFlavor IS - * THE PUBLIC INTERFACE, AND THIS IS PROVIDED AS A ***PRIVATE*** - * (THAT IS AS IN *NOT* PUBLIC) HELPER CLASS! - */ -class MimeType implements Externalizable, Cloneable { - - /* - * serialization support - */ - - static final long serialVersionUID = -6568722458793895906L; - - /** - * Constructor for externalization; this constructor should not be - * called directly by an application, since the result will be an - * uninitialized, immutable <code>MimeType</code> object. - */ - public MimeType() { - } - - /** - * Builds a <code>MimeType</code> from a <code>String</code>. - * - * @param rawdata text used to initialize the <code>MimeType</code> - * @throws NullPointerException if <code>rawdata</code> is null - */ - public MimeType(String rawdata) throws MimeTypeParseException { - parse(rawdata); - } - - /** - * Builds a <code>MimeType</code> with the given primary and sub - * type but has an empty parameter list. - * - * @param primary the primary type of this <code>MimeType</code> - * @param sub the subtype of this <code>MimeType</code> - * @throws NullPointerException if either <code>primary</code> or - * <code>sub</code> is null - */ - public MimeType(String primary, String sub) throws MimeTypeParseException { - this(primary, sub, new MimeTypeParameterList()); - } - - /** - * Builds a <code>MimeType</code> with a pre-defined - * and valid (or empty) parameter list. - * - * @param primary the primary type of this <code>MimeType</code> - * @param sub the subtype of this <code>MimeType</code> - * @param mtpl the requested parameter list - * @throws NullPointerException if either <code>primary</code>, - * <code>sub</code> or <code>mtpl</code> is null - */ - public MimeType(String primary, String sub, MimeTypeParameterList mtpl) throws -MimeTypeParseException { - // check to see if primary is valid - if(isValidToken(primary)) { - primaryType = primary.toLowerCase(Locale.ENGLISH); - } else { - throw new MimeTypeParseException("Primary type is invalid."); - } - - // check to see if sub is valid - if(isValidToken(sub)) { - subType = sub.toLowerCase(Locale.ENGLISH); - } else { - throw new MimeTypeParseException("Sub type is invalid."); - } - - parameters = (MimeTypeParameterList)mtpl.clone(); - } - - public int hashCode() { - - // We sum up the hash codes for all of the strings. This - // way, the order of the strings is irrelevant - int code = 0; - code += primaryType.hashCode(); - code += subType.hashCode(); - code += parameters.hashCode(); - return code; - } // hashCode() - - /** - * <code>MimeType</code>s are equal if their primary types, - * subtypes, and parameters are all equal. No default values - * are taken into account. - * @param thatObject the object to be evaluated as a - * <code>MimeType</code> - * @return <code>true</code> if <code>thatObject</code> is - * a <code>MimeType</code>; otherwise returns <code>false</code> - */ - public boolean equals(Object thatObject) { - if (!(thatObject instanceof MimeType)) { - return false; - } - MimeType that = (MimeType)thatObject; - boolean isIt =