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 <table> element holding an 137 * <img/> 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}