001/* A tableau representing an image token display. 002 003 Copyright (c) 2004-2015 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 */ 027package ptolemy.actor.lib.image; 028 029import java.awt.BorderLayout; 030import java.awt.Container; 031import java.awt.Image; 032import java.util.Iterator; 033import java.util.List; 034 035import javax.swing.JFrame; 036 037import ptolemy.actor.gui.Effigy; 038import ptolemy.actor.gui.ImageTokenEffigy; 039import ptolemy.actor.gui.Tableau; 040import ptolemy.actor.gui.TableauFactory; 041import ptolemy.actor.gui.TableauFrame; 042import ptolemy.actor.gui.TokenEffigy; 043import ptolemy.actor.gui.TokenTableau; 044import ptolemy.data.ImageToken; 045import ptolemy.data.Token; 046import ptolemy.kernel.util.IllegalActionException; 047import ptolemy.kernel.util.NameDuplicationException; 048import ptolemy.kernel.util.NamedObj; 049import ptolemy.media.Picture; 050 051/////////////////////////////////////////////////////////////////// 052//// TokenTableau 053 054/** 055 A tableau representing an image displayed in a top-level window. 056 057 @author Edward A. Lee 058 @version $Id$ 059 @since Ptolemy II 4.1 060 @Pt.ProposedRating Yellow (eal) 061 @Pt.AcceptedRating Red (cxh) 062 @see TokenEffigy 063 */ 064public class ImageTableau extends TokenTableau { 065 /** Construct a new tableau for the model represented by the given effigy. 066 * @param container The container. 067 * @param name The name. 068 * @exception IllegalActionException If the container does not accept 069 * this entity (this should not occur). 070 * @exception NameDuplicationException If the name coincides with an 071 * attribute already in the container. 072 */ 073 public ImageTableau(Effigy container, String name) 074 throws IllegalActionException, NameDuplicationException { 075 super(container, name); 076 } 077 078 /** Construct a new tableau for the model represented by the given effigy, 079 * using the specified frame. 080 * @param container The container. 081 * @param name The name. 082 * @param frame The frame to use. 083 * @exception IllegalActionException If the container does not accept 084 * this entity (this should not occur). 085 * @exception NameDuplicationException If the name coincides with an 086 * attribute already in the container. 087 */ 088 public ImageTableau(Effigy container, String name, TableauFrame frame) 089 throws IllegalActionException, NameDuplicationException { 090 super(container, name, frame); 091 } 092 093 /** Construct a new tableau for the model represented by the given effigy, 094 * using the specified frame. 095 * @param container The container. 096 * @param name The name. 097 * @param frame The frame to use. 098 * @param width The width of the picture display in pixels. 099 * @param height The height of the picture display in pixels. 100 * @exception IllegalActionException If the container does not accept 101 * this entity (this should not occur). 102 * @exception NameDuplicationException If the name coincides with an 103 * attribute already in the container. 104 */ 105 public ImageTableau(Effigy container, String name, TableauFrame frame, 106 int width, int height) 107 throws IllegalActionException, NameDuplicationException { 108 super(container, name, frame); 109 _oldxsize = width; 110 _oldysize = height; 111 } 112 113 /////////////////////////////////////////////////////////////////// 114 //// public methods //// 115 116 /** Display the specified token. 117 * If the token is not an ImageToken, do nothing. 118 * @param token The token to display. 119 * @exception IllegalActionException If the token is not an ImageToken. 120 */ 121 @Override 122 public void append(Token token) throws IllegalActionException { 123 if (token instanceof ImageToken) { 124 display((ImageToken) token); 125 } 126 } 127 128 /** Display the specified tokens. 129 * If the tokens are not instances of ImageToken, do nothing. 130 * @exception IllegalActionException If the tokens are not 131 * instances of ImageToken. 132 */ 133 @Override 134 public void append(List list) throws IllegalActionException { 135 Iterator tokens = list.iterator(); 136 137 while (tokens.hasNext()) { 138 Object token = tokens.next(); 139 140 if (token instanceof ImageToken) { 141 display((ImageToken) token); 142 } 143 } 144 } 145 146 /** Return true if this tableau can display the specified token. 147 * @param token A candidate token to display. 148 * @return True, since this tableau can display any token. 149 */ 150 public static boolean canDisplay(Token token) { 151 if (token instanceof ImageToken) { 152 return true; 153 } else { 154 return false; 155 } 156 } 157 158 /** Clear the display. 159 */ 160 @Override 161 public void clear() { 162 if (_picture != null) { 163 // FIXME: How to do this? 164 // _picture.clear(); 165 } 166 } 167 168 /** Create an image display to view the picture. 169 * This is called in the constructor. 170 * @param frame The frame to use, or null if none is specified. 171 * @exception IllegalActionException If the frame cannot be created. 172 */ 173 @Override 174 public void createFrame(TableauFrame frame) throws IllegalActionException { 175 ImageTokenEffigy effigy = (ImageTokenEffigy) getContainer(); 176 177 if (frame == null) { 178 // The second argument prevents a status bar. 179 frame = new TableauFrame(this, null); 180 } 181 182 setFrame(frame); 183 ImageToken token = effigy.getImage(); 184 if (token == null) { 185 _picture = new Picture(_oldxsize, _oldysize); 186 } else { 187 Image image = token.asAWTImage(); 188 if (image != null) { 189 int width = image.getWidth(null); 190 int height = image.getHeight(null); 191 if (width > 0 && height > 0) { 192 // FIXME: scale to fit on screen. 193 _picture = new Picture(width, height); 194 } else { 195 _picture = new Picture(_oldxsize, _oldysize); 196 } 197 } else { 198 _picture = new Picture(_oldxsize, _oldysize); 199 } 200 } 201 frame.getContentPane().add(_picture, BorderLayout.CENTER); 202 203 // Display current data. 204 if (token != null) { 205 display(token); 206 } 207 } 208 209 /** Display the specified token. 210 * @param token The token to append. 211 * @exception IllegalActionException If the token is null or 212 * not an ImageToken. 213 */ 214 public void display(ImageToken token) throws IllegalActionException { 215 Image image = token.asAWTImage(); 216 217 if (image == null) { 218 throw new IllegalActionException(this, 219 "ImageTableau: input image was null!"); 220 } else { 221 int xsize = image.getWidth(null); 222 int ysize = image.getHeight(null); 223 224 if (_oldxsize != xsize || _oldysize != ysize) { 225 if (_debugging) { 226 _debug("Image size has changed."); 227 } 228 229 _oldxsize = xsize; 230 _oldysize = ysize; 231 232 Container container = _picture.getParent(); 233 Container top = container.getParent(); 234 235 while (top.getParent() != null) { 236 top = top.getParent(); 237 } 238 239 JFrame castTop = (JFrame) top; 240 241 castTop.getContentPane().remove(_picture); 242 243 _picture = new Picture(xsize, ysize); 244 _picture.setImage(image); 245 _picture.setBackground(null); 246 247 // FIXME: This messes up the menus! 248 castTop.getContentPane().add(_picture, BorderLayout.CENTER); 249 250 // FIXME: All the below appear to be required only by superstition. 251 castTop.getContentPane().validate(); 252 253 // container.invalidate(); 254 // container.repaint(); 255 // container.doLayout(); 256 castTop.pack(); 257 } else { 258 _picture.setImage(image); 259 } 260 261 // display it. 262 _picture.displayImage(); 263 _picture.repaint(); 264 265 Thread.yield(); 266 } 267 } 268 269 /////////////////////////////////////////////////////////////////// 270 //// private members //// 271 272 /** The horizontal size of the previous image. */ 273 private int _oldxsize = 0; 274 275 /** The vertical size of the previous image. */ 276 private int _oldysize = 0; 277 278 /** The frame for displaying the image. */ 279 private Picture _picture; 280 281 /////////////////////////////////////////////////////////////////// 282 //// inner classes //// 283 284 /** A factory that creates a token tableau. 285 */ 286 public static class Factory extends TableauFactory { 287 /** Create a factory with the given name and container. 288 * @param container The container. 289 * @param name The name. 290 * @exception IllegalActionException If the container is incompatible 291 * with this attribute. 292 * @exception NameDuplicationException If the name coincides with 293 * an attribute already in the container. 294 */ 295 public Factory(NamedObj container, String name) 296 throws IllegalActionException, NameDuplicationException { 297 super(container, name); 298 } 299 300 /////////////////////////////////////////////////////////////////// 301 //// public methods //// 302 303 /** If the specified effigy already contains a tableau named 304 * "imageTableau", then return that tableau; otherwise, create 305 * a new instance of ImageTableau in the specified 306 * effigy, and name it "imageTableau". If the specified 307 * effigy is not an instance of TokenEffigy, then do not 308 * create a tableau and return null. It is the 309 * responsibility of callers of this method to check the 310 * return value and call show(). 311 * 312 * @param effigy The effigy, which is expected to be a TokenEffigy. 313 * @return An instance of ImageTableau, or null if one cannot be 314 * found or created. 315 * @exception Exception If the factory should be able to create a 316 * tableau for the effigy, but something goes wrong. 317 */ 318 @Override 319 public Tableau createTableau(Effigy effigy) throws Exception { 320 if (effigy instanceof ImageTokenEffigy) { 321 // First see whether the effigy already contains an 322 // ImageTableau. 323 ImageTableau tableau = (ImageTableau) effigy 324 .getEntity("imageTableau"); 325 326 if (tableau != null) { 327 return tableau; 328 } 329 330 // NOTE: Normally need to check effigy tokens for 331 // compatibility here, but they are always compatible, 332 // so we don't bother. 333 return new ImageTableau(effigy, "imageTableau"); 334 } 335 336 return null; 337 } 338 } 339}