org.openide.loaders.LoaderTransfer Maven / Gradle / Ivy
/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is NetBeans. The Initial Developer of the Original
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.openide.loaders;
import java.awt.datatransfer.*;
import java.awt.dnd.DnDConstants;
import java.io.IOException;
import java.text.MessageFormat;
import org.openide.ErrorManager;
import org.openide.util.datatransfer.*;
/** Class that contains specific datatransfer flavors and methods to work with
* transfered DataObjects. There are flavors to allow a DataObject
* to be copied or cut into clipboard, and to retrieve them from clipboard
* when implementing paste operation.
* This is a dummy utility class--no instances are possible.
*
* @author Vita Stejskal
* @since 1.21
*/
public abstract class LoaderTransfer {
/** Creates new LoaderTransfer */
private LoaderTransfer () {}
/** Constants for drag-n-drop operations.
* Are exactly the same as constants
* in {@link DnDConstants}.
*/
public static final int DND_NONE = DnDConstants.ACTION_NONE;
public static final int DND_COPY = DnDConstants.ACTION_COPY;
public static final int DND_MOVE = DnDConstants.ACTION_MOVE;
public static final int DND_COPY_OR_MOVE = DnDConstants.ACTION_COPY | DnDConstants.ACTION_MOVE;
public static final int DND_LINK = DnDConstants.ACTION_LINK;
public static final int DND_REFERENCE = DnDConstants.ACTION_LINK;
/** Constant indicating copying to the clipboard.
* Equal to {@link #DND_COPY}, because
* copy to clipboard and d'n'd copy should be the same.
*/
public static final int CLIPBOARD_COPY = DND_COPY;
/** Constant indicating cutting to the clipboard.
*/
public static final int CLIPBOARD_CUT = 0x04;
/** Generic mask for copying DataObjects (do not destroy the original).
* Equal to {@link #CLIPBOARD_COPY} or {@link #DND_COPY}.
*/
public static final int COPY = CLIPBOARD_COPY | DND_COPY;
/** Generic mask for moving DataObjects (destroy the original).
* Equal to {@link #CLIPBOARD_CUT} or {@link #DND_MOVE}.
*/
public static final int MOVE = CLIPBOARD_CUT | DND_MOVE;
/** message format to create and parse the mimetype
*/
private static MessageFormat dndMimeType = new MessageFormat (
"application/x-java-openide-dataobjectdnd;class=org.openide.loaders.DataObject;mask={0}" // NOI18N
);
/** Creates transferable that represents an operation, such as cut-to-clipboard.
* The transferable will be recognizable by {@link #getDataObject} and {@link #getDataObjects}.
*
* @param d the DataObject to create a transferable for
* @param actions the action performed on the DataObject's node
* @return the transferable
*/
public static ExTransferable.Single transferable (final DataObject d, int actions) {
return new ExTransferable.Single (createDndFlavor (actions)) {
public Object getData () {
return d;
}
};
}
/** Obtain a DataObject from a transferable.
* Probes the transferable in case it includes a flavor corresponding
* to a DataObject's node operation (which you must specify a mask for).
*
* @param t transferable
* @param action one of the DND_*
or CLIPBOARD_*
constants
* @return the DataObject or null
*/
public static DataObject getDataObject (Transferable t, int action) {
DataFlavor[] flavors = t.getTransferDataFlavors ();
if (flavors == null) {
return null;
}
int len = flavors.length;
String subtype = "x-java-openide-dataobjectdnd"; // NOI18N
String primary = "application"; // NOI18N
String mask = "mask"; // NOI18N
for (int i = 0; i < len; i++) {
DataFlavor df = flavors[i];
if (
df.getSubType ().equals (subtype) &&
df.getPrimaryType ().equals (primary)
) {
try {
int m = Integer.valueOf (df.getParameter (mask)).intValue ();
if ((m & action) != 0) {
// found the node
DataObject o = (DataObject)t.getTransferData(df);
if (o.isValid()) {
return o;
} else {
// #14344
return null;
}
}
} catch (NumberFormatException nfe) {
maybeReportException (nfe);
} catch (ClassCastException cce) {
maybeReportException (cce);
} catch (IOException ioe) {
// #32206 - this exception is thrown when underlying fileobject
// does not exist and DataObject cannot be found for it. It happens when
// user copy a DataObject into clipboard, close NB, delete the file,
// restart the NB. During the startup the clipboard content is checked and
// this exception is thrown. It would be better to catch just FileStateInvalidException,
// but it gets wrapped into IOException in sun.awt.datatransfer.DataTransferer.
// Logging this exception as informative is too confusing.
// There is usually several exceptions logged for one clipboard object
// and users file it repeatedly as bug. Just log some explanation message instead.
ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL,
"INFORMATIONAL: Object in clipboard refers to a non existing file. "+ ioe.toString()); //NOI18N
} catch (UnsupportedFlavorException ufe) {
maybeReportException (ufe);
}
}
}
return null;
}
/** Obtain a list of DataObjects from a transferable.
* If there is only a single DataObject in the transferable, this will just return a singleton
* array like {@link #getDataObject}.
* If there is a {@link ExTransferable#multiFlavor multiple transfer} (of at least one element),
* each element of which
* contains a DataObject, then an array of these will be returned.
* If neither of these things is true, null
will be returned.
*
This is a convenience method intended for those who wish to specially support pastes
* of multiple DataObjects at once.
* @param t the transferable to probe
* @param action a DnD or clipboard constant
* @return a non-empty array of nodes, or null
*/
public static DataObject[] getDataObjects (Transferable t, int action) {
try {
if (t.isDataFlavorSupported (ExTransferable.multiFlavor)) {
MultiTransferObject mto = (MultiTransferObject) t.getTransferData (ExTransferable.multiFlavor);
int count = mto.getCount ();
DataObject[] datas = new DataObject[count];
boolean ok = true;
for (int i = 0; i < count; i++) {
DataObject d = getDataObject (mto.getTransferableAt (i), action);
if (d == null) {
ok = false;
break;
} else {
datas[i] = d;
}
}
if (ok && count > 0) return datas;
} else {
DataObject d = getDataObject (t, action);
if (d != null) return new DataObject[] { d };
}
} catch (ClassCastException cce) {
maybeReportException (cce);
} catch (IOException ioe) {
maybeReportException (ioe);
} catch (UnsupportedFlavorException ufe) {
maybeReportException (ufe);
}
return null;
}
/** Creates data flavor for given mask of dnd actions.
* @param actions any mask of dnd constants DND_* and CLIPBOARD_*
*/
private static DataFlavor createDndFlavor (int actions) {
try {
return new DataFlavor (dndMimeType.format (new Object[] { new Integer (actions) }));
} catch (ClassNotFoundException ex) {
throw new InternalError (ex.toString());
}
}
/** Print a stack trace if debugging is on.
* Used for exceptions that could occur when probing transferables,
* which should not interrupt the probing with an error, but
* indicate a bug elsewhere and should be reported somehow.
* @param e the exception
*/
private static void maybeReportException (Exception e) {
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
}
}