001/* Base class for actors implementing the Placeable interface.
002
003 Copyright (c) 2007-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.actor.gui;
030
031import java.awt.Component;
032import java.awt.Container;
033import java.awt.event.WindowAdapter;
034import java.awt.event.WindowEvent;
035import java.io.IOException;
036import java.io.Writer;
037
038import javax.swing.JFrame;
039
040import ptolemy.actor.TypedAtomicActor;
041import ptolemy.kernel.CompositeEntity;
042import ptolemy.kernel.util.IllegalActionException;
043import ptolemy.kernel.util.NameDuplicationException;
044import ptolemy.kernel.util.Workspace;
045
046///////////////////////////////////////////////////////////////////
047//// AbstractPlaceableActor
048
049/**
050 Base class for actors that implement the Placeable interface.
051
052 @author Edward A. Lee
053 @version $Id$
054 @since Ptolemy II 6.1
055 @Pt.ProposedRating Green (eal)
056 @Pt.AcceptedRating Yellow (cxh)
057 */
058public abstract class AbstractPlaceableActor extends TypedAtomicActor
059        implements Placeable {
060
061    /** Construct an actor with the specified container and name.
062     *  @param container The container.
063     *  @param name The name of this actor.
064     *  @exception IllegalActionException If the entity cannot be contained
065     *   by the proposed container.
066     *  @exception NameDuplicationException If the container already has an
067     *   actor with this name.
068     */
069    public AbstractPlaceableActor(CompositeEntity container, String name)
070            throws IllegalActionException, NameDuplicationException {
071        super(container, name);
072
073        _windowProperties = new WindowPropertiesAttribute(this,
074                "_windowProperties");
075        // Note that we have to force this to be persistent because
076        // there is no real mechanism for the value of the properties
077        // to be updated when the window is moved or resized. By
078        // making it persistent, when the model is saved, the
079        // attribute will determine the current size and position
080        // of the window and save it.
081        _windowProperties.setPersistent(true);
082        _paneSize = new SizeAttribute(this, "_paneSize");
083        _paneSize.setPersistent(true);
084    }
085
086    ///////////////////////////////////////////////////////////////////
087    ////                         public methods                    ////
088
089    /** Clone the actor.
090     *  @param workspace The workspace in which to place the cloned variable.
091     *  @exception CloneNotSupportedException Not thrown in this base class.
092     *  @see java.lang.Object#clone()
093     *  @return The cloned variable.
094     */
095    @Override
096    public Object clone(Workspace workspace) throws CloneNotSupportedException {
097        AbstractPlaceableActor newObject = (AbstractPlaceableActor) super.clone(
098                workspace);
099        try {
100            newObject._windowProperties = (WindowPropertiesAttribute) newObject
101                    .getAttribute("_windowProperties");
102            newObject._windowProperties.setPersistent(true);
103
104            newObject._paneSize = (SizeAttribute) newObject
105                    .getAttribute("_paneSize");
106            newObject._paneSize.setPersistent(true);
107
108        } catch (Throwable throwable) {
109            throw new CloneNotSupportedException(
110                    getFullName() + ": Failed to clone: " + throwable);
111        }
112        return newObject;
113    }
114
115    /** Specify the container into which this object should be placed.
116     *  Obviously, this method needs to be called before the object
117     *  is actually placed in a container.  Otherwise, the object will be
118     *  expected to create its own frame into which to place itself.
119     *  For actors, this method should be called before initialize().
120     *  @param container The container in which to place the object, or
121     *   null to specify that there is no current container.
122     */
123    @Override
124    public abstract void place(Container container);
125
126    /** Specify the associated frame and set its properties (size, etc.)
127     *  to match those stored in the _windowProperties attribute.
128     *  @param frame The associated frame.
129     */
130    public void setFrame(JFrame frame) {
131
132        if (_frame != null) {
133            _frame.removeWindowListener(_windowClosingAdapter);
134        }
135
136        if (frame == null) {
137            _frame = null;
138            return;
139        }
140
141        _frame = frame;
142
143        _windowClosingAdapter = new WindowClosingAdapter();
144        frame.addWindowListener(_windowClosingAdapter);
145
146        _windowProperties.setProperties(_frame);
147
148        // Regrettably, since setSize() in swing doesn't actually
149        // set the size of the frame, we have to also set the
150        // size of the internal component.
151        Component[] components = _frame.getContentPane().getComponents();
152
153        if (components.length > 0) {
154            _paneSize.setSize(components[0]);
155        }
156    }
157
158    ///////////////////////////////////////////////////////////////////
159    ////                         protected methods                 ////
160
161    /** Free up memory when closing. */
162    protected void cleanUp() {
163        setFrame(null);
164    }
165
166    /** Write a MoML description of the contents of this object. This
167     *  overrides the base class to make sure that the current frame
168     *  properties, if there is a frame, are recorded.
169     *  @param output The output stream to write to.
170     *  @param depth The depth in the hierarchy, to determine indenting.
171     *  @exception IOException If an I/O error occurs.
172     */
173    @Override
174    protected void _exportMoMLContents(Writer output, int depth)
175            throws IOException {
176        // Make sure that the current position of the frame, if any,
177        // is up to date.
178        if (_frame != null) {
179            _windowProperties.recordProperties(_frame);
180
181            // Regrettably, have to also record the size of the contents
182            // because in Swing, setSize() methods do not set the size.
183            // Only the first component size is recorded.
184            Component[] components = _frame.getContentPane().getComponents();
185
186            if (components.length > 0) {
187                _paneSize.recordSize(components[0]);
188            }
189        }
190
191        super._exportMoMLContents(output, depth);
192    }
193
194    ///////////////////////////////////////////////////////////////////
195    ////                         protected variables               ////
196
197    /** The associated frame. */
198    protected JFrame _frame;
199
200    /** A specification of the size of the pane if it's in its own window. */
201    protected SizeAttribute _paneSize;
202
203    /** A specification for the window properties of the frame. */
204    protected WindowPropertiesAttribute _windowProperties;
205
206    /** A reference to the listener for removal purposes. */
207    protected WindowClosingAdapter _windowClosingAdapter;
208
209    ///////////////////////////////////////////////////////////////////
210    ////                         inner classes                     ////
211
212    /** Listener for windowClosing action. */
213    class WindowClosingAdapter extends WindowAdapter {
214        @Override
215        public void windowClosing(WindowEvent e) {
216            cleanUp();
217        }
218    }
219}