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}