001/* Attribute for inserting an image into a web page.
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.export.web;
030
031import java.awt.Frame;
032import java.awt.print.PrinterException;
033import java.io.File;
034import java.io.FileOutputStream;
035import java.io.IOException;
036import java.io.OutputStream;
037import java.util.HashMap;
038import java.util.List;
039import java.util.Map;
040
041import ptolemy.actor.gui.Configuration;
042import ptolemy.actor.gui.Effigy;
043import ptolemy.actor.gui.PtolemyEffigy;
044import ptolemy.actor.gui.Tableau;
045import ptolemy.gui.ImageExportable;
046import ptolemy.kernel.util.IllegalActionException;
047import ptolemy.kernel.util.NameDuplicationException;
048import ptolemy.kernel.util.NamedObj;
049import ptolemy.vergil.basic.ExportParameters;
050
051///////////////////////////////////////////////////////////////////
052//// HTMLImage
053/**
054 * Attribute for inserting an image into a web page.  Drag this attribute onto an
055 * actor that produces a BasicGraphFrame (for example,
056 * ptolemy.actor.lib.gui.XYPlotter) and specify the caption for this image.
057 *
058 * By default, this image will be placed at the end of the HTML page,
059 * but you can change the position by setting the
060 * <i>imagePosition</i> parameter. You can also separately control what
061 * text is displayed in the model, or make the attribute disappear altogether
062 * in the model (for this, just set <i>displayText</i> to an empty string).
063 *
064 * Based on ptolemy.vergil.basic.export.web.HTMLText
065 *
066 * @author Beth Latronico
067 * @version $Id$
068 * @since Ptolemy II 10.0
069 * @see ptolemy.gui.ImageExportable
070 * @see ptolemy.vergil.basic.export.web.HTMLText
071 * @see ptolemy.vergil.basic.export.web.LinkToOpenTableaux
072
073 * @Pt.ProposedRating Red (ltrnc)
074 * @Pt.AcceptedRating Red (ltrnc)
075 */
076public class HTMLImage extends WebContent {
077
078    /** Create an instance of this parameter.
079     *  @param container The container.
080     *  @param name The name.
081     *  @exception IllegalActionException If the superclass throws it.
082     *  @exception NameDuplicationException If the superclass throws it.
083     */
084    public HTMLImage(NamedObj container, String name)
085            throws IllegalActionException, NameDuplicationException {
086        super(container, name);
087        imagePosition = new HTMLTextPosition(this, "imagePosition");
088    }
089
090    ///////////////////////////////////////////////////////////////////
091    ////                         parameters                        ////
092
093    /** Parameter specifying the position into which to export the image.
094     *  The parameter offers the following possibilities:
095     *  <ul>
096     *  <li><b>end</b>: Put the image at the end of the HTML file.
097     *  <li><b>header</b>: Put the image in the header section.
098     *  <li><b>start</b>: Put the image at the start of the body section.
099     *  <li><i>anything_else</i>: Put the image in a separate HTML file
100     *   named <i>anything_else</i>.
101     *  </ul>
102     *  The default is "start".
103     */
104    // FIXME:  This implementation should be improved.  Should the location be
105    // the responsibility of the WebContent class, or the WebExporter?  I think
106    // the WebExporter.
107    public HTMLTextPosition imagePosition;
108
109    ///////////////////////////////////////////////////////////////////
110    ////                         public methods                    ////
111
112    /** Return image plus the appropriate file extension, e.g. image/gif
113     *
114     * @return image plus the appropriate file extension, e.g. image/gif
115     */
116    // FIXME: Implement other file extensions (do we use any?)
117    // How to determine which file extension should be used?  If file has not
118    // been created yet?
119    @Override
120    public String getMimeType() {
121        return "image/gif";
122    }
123
124    /** Return true, since old images should be overwritten with new.
125     *
126     * @return True, since old images should be overwritten with new
127     */
128    @Override
129    public boolean isOverwriteable() {
130        return true;
131    }
132
133    ///////////////////////////////////////////////////////////////////
134    ////                         protected methods                 ////
135
136    /** Generate the image file and a &lt;table&gt; element holding an
137     *  &lt;img/&gt; element and a caption for the image..
138     *
139     *  @param exporter The WebExporter to add content to
140     *  @exception IllegalActionException If something is wrong generating the
141     *  image file or generating the additional web content
142     */
143    @Override
144    public void _provideElements(WebExporter exporter)
145            throws IllegalActionException {
146
147        // Copied from LinkToOpenTableau
148        // Create a table of effigies associated with any
149        // open submodel or plot.
150        Map<NamedObj, PtolemyEffigy> openEffigies = new HashMap<NamedObj, PtolemyEffigy>();
151        Tableau myTableau = exporter.getFrame().getTableau();
152        Effigy myEffigy = (Effigy) myTableau.getContainer();
153        List<PtolemyEffigy> effigies = myEffigy.entityList(PtolemyEffigy.class);
154        for (PtolemyEffigy effigy : effigies) {
155            openEffigies.put(effigy.getModel(), effigy);
156        }
157
158        // Get the effigy that goes with this attribute's container
159        PtolemyEffigy effigy = openEffigies.get(getContainer());
160
161        // The hierarchy of effigies does not always follow the model hierarchy
162        // (e.g., a PlotEffigy will be contained by the top-level effigy for the
163        // model for some reason), so if the effigy is null, we search
164        // nonetheless for an effigy.
165        if (effigy == null) {
166            Effigy candidate = Configuration.findEffigy(getContainer());
167            if (candidate instanceof PtolemyEffigy) {
168                effigy = (PtolemyEffigy) candidate;
169            }
170        }
171        try {
172            // _linkTo calls addContent()
173            if (effigy != null) {
174                // _linkTo() recursively calls writeHTML();
175                _linkTo(exporter, effigy, getContainer(), getContainer(),
176                        exporter.getExportParameters());
177            }
178        } catch (Throwable throwable) {
179            throw new IllegalActionException(this, throwable,
180                    "Failed to generate HTMLImage. ");
181        }
182    }
183
184    ///////////////////////////////////////////////////////////////////
185    ////                         private methods                   ////
186
187    private void _linkTo(WebExporter exporter, PtolemyEffigy effigy,
188            NamedObj sourceObject, NamedObj destinationObject,
189            ExportParameters parameters)
190            throws IOException, PrinterException, IllegalActionException {
191        File gifFile;
192        WebElement webElement;
193        // Look for any open tableaux for the object.
194        List<Tableau> tableaux = effigy.entityList(Tableau.class);
195        // If there are multiple tableaux open, use only the first one.
196        if (tableaux.size() > 0) {
197            String name = destinationObject.getName();
198            Frame frame = tableaux.get(0).getFrame();
199            // If it's a composite actor, export HTML.
200            if (frame instanceof ImageExportable) {
201
202                gifFile = new File(parameters.directoryToExportTo,
203                        name + ".gif");
204                if (parameters.deleteFilesOnExit) {
205                    gifFile.deleteOnExit();
206                }
207                OutputStream gifOut = new FileOutputStream(gifFile);
208                try {
209                    ((ImageExportable) frame).writeImage(gifOut, "gif");
210                } finally {
211                    gifOut.close();
212                }
213
214                // Check the exporter for the path to use here
215                // This can differ depending on the exporter
216                // For example, an HttpService uses a URL as a path since the
217                // WebServer has a resource handler to serve files
218                // ExportToHTML will use a directory since the files are
219                // stored locally and located relative to the main web page
220                String path = exporter.getExportParameters().HTMLPathForFiles;
221                if (path == null) {
222                    path = "/";
223                } else {
224                    if (!path.equals("") && !path.endsWith("/")) {
225                        path = path + "/";
226                    }
227                }
228
229                String content = "<table> <caption align=\"bottom\">"
230                        + this.displayText.getExpression()
231                        + "</caption> <tr> <td> <img src=\"" + path + name
232                        + ".gif\"> </td></tr></table>";
233
234                webElement = WebElement.createWebElement(getContainer(),
235                        getName() + "WebElement", getName() + "WebElement");
236                webElement.setExpression(content);
237                webElement.setParent(imagePosition.stringValue());
238
239                //Add image. Image should only be added once (onceOnly -> true).
240                exporter.defineElement(webElement, true);
241            }
242        }
243    }
244}