001/* A transferable object that contains a named object.
002
003 Copyright (c) 2000-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.vergil.toolbox;
029
030import java.awt.datatransfer.DataFlavor;
031import java.awt.datatransfer.Transferable;
032import java.awt.datatransfer.UnsupportedFlavorException;
033import java.io.IOException;
034import java.io.Serializable;
035import java.io.StringReader;
036import java.io.StringWriter;
037import java.util.Collections;
038import java.util.Iterator;
039import java.util.LinkedList;
040import java.util.List;
041
042import ptolemy.gui.PtGUIUtilities;
043import ptolemy.kernel.util.NamedObj;
044
045///////////////////////////////////////////////////////////////////
046//// PtolemyTransferable
047
048/**
049 A transferable object that contains a local JVM reference to a
050 number of named objects.  To get a reference to an iterator on the
051 objects, request data with the data flavor given in the static
052 namedObjFlavor variable.  This class will also return a MoML
053 representation of the objects, if data is requested with the
054 DataFlavor.stringFlavor or DataFlavor.plainTextFlavor.
055
056 @author Steve Neuendorffer
057 @version $Id$
058 @since Ptolemy II 1.0
059 @Pt.ProposedRating Red (eal)
060 @Pt.AcceptedRating Red (johnr)
061 */
062@SuppressWarnings("serial")
063public class PtolemyTransferable implements Transferable, Serializable {
064    // This class implements Serializable in hopes that
065    // drag and drop will work under Mac OS X.
066
067    /**
068     * Create a new transferable object that contains no objects.
069     */
070    public PtolemyTransferable() {
071        _objectList = new LinkedList();
072    }
073
074    ///////////////////////////////////////////////////////////////////
075    ////                         public methods                    ////
076
077    /**
078     * Add the given named object to the objects contained in this
079     * transferable.  If the object already exists in this transferable,
080     * then do not add it again.
081     * @param object The object to be added to this transferable.
082     */
083    public void addObject(NamedObj object) {
084        if (!_objectList.contains(object)) {
085            _objectList.add(object);
086        }
087    }
088
089    /**
090     * Return the data flavors that this transferable supports.
091     * @return The data flavors.
092     */
093    @Override
094    public synchronized DataFlavor[] getTransferDataFlavors() {
095        return _flavors;
096    }
097
098    /**
099     * Return true if the given data flavor is supported.
100     * @param flavor The data flavor that is searched for.
101     * @return true if the given data flavor is supported.
102     */
103    @Override
104    public boolean isDataFlavorSupported(DataFlavor flavor) {
105        int i;
106
107        for (i = 0; i < _flavors.length; i++) {
108            if (_flavors[i].equals(flavor)) {
109                return true;
110            }
111        }
112
113        return false;
114    }
115
116    /**
117     * Return an object that represents the data contained within this
118     * transferable with the given flavor.  If the flavor is namedObjFlavor,
119     * return an iterator of the objects that this transferable refers to.
120     * If the flavor is DataFlavor.plainTextFlavor, return an
121     * InputStream that contains a MoML representation of the objects.
122     * If the flavor is DataFlavor.stringFlavor return a string that
123     * contains the MoML representation.
124     *
125     * @param flavor The data flavor.
126     * @return An object with the given flavor.
127     * @exception UnsupportedFlavorException If the given flavor is
128     * not supported.
129     * @exception IOException If thrown while creating the MoML.
130     */
131    @Override
132    public Object getTransferData(DataFlavor flavor)
133            throws UnsupportedFlavorException, IOException {
134        if (flavor.equals(DataFlavor.plainTextFlavor)) {
135            // plain text flavor is deprecated, but everybody still
136            // implements it.  The problem is that all the implementations
137            // differ from the docs.  *sigh*
138            return new StringReader(_getMoML());
139        } else if (flavor.equals(namedObjFlavor)) {
140            return Collections.unmodifiableList(_objectList);
141        } else if (flavor.equals(DataFlavor.stringFlavor)) {
142            return _getMoML();
143        }
144
145        throw new UnsupportedFlavorException(flavor);
146    }
147
148    /**
149     *  Remove the given object from this transferable.
150     *  If the object does not exist in the transferable, then do nothing.
151     *  @param object The object to be removed.
152     */
153    public void removeObject(NamedObj object) {
154        if (_objectList.contains(object)) {
155            _objectList.remove(object);
156        }
157    }
158
159    ///////////////////////////////////////////////////////////////////
160    ////                         public variables                  ////
161
162    /**
163     * The flavor that requests a local virtual machine
164     * reference to the contained object.
165     */
166    public static final DataFlavor namedObjFlavor;
167
168    static {
169        // Under MacOS X 10.2, Java 1.4.1_01 we get a stack trace
170        // when ever we drag and drop.  For details See
171        // http://lists.apple.com/archives/java-dev/2003/Apr/16/classcastexceptionindrag.txt
172        // FIXME: This change happened just before the release of 3.0.2,
173        // so we only make the change under Mac OS.
174        if (PtGUIUtilities.macOSLookAndFeel()) {
175            namedObjFlavor = new DataFlavor(
176                    DataFlavor.javaJVMLocalObjectMimeType
177                            + ";class=ptolemy.kernel.util.NamedObj",
178                    "Named Object");
179        } else {
180            namedObjFlavor = new DataFlavor(
181                    DataFlavor.javaJVMLocalObjectMimeType
182                            + "ptolemy.kernel.util.NamedObj",
183                    "Named Object");
184        }
185    }
186
187    /** Return a string with a MoML description of all the objects in
188     *  the list.
189     *  @return the MoML description.
190     *  @exception IOException If thrown while creating the MoML.
191     */
192    public String _getMoML() throws IOException {
193        StringWriter buffer = new StringWriter();
194        buffer.write("<group>\n");
195
196        Iterator elements = Collections.unmodifiableList(_objectList)
197                .iterator();
198
199        while (elements.hasNext()) {
200            NamedObj element = (NamedObj) elements.next();
201
202            // first level to avoid obnoxiousness with toplevel translations.
203            element.exportMoML(buffer, 1);
204        }
205
206        buffer.write("</group>\n");
207        return buffer.toString();
208    }
209
210    ///////////////////////////////////////////////////////////////////
211    ////                         private variables                 ////
212    // The flavors that this node can return.
213    private final DataFlavor[] _flavors = { DataFlavor.plainTextFlavor,
214            DataFlavor.stringFlavor, namedObjFlavor, };
215
216    //The object contained by this transferable.
217    private List _objectList;
218}