001/* JUnit tests for BasicGraphFrame ExportImageAction
002
003 Copyright (c) 2011-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 */
028
029package ptolemy.vergil.basic.test.junit;
030
031import java.io.File;
032import java.io.FileOutputStream;
033import java.io.IOException;
034import java.io.OutputStream;
035import java.util.Locale;
036
037import javax.swing.SwingUtilities;
038
039import ptolemy.actor.Manager;
040import ptolemy.actor.TypedCompositeActor;
041import ptolemy.actor.gui.ConfigurationApplication;
042import ptolemy.actor.lib.image.ImageReader;
043import ptolemy.kernel.CompositeEntity;
044import ptolemy.kernel.util.BasicModelErrorHandler;
045import ptolemy.vergil.basic.BasicGraphFrame;
046
047///////////////////////////////////////////////////////////////////
048//// ExportImageJUnitTest
049/**
050 * Test out the Export Image facility, which saves as gif, png, pdf etc.
051 *
052 * @author Christopher Brooks
053 * @version $Id$
054 * @since Ptolemy II 10.0
055 * @Pt.ProposedRating Red (cxh)
056 * @Pt.AcceptedRating Red (cxh)
057 */
058public class ExportImageJUnitTest {
059
060    /** Test the ExportImage facility.
061     *
062     *  <p>To run, use:</p>
063     *
064     *  <pre>
065     *   java -classpath \
066     *      $PTII:$PTII/lib/junit-4.8.2.jar: \
067     *      ptolemy.vergil.basic.test.junit.ExportImageJUnitTest
068     *  </pre>
069     *
070     *  @param args Not used.
071     */
072    public static void main(String args[]) {
073        org.junit.runner.JUnitCore
074                .main("ptolemy.vergil.basic.test.junit.ExportImageJUnitTest");
075    }
076
077    /**
078     * Test the layout facility by reading in a models, stripping
079     * out the graphical elements, laying out the models, comparing
080     * the new results with the known good results and then doing
081     * undo and redo.
082     * @exception Throwable If there is a problem reading or exporting
083     * the image.
084     */
085    @org.junit.Test
086    public void runModulation() throws Throwable {
087        _exportImageTest("$CLASSPATH/ptolemy/moml/demo/modulation.xml");
088    }
089
090    ///////////////////////////////////////////////////////////////////
091    ////                         protected methods                 ////
092
093    /**
094     * Test the Export Image facility by saving images and reading
095     * them back in.
096     *
097     * <p>This is the main entry point for Export Image tests.</p>
098     *
099     * <p>The caller of this method need <b>not</b>be in the Swing
100     * Event Thread.</p>
101     *
102     * @param modelFileName The file name of the test model.
103     * @exception Throwable If the file name cannot be read or laid out.
104     */
105    protected void _exportImageTest(final String modelFileName)
106            throws Throwable {
107
108        // Give the developer feedback about what model is being opened.
109        System.out.print(modelFileName + " ");
110
111        // FIXME: this seem wrong:  The inner classes are in different
112        // threads and can only access final variables.  However, we
113        // use an array as a final variable, but we change the value
114        // of the element of the array.  Is this thread safe?
115        final CompositeEntity[] model = new CompositeEntity[1];
116
117        /////
118        // Open the model.
119        // FIXME: Refactor this and KielerLayoutJUnitTest to a common class.
120        Runnable openModelAction = new Runnable() {
121            @Override
122            public void run() {
123                try {
124                    model[0] = ConfigurationApplication
125                            .openModelOrEntity(modelFileName);
126                } catch (Throwable throwable) {
127                    throw new RuntimeException(throwable);
128                }
129            }
130        };
131        SwingUtilities.invokeAndWait(openModelAction);
132        _sleep();
133
134        _basicGraphFrame = BasicGraphFrame.getBasicGraphFrame(model[0]);
135
136        // Open a model that we will use to display the image.
137
138        // FIXME: this seem wrong:  The inner classes are in different
139        // threads and can only access final variables.  However, we
140        // use an array as a final variable, but we change the value
141        // of the element of the array.  Is this thread safe?
142        final CompositeEntity[] imageDisplayModel = new CompositeEntity[1];
143
144        // FIXME: Refactor this and KielerLayoutJUnitTest to a common class.
145        Runnable openImageDisplayModelAction = new Runnable() {
146            @Override
147            public void run() {
148                try {
149                    imageDisplayModel[0] = ConfigurationApplication
150                            .openModelOrEntity(
151                                    "$CLASSPATH/ptolemy/actor/lib/image/test/auto/ImageReaderImageDisplay.xml");
152                } catch (Throwable throwable) {
153                    throw new RuntimeException(throwable);
154                }
155            }
156        };
157        SwingUtilities.invokeAndWait(openImageDisplayModelAction);
158        _sleep();
159
160        // Export images
161        // FIXME: we should get the list of acceptable format names from
162        // BasicGraphFrame
163        String[] formatNames = new String[] { "GIF", "PNG" };
164        for (final String formatName : formatNames) {
165            Runnable exportImageAction = new Runnable() {
166                @Override
167                public void run() {
168                    try {
169                        System.out.print(" " + formatName + " ");
170                        File imageFile = File.createTempFile(model[0].getName(),
171                                formatName.toLowerCase(Locale.getDefault()));
172                        imageFile.deleteOnExit();
173                        OutputStream out = null;
174                        try {
175                            out = new FileOutputStream(imageFile);
176                            // Export the image.
177                            _basicGraphFrame.getJGraph().exportImage(out,
178                                    formatName);
179                        } finally {
180                            if (out != null) {
181                                try {
182                                    out.close();
183                                } catch (IOException ex) {
184                                    ex.printStackTrace();
185                                }
186                            }
187                        }
188
189                        // Run a model that displays the image.
190                        ImageReader imageReader = (ImageReader) imageDisplayModel[0]
191                                .getEntity("ImageReader");
192
193                        imageReader.fileOrURL.setExpression(
194                                imageFile.toURI().toURL().toString());
195                        if (!(model[0] instanceof TypedCompositeActor)) {
196                            throw new RuntimeException(model[0].getFullName()
197                                    + "is not a TypedCompositeActor? "
198                                    + model[0].getClass());
199                        } else {
200                            Manager manager = ((TypedCompositeActor) model[0])
201                                    .getManager();
202                            if (manager == null) {
203                                manager = new Manager(
204                                        imageDisplayModel[0].workspace(),
205                                        "MyManager");
206
207                            }
208                            if (!(imageDisplayModel[0] instanceof TypedCompositeActor)) {
209                                throw new RuntimeException(imageDisplayModel[0]
210                                        .getFullName()
211                                        + "is not a TypedCompositeActor? "
212                                        + imageDisplayModel[0].getClass());
213                            } else {
214                                ((TypedCompositeActor) imageDisplayModel[0])
215                                        .setManager(manager);
216                                ((TypedCompositeActor) imageDisplayModel[0])
217                                        .setModelErrorHandler(
218                                                new BasicModelErrorHandler());
219                                manager.execute();
220                            }
221                        }
222
223                    } catch (Throwable throwable) {
224                        throwable.printStackTrace();
225                        throw new RuntimeException(throwable);
226                    }
227                }
228            };
229            SwingUtilities.invokeAndWait(exportImageAction);
230            _sleep();
231        }
232
233        /////
234        // Close the model.
235        Runnable closeAction = new Runnable() {
236            @Override
237            public void run() {
238                try {
239                    ConfigurationApplication
240                            .closeModelWithoutSavingOrExiting(model[0]);
241                } catch (Exception ex) {
242                    throw new RuntimeException(ex);
243                }
244            }
245        };
246        SwingUtilities.invokeAndWait(closeAction);
247        _sleep();
248    }
249
250    /** Sleep the current thread, which is usually not the Swing Event
251     *  Dispatch Thread.
252     */
253    protected void _sleep() {
254        try {
255            Thread.sleep(1000);
256        } catch (Throwable ex) {
257            //Ignore
258        }
259    }
260
261    ///////////////////////////////////////////////////////////////////
262    ////                         private fields                    ////
263
264    /** The BasicGraphFrame of the model. */
265    private BasicGraphFrame _basicGraphFrame;
266}