001/*
002 Interface encapsulating platform dependent code of the PlotterBase from the
003 platform independent parts.
004
005 @Copyright (c) 1998-2014 The Regents of the University of California.
006 All rights reserved.
007
008 Permission is hereby granted, without written agreement and without
009 license or royalty fees, to use, copy, modify, and distribute this
010 software and its documentation for any purpose, provided that the
011 above copyright notice and the following two paragraphs appear in all
012 copies of this software.
013
014 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
015 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
016 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
017 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
018 SUCH DAMAGE.
019
020 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
021 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
022 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
023 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
024 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
025 ENHANCEMENTS, OR MODIFICATIONS.
026
027 PT_COPYRIGHT_VERSION 2
028 COPYRIGHTENDKEY
029 */
030
031package ptolemy.actor.lib.gui;
032
033import java.awt.Component;
034import java.awt.Container;
035import java.awt.event.WindowAdapter;
036import java.awt.event.WindowEvent;
037
038import javax.swing.SwingUtilities;
039
040import ptolemy.actor.gui.Configuration;
041import ptolemy.actor.gui.Effigy;
042import ptolemy.actor.gui.PlotEffigy;
043import ptolemy.actor.gui.PlotTableau;
044import ptolemy.actor.gui.PlotTableauFrame;
045import ptolemy.actor.gui.SizeAttribute;
046import ptolemy.actor.gui.WindowPropertiesAttribute;
047import ptolemy.kernel.util.IllegalActionException;
048import ptolemy.kernel.util.NameDuplicationException;
049import ptolemy.plot.Plot;
050import ptolemy.plot.PlotBox;
051import ptolemy.plot.PlotBoxInterface;
052
053///////////////////////////////////////////////////////////////////
054//// PlotterBaseJavaSE
055
056/**
057 * Java SE implementation of PlotterBaseInterface.  The code is largely based on
058 * the original platform dependent version of the PlotterBase but was moved here
059 * in order to support portability of the actor.
060 * @author Edward A. Lee Contributors: Anar Huseynov
061 * @version $Id$
062 * @since Ptolemy II 10.0
063 * @Pt.ProposedRating Red (ahuseyno)
064 * @Pt.AcceptedRating Red (ahuseyno)
065 */
066public class PlotterBaseJavaSE implements PlotterBaseInterface {
067
068    /** Show and then bing the frame to the front. */
069    @Override
070    public void bringToFront() {
071        if (_frame != null) {
072            // show() used to call pack, which would override any manual
073            // changes in placement. No more.
074            _frame.show();
075            _frame.toFront();
076        }
077    }
078
079    /**
080     * Free up memory when closing.
081     */
082    @Override
083    public void cleanUp() {
084        _tableau = null;
085    }
086
087    /**
088     * Get the plotter's frame.
089     * @return the plotter's frame.
090     * @see #setFrame(Object)
091     */
092    @Override
093    public Object getFrame() {
094        return _frame;
095    }
096
097    /**
098     * Get the platform dependent container that contains the plotter.
099     * @return the platform dependent container.
100     * @see #setPlatformContainer(Object)
101     */
102    @Override
103    public Object getPlatformContainer() {
104        return _container;
105    }
106
107    /**
108     * Get the plotter tableau.
109     * @return the plotter tableau.
110     */
111    @Override
112    public Object getTableau() {
113        return _tableau;
114    }
115
116    /**
117     * Initialize the implementation.
118     * @param plotterBase the instance that created the implementation.
119     */
120    @Override
121    public void init(PlotterBase plotterBase) {
122        _plotterBase = plotterBase;
123    }
124
125    /**
126     * Initialize the effigy of the plotter.
127     * @exception IllegalActionException If there is a problem initializing the effigy
128     */
129    @Override
130    public void initializeEffigy() throws IllegalActionException {
131        // Need an effigy and a tableau so that menu ops work properly.
132        Effigy containerEffigy = Configuration
133                .findEffigy(_plotterBase.toplevel());
134
135        if (containerEffigy == null) {
136            try {
137                containerEffigy = new PlotEffigy(_plotterBase.workspace());
138                //containerEffigy.setModel(_plotterBase.toplevel());
139            } catch (Exception ex) {
140                throw new IllegalActionException(_plotterBase, ex,
141                        "Cannot find effigy for top level: "
142                                + _plotterBase.toplevel().getFullName());
143            }
144        }
145
146        try {
147            PlotEffigy plotEffigy;
148            // In PN models, there could be multiple of these running
149            // at the same time, in which case we may get a name collision.
150            // To prevent this, synchronize on the effigy.
151            synchronized (containerEffigy) {
152                plotEffigy = new PlotEffigy(containerEffigy,
153                        containerEffigy.uniqueName("plot"));
154            }
155            // Specify that the associated plot is the one created here.
156            plotEffigy.setPlot(_plotterBase.plot);
157            // Specify that the associated Ptolemy model is this actor.
158            plotEffigy.setModel(_plotterBase);
159
160            // The default identifier is "Unnamed", which is no good for
161            // two reasons: Wrong title bar label, and it causes a save-as
162            // to destroy the original window.
163            plotEffigy.identifier.setExpression(_plotterBase.getFullName());
164
165            _tableau = new PlotWindowTableau(plotEffigy, "tableau");
166
167            setFrame(_tableau.frame);
168        } catch (Exception ex) {
169            throw new IllegalActionException(_plotterBase, null, ex,
170                    "Error creating effigy and tableau");
171        }
172    }
173
174    /**
175     * Initialize the effigy of the plotter.
176     * @exception IllegalActionException If there is a problem initializing the effigy
177     */
178    @Override
179    public void initWindowAndSizeProperties()
180            throws IllegalActionException, NameDuplicationException {
181        _windowProperties = (WindowPropertiesAttribute) _plotterBase
182                .getAttribute("_windowProperties",
183                        WindowPropertiesAttribute.class);
184        if (_windowProperties == null) {
185            _windowProperties = new WindowPropertiesAttribute(_plotterBase,
186                    "_windowProperties");
187            // Note that we have to force this to be persistent because
188            // there is no real mechanism for the value of the properties
189            // to be updated when the window is moved or resized. By
190            // making it persistent, when the model is saved, the
191            // attribute will determine the current size and position
192            // of the window and save it.
193            _windowProperties.setPersistent(true);
194        }
195        _plotSize = (SizeAttribute) _plotterBase.getAttribute("_plotSize",
196                SizeAttribute.class);
197        if (_plotSize == null) {
198            _plotSize = new SizeAttribute(_plotterBase, "_plotSize");
199            _plotSize.setPersistent(true);
200        }
201    }
202
203    /**
204     * Create a new instance of the PlotBoxInterface implementation.
205     * @return a new instance of the PlotBoxInterface implementation.
206     */
207    @Override
208    public PlotBoxInterface newPlot() {
209        return new Plot();
210    }
211
212    /**
213     * Remove the plot from the current container, if there is one.
214     */
215    @Override
216    public void remove() {
217        SwingUtilities.invokeLater(new Runnable() {
218            @Override
219            public void run() {
220                if (_plotterBase.plot != null) {
221                    if (_container != null) {
222                        _container.remove((Component) _plotterBase.plot);
223                        _container.invalidate();
224                        _container.repaint();
225                    } else if (_frame != null) {
226                        _frame.dispose();
227                    }
228                }
229            }
230        });
231    }
232
233    /**
234     * Remove the plot from the frame if the container is null.
235     */
236    @Override
237    public void removeNullContainer() {
238        // NOTE: This actor always shows the plot buttons, even if
239        // the plot is in a separate frame.  They are very useful.
240        if (_container == null) {
241            // Dissociate with any container.
242            // NOTE: _remove() doesn't work here.  Why?
243            if (_frame != null) {
244                _frame.dispose();
245            }
246
247            _frame = null;
248
249            // If we forget the plot, then its properties get lost.
250            // Also, if the window is deleted during a run, the data
251            // will be lost. So do not forget the plot.
252            // plot = null;
253            return;
254        }
255    }
256
257    /**
258     * Set the frame of the plotter.
259     * @param frame The frame to set.
260     * @see #getFrame()
261     */
262    @Override
263    public void setFrame(Object frame) {
264        if (_frame != null) {
265            _frame.removeWindowListener(_windowClosingAdapter);
266        }
267
268        if (frame == null) {
269            _frame = null;
270            return;
271        }
272
273        _frame = (PlotTableauFrame) frame;
274
275        _windowClosingAdapter = new WindowClosingAdapter();
276        _frame.addWindowListener(_windowClosingAdapter);
277
278        _windowProperties.setProperties(_frame);
279    }
280
281    /**
282     * Set the platform dependent container of the plotter.
283     * The container can be AWT container or Android view.
284     * @param container the platform dependent container.
285     * @see #getPlatformContainer()
286     */
287    @Override
288    public void setPlatformContainer(Object container) {
289        _container = (Container) container;
290    }
291
292    /**
293     * Set the title of the tableau.
294     * @param title the title to set.
295     */
296    @Override
297    public void setTableauTitle(String title) {
298        if (_tableau != null) {
299            _tableau.setTitle(title);
300        }
301    }
302
303    /**
304     * Update size attribute of the plotter.
305     */
306    @Override
307    public void updateSize() {
308        if (_plotSize != null) {
309            _plotSize.setSize((Component) _plotterBase.plot);
310        }
311
312        if (_frame != null) {
313            _frame.pack();
314        }
315    }
316
317    /**
318     * Update values of the attributes.
319     */
320    @Override
321    public void updateWindowAndSizeAttributes() {
322        if (_frame != null) {
323            _windowProperties.recordProperties(_frame);
324        }
325
326        if (_plotterBase.plot != null) {
327            _plotSize.recordSize((Component) _plotterBase.plot);
328        }
329    }
330
331    ///////////////////////////////////////////////////////////////////
332    ////                         protected variables               ////
333    /** Container into which this plot should be placed. */
334    protected Container _container;
335
336    /** Frame into which plot is placed, if any. */
337    protected transient PlotTableauFrame _frame;
338
339    /** An attribute that contains the size of the plot. */
340    protected SizeAttribute _plotSize;
341
342    /** The base instance that created the implementation. */
343    protected PlotterBase _plotterBase;
344
345    /** The Plotter tableau. */
346    protected PlotWindowTableau _tableau;
347
348    /** A reference to the listener for removal purposes. */
349    protected WindowClosingAdapter _windowClosingAdapter;
350
351    /** An attribute tha contains the size and position of the window. */
352    protected WindowPropertiesAttribute _windowProperties;
353
354    ///////////////////////////////////////////////////////////////////
355    ////                         inner classes                     ////
356
357    /** Tableau that creates a PlotterPlotFrame.
358     */
359    protected class PlotWindowTableau extends PlotTableau {
360        /** Construct a new tableau for the model represented by the
361         *  given effigy.
362         *  @param container The container.
363         *  @param name The name.
364         *  @exception IllegalActionException If the container does not accept
365         *   this entity (this should not occur).
366         *  @exception NameDuplicationException If the name coincides with an
367         *   attribute already in the container.
368         */
369        public PlotWindowTableau(PlotEffigy container, String name)
370                throws IllegalActionException, NameDuplicationException {
371            super(container, name);
372            frame = new PlotTableauFrame(this, (PlotBox) _plotterBase.plot,
373                    _plotterBase);
374            setFrame(frame);
375        }
376
377        /** The frame. */
378        public PlotTableauFrame frame;
379    }
380
381    /** Listener for windowClosing action. */
382    class WindowClosingAdapter extends WindowAdapter {
383        @Override
384        public void windowClosing(WindowEvent e) {
385            _plotterBase.cleanUp();
386        }
387    }
388}