All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openide.nodes.NodeTransfer Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.openide.nodes;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openide.util.datatransfer.ExTransferable;
import org.openide.util.datatransfer.MultiTransferObject;
import org.openide.util.datatransfer.PasteType;

/** Class that contains specific datatransfer flavors and methods to work with
* nodes. There are flavors to allow a node
* to be copied or cut, and to decide its paste types.
* 

This is a dummy utility class--no instances are possible. * * @author Jaroslav Tulach */ public abstract class NodeTransfer extends Object { /** 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 nodes (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 nodes (destroy the original). * Equal to {@link #CLIPBOARD_CUT} or {@link #DND_MOVE}. */ public static final int MOVE = CLIPBOARD_CUT | DND_MOVE; /** Flavor for representation class {@link NodeTransfer.Paste}. * Provides methods for obtaining a set of {@link PasteType}s when * the target node is known. */ private static final DataFlavor nodePasteFlavor; static { try { nodePasteFlavor = new DataFlavor( "application/x-java-openide-nodepaste;class=org.openide.nodes.Node", // NOI18N Node.getString("LBL_nodePasteFlavor"), Node.class.getClassLoader()); } catch (ClassNotFoundException e) { throw new AssertionError(e); } } private static final String dndMimeType = "application/x-java-openide-nodednd;class=org.openide.nodes.Node;mask="; //NOI18N private NodeTransfer() { } /** 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) { Exception ex; try { return new DataFlavor(dndMimeType + actions, null, Node.class.getClassLoader()); } catch (IllegalArgumentException iae) { ex = iae; } catch (ClassNotFoundException cnfE) { ex = cnfE; } throw new IllegalStateException("Cannot createDndFlavor(" + actions + ")", ex); // NOI18N } /** Creates transferable that represents a node operation, such as cut-to-clipboard. * The transferable will be recognizable by {@link #node}, {@link #nodes}, and {@link #cookie}. * * @param n the node to create a transferable for * @param actions the action performed on the node * @return the transferable */ public static ExTransferable.Single transferable(final Node n, int actions) { return new ExTransferable.Single(createDndFlavor(actions)) { public Object getData() { return n; } }; } /** Obtain a node from a transferable. * Probes the transferable in case it includes a flavor corresponding * to a node operation (which you must specify a mask for). * * @param t transferable * @param action one of the DND_* or CLIPBOARD_* constants * @return the node or null */ public static Node node(Transferable t, int action) { DataFlavor[] flavors = t.getTransferDataFlavors(); if (flavors == null) { return null; } int len = flavors.length; String subtype = "x-java-openide-nodednd"; // 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 return (Node) t.getTransferData(df); } } catch (NumberFormatException nfe) { maybeReportException(nfe); } catch (ClassCastException cce) { maybeReportException(cce); } catch (IOException ioe) { maybeReportException(ioe); } catch (UnsupportedFlavorException ufe) { maybeReportException(ufe); } } } return null; } /** Obtain a list of nodes from a transferable. * If there is only a single node in the transferable, this will just return a singleton * array like {@link #node}. * If there is a {@link ExTransferable#multiFlavor multiple transfer} (of at least one element), * each element of which * contains a node, 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 nodes at once. (By default, an explorer will * fall back to presenting each component of a multiple-item transferable separately when checking for paste * types on a target node, so if you have only one paste type and it makes no difference whether all of the nodes * are pasted together or separately, you can just use {@link #node}.) *

If you wish to test for cookies, you should do so manually * according to your specific logic. * @param t the transferable to probe * @param action a DnD or clipboard constant * @return a non-empty array of nodes, or null */ public static Node[] nodes(Transferable t, int action) { try { if (t.isDataFlavorSupported(ExTransferable.multiFlavor)) { MultiTransferObject mto = (MultiTransferObject) t.getTransferData(ExTransferable.multiFlavor); int count = mto.getCount(); Node[] ns = new Node[count]; boolean ok = true; for (int i = 0; i < count; i++) { Node n = node(mto.getTransferableAt(i), action); if (n == null) { ok = false; break; } else { ns[i] = n; } } if (ok && (count > 0)) { return ns; } } else { Node n = node(t, action); if (n != null) { return new Node[] { n }; } } } catch (ClassCastException cce) { maybeReportException(cce); } catch (IOException ioe) { maybeReportException(ioe); } catch (UnsupportedFlavorException ufe) { maybeReportException(ufe); } return null; } /** Obtain a cookie instance from the copied node in a transferable. *

* First of all it checks whether the given transferable contains * a node and then asks for the cookie. *

If you wish to specially support multiple-node transfers, please use {@link #nodes} * and manually check for the desired combination of cookies. * * @param t transferable to check in * @param cookie cookie representation class to look for * @param action the action which was used to store the node * * @return cookie or null if it does not exist */ public static T cookie(Transferable t, int action, Class cookie) { Node n = node(t, action); return (n == null) ? null : n.getCookie(cookie); } /** Creates transfer object that is used to carry an intelligent * paste source through transferable or clipboard. * {@link #findPaste} can retrieve it. * @param paste the intelligent source of paste types * @return the transferable */ public static ExTransferable.Single createPaste(final Paste paste) { return new ExTransferable.Single(nodePasteFlavor) { public Object getData() { return paste; } }; } /** Find an intelligent source of paste types in a transferable. * Note that {@link AbstractNode#createPasteTypes} looks for this * by default, so cut/copied nodes may specify how they may be pasted * to some external node target. * @param t the transferable to test * @return the intelligent source or null if none is in the transferable */ public static Paste findPaste(Transferable t) { try { if (t.isDataFlavorSupported(nodePasteFlavor)) { return (Paste) t.getTransferData(nodePasteFlavor); } } catch (ClassCastException cce) { maybeReportException(cce); } catch (IOException ioe) { maybeReportException(ioe); } catch (UnsupportedFlavorException ufe) { maybeReportException(ufe); } return null; } /** 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) { Logger.getLogger(NodeTransfer.class.getName()).log(Level.WARNING, "Node transfer error: {0}", e.getMessage()); Logger.getLogger(NodeTransfer.class.getName()).log(Level.INFO, null, e); } /** An intelligent source of paste types (ways how to paste) * for a target node. *

* Each node should check for this * type in a paste operation to allow anyone to insert something * into it. *

* Sample example of implementation of {@link Node#getPasteTypes}: *

{@code
    *   public PasteType[] getPasteTypes (Transferable t) {
    *     NodeTransfer.Paste p = (NodeTransfer.Paste)t.getTransferData (
    *       NodeTransfer.nodePasteFlavor
    *     );
    *     return p.types (this);
    *   }
    * }
*/ public interface Paste { /** Method that checks the type of target node and can * decide which paste types it supports. * * @param target the target node * @return array of paste types that are valid for such a target node */ public PasteType[] types(Node target); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy