Path: blob/master/src/java.datatransfer/share/classes/java/awt/datatransfer/Clipboard.java
41159 views
/*1* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.awt.datatransfer;2627import java.io.IOException;28import java.util.Arrays;29import java.util.HashSet;30import java.util.Objects;31import java.util.Set;3233import sun.datatransfer.DataFlavorUtil;3435/**36* A class that implements a mechanism to transfer data using cut/copy/paste37* operations.38* <p>39* {@link FlavorListener}s may be registered on an instance of the Clipboard40* class to be notified about changes to the set of {@link DataFlavor}s41* available on this clipboard (see {@link #addFlavorListener}).42*43* @author Amy Fowler44* @author Alexander Gerasimov45* @see java.awt.Toolkit#getSystemClipboard46* @see java.awt.Toolkit#getSystemSelection47* @since 1.148*/49public class Clipboard {5051String name;5253/**54* The owner of the clipboard.55*/56protected ClipboardOwner owner;5758/**59* Contents of the clipboard.60*/61protected Transferable contents;6263/**64* An aggregate of flavor listeners registered on this local clipboard.65*66* @since 1.567*/68private Set<FlavorListener> flavorListeners;6970/**71* A set of {@code DataFlavor}s that is available on this local clipboard.72* It is used for tracking changes of {@code DataFlavor}s available on this73* clipboard.74*75* @since 1.576*/77private Set<DataFlavor> currentDataFlavors;7879/**80* Creates a clipboard object.81*82* @param name for the clipboard83* @see java.awt.Toolkit#getSystemClipboard84*/85public Clipboard(String name) {86this.name = name;87}8889/**90* Returns the name of this clipboard object.91*92* @return the name of this clipboard object93* @see java.awt.Toolkit#getSystemClipboard94*/95public String getName() {96return name;97}9899/**100* Sets the current contents of the clipboard to the specified transferable101* object and registers the specified clipboard owner as the owner of the102* new contents.103* <p>104* If there is an existing owner different from the argument {@code owner},105* that owner is notified that it no longer holds ownership of the clipboard106* contents via an invocation of {@code ClipboardOwner.lostOwnership()} on107* that owner. An implementation of {@code setContents()} is free not to108* invoke {@code lostOwnership()} directly from this method. For example,109* {@code lostOwnership()} may be invoked later on a different thread. The110* same applies to {@code FlavorListener}s registered on this clipboard.111* <p>112* The method throws {@code IllegalStateException} if the clipboard is113* currently unavailable. For example, on some platforms, the system114* clipboard is unavailable while it is accessed by another application.115*116* @param contents the transferable object representing the clipboard117* content118* @param owner the object which owns the clipboard content119* @throws IllegalStateException if the clipboard is currently unavailable120* @see java.awt.Toolkit#getSystemClipboard121*/122public synchronized void setContents(Transferable contents, ClipboardOwner owner) {123final ClipboardOwner oldOwner = this.owner;124final Transferable oldContents = this.contents;125126this.owner = owner;127this.contents = contents;128129if (oldOwner != null && oldOwner != owner) {130DataFlavorUtil.getDesktopService().invokeOnEventThread(() ->131oldOwner.lostOwnership(Clipboard.this, oldContents));132}133fireFlavorsChanged();134}135136/**137* Returns a transferable object representing the current contents of the138* clipboard. If the clipboard currently has no contents, it returns139* {@code null}. The parameter Object requestor is not currently used. The140* method throws {@code IllegalStateException} if the clipboard is currently141* unavailable. For example, on some platforms, the system clipboard is142* unavailable while it is accessed by another application.143*144* @param requestor the object requesting the clip data (not used)145* @return the current transferable object on the clipboard146* @throws IllegalStateException if the clipboard is currently unavailable147* @see java.awt.Toolkit#getSystemClipboard148*/149public synchronized Transferable getContents(Object requestor) {150return contents;151}152153/**154* Returns an array of {@code DataFlavor}s in which the current contents of155* this clipboard can be provided. If there are no {@code DataFlavor}s156* available, this method returns a zero-length array.157*158* @return an array of {@code DataFlavor}s in which the current contents of159* this clipboard can be provided160* @throws IllegalStateException if this clipboard is currently unavailable161* @since 1.5162*/163public DataFlavor[] getAvailableDataFlavors() {164Transferable cntnts = getContents(null);165if (cntnts == null) {166return new DataFlavor[0];167}168return cntnts.getTransferDataFlavors();169}170171/**172* Returns whether or not the current contents of this clipboard can be173* provided in the specified {@code DataFlavor}.174*175* @param flavor the requested {@code DataFlavor} for the contents176* @return {@code true} if the current contents of this clipboard can be177* provided in the specified {@code DataFlavor}; {@code false}178* otherwise179* @throws NullPointerException if {@code flavor} is {@code null}180* @throws IllegalStateException if this clipboard is currently unavailable181* @since 1.5182*/183public boolean isDataFlavorAvailable(DataFlavor flavor) {184if (flavor == null) {185throw new NullPointerException("flavor");186}187188Transferable cntnts = getContents(null);189if (cntnts == null) {190return false;191}192return cntnts.isDataFlavorSupported(flavor);193}194195/**196* Returns an object representing the current contents of this clipboard in197* the specified {@code DataFlavor}. The class of the object returned is198* defined by the representation class of {@code flavor}.199*200* @param flavor the requested {@code DataFlavor} for the contents201* @return an object representing the current contents of this clipboard in202* the specified {@code DataFlavor}203* @throws NullPointerException if {@code flavor} is {@code null}204* @throws IllegalStateException if this clipboard is currently unavailable205* @throws UnsupportedFlavorException if the requested {@code DataFlavor} is206* not available207* @throws IOException if the data in the requested {@code DataFlavor} can208* not be retrieved209* @see DataFlavor#getRepresentationClass210* @since 1.5211*/212public Object getData(DataFlavor flavor)213throws UnsupportedFlavorException, IOException {214if (flavor == null) {215throw new NullPointerException("flavor");216}217218Transferable cntnts = getContents(null);219if (cntnts == null) {220throw new UnsupportedFlavorException(flavor);221}222return cntnts.getTransferData(flavor);223}224225/**226* Registers the specified {@code FlavorListener} to receive227* {@code FlavorEvent}s from this clipboard. If {@code listener} is228* {@code null}, no exception is thrown and no action is performed.229*230* @param listener the listener to be added231* @see #removeFlavorListener232* @see #getFlavorListeners233* @see FlavorListener234* @see FlavorEvent235* @since 1.5236*/237public synchronized void addFlavorListener(FlavorListener listener) {238if (listener == null) {239return;240}241242if (flavorListeners == null) {243flavorListeners = new HashSet<>();244currentDataFlavors = getAvailableDataFlavorSet();245}246247flavorListeners.add(listener);248}249250/**251* Removes the specified {@code FlavorListener} so that it no longer252* receives {@code FlavorEvent}s from this {@code Clipboard}. This method253* performs no function, nor does it throw an exception, if the listener254* specified by the argument was not previously added to this255* {@code Clipboard}. If {@code listener} is {@code null}, no exception is256* thrown and no action is performed.257*258* @param listener the listener to be removed259* @see #addFlavorListener260* @see #getFlavorListeners261* @see FlavorListener262* @see FlavorEvent263* @since 1.5264*/265public synchronized void removeFlavorListener(FlavorListener listener) {266if (listener == null || flavorListeners == null) {267return;268}269flavorListeners.remove(listener);270}271272/**273* Returns an array of all the {@code FlavorListener}s currently registered274* on this {@code Clipboard}.275*276* @return all of this clipboard's {@code FlavorListener}s or an empty array277* if no listeners are currently registered278* @see #addFlavorListener279* @see #removeFlavorListener280* @see FlavorListener281* @see FlavorEvent282* @since 1.5283*/284public synchronized FlavorListener[] getFlavorListeners() {285return flavorListeners == null ? new FlavorListener[0] :286flavorListeners.toArray(new FlavorListener[flavorListeners.size()]);287}288289/**290* Checks change of the {@code DataFlavor}s and, if necessary, notifies all291* listeners that have registered interest for notification on292* {@code FlavorEvent}s.293*294* @since 1.5295*/296private void fireFlavorsChanged() {297if (flavorListeners == null) {298return;299}300301Set<DataFlavor> prevDataFlavors = currentDataFlavors;302currentDataFlavors = getAvailableDataFlavorSet();303if (Objects.equals(prevDataFlavors, currentDataFlavors)) {304return;305}306flavorListeners.forEach(listener ->307DataFlavorUtil.getDesktopService().invokeOnEventThread(() ->308listener.flavorsChanged(new FlavorEvent(Clipboard.this))));309}310311/**312* Returns a set of {@code DataFlavor}s currently available on this313* clipboard.314*315* @return a set of {@code DataFlavor}s currently available on this316* clipboard317* @since 1.5318*/319private Set<DataFlavor> getAvailableDataFlavorSet() {320Set<DataFlavor> set = new HashSet<>();321Transferable contents = getContents(null);322if (contents != null) {323DataFlavor[] flavors = contents.getTransferDataFlavors();324if (flavors != null) {325set.addAll(Arrays.asList(flavors));326}327}328return set;329}330}331332333