001/* Base class for plotters, except histograms.
002
003 @Copyright (c) 1998-2015 The Regents of the University of California.
004 All rights reserved.
005
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the
009 above copyright notice and the following two paragraphs appear in all
010 copies of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION 2
026 COPYRIGHTENDKEY
027 */
028package ptolemy.actor.lib.gui;
029
030import ptolemy.data.BooleanToken;
031import ptolemy.data.IntToken;
032import ptolemy.data.expr.Parameter;
033import ptolemy.data.type.BaseType;
034import ptolemy.kernel.CompositeEntity;
035import ptolemy.kernel.util.Attribute;
036import ptolemy.kernel.util.IllegalActionException;
037import ptolemy.kernel.util.NameDuplicationException;
038import ptolemy.plot.PlotInterface;
039
040///////////////////////////////////////////////////////////////////
041//// Plotter
042
043/**
044 Base class for plotters.  This class contains an instance of the
045 Plot class from the Ptolemy plot package as a public member.
046 It provides a parameter that determines whether to fill the plot
047 when wrapup is invoked. It also has a <i>legend</i> parameter,
048 which gives a comma-separated list of labels to attach to
049 each dataset.  Normally, the number of elements in this list
050 should equal the number of input channels, although this
051 is not enforced.
052 <p>
053 This actor also provides a parameter
054 <i>startingDataset</i>, which specifies the starting point
055 for the number of the dataset to use to create the plots.
056 This defaults to zero, but will typically be set to a positive
057 number when more than one instance of a plotter actor shares
058 the same plot object.
059
060 @see ptolemy.plot.PlotInterface
061
062 @author  Edward A. Lee
063 @version $Id$
064 @since Ptolemy II 1.0
065 @Pt.ProposedRating Green (eal)
066 @Pt.AcceptedRating Green (cxh)
067 */
068public class Plotter extends PlotterBase {
069    /** Construct an actor with the given container and name.
070     *  @param container The container.
071     *  @param name The name of this actor.
072     *  @exception IllegalActionException If the actor cannot be contained
073     *   by the proposed container.
074     *  @exception NameDuplicationException If the container already has an
075     *   actor with this name.
076     */
077    public Plotter(CompositeEntity container, String name)
078            throws IllegalActionException, NameDuplicationException {
079        super(container, name);
080
081        startingDataset = new Parameter(this, "startingDataset",
082                new IntToken(0));
083        startingDataset.setTypeEquals(BaseType.INT);
084    }
085
086    ///////////////////////////////////////////////////////////////////
087    ////                     ports and parameters                  ////
088
089    /** The starting dataset number to which data is plotted.
090     *  This parameter has type IntToken, with default value 0.
091     *  Its value must be non-negative.
092     */
093    public Parameter startingDataset;
094
095    ///////////////////////////////////////////////////////////////////
096    ////                         public methods                    ////
097
098    /** If the attribute is <i>startingDataset</i>, then check its validity.
099     *  @param attribute The attribute that changed.
100     *  @exception IllegalActionException If the specified attribute
101     *   is <i>startingDataset</i> and its value is negative, or if the
102     *   superclass throws it.
103     */
104    @Override
105    public void attributeChanged(Attribute attribute)
106            throws IllegalActionException {
107        // NOTE: Do not react to changes in _windowProperties.
108        // Those properties are only used when originally opening a window.
109        if (attribute == startingDataset) {
110            IntToken dataset = (IntToken) startingDataset.getToken();
111            if (dataset == null) {
112                throw new IllegalActionException(this,
113                        "startingDataset null: please enter a nonnegative index value.");
114            } else if (dataset.intValue() < 0) {
115                throw new IllegalActionException(this,
116                        "startingDataset: negative value is not allowed.");
117            }
118        } else {
119            super.attributeChanged(attribute);
120        }
121    }
122
123    /** If the plot has not already been created, create it.
124     *  If configurations specified by a call to configure() have not yet
125     *  been processed, process them. Clear the data sets that this
126     *  actor is responsible for (starting with the one indexed
127     *  by <i>startingDataset</i>, up to <i>startingDataset</i> +
128     *  <i>width</i> - 1, where <i>width</i> is the width of the
129     *  input port.
130     *  @exception IllegalActionException If the parent class throws it.
131     */
132    @Override
133    public void initialize() throws IllegalActionException {
134        super.initialize();
135
136        if (plot == null) {
137            // Create a new plot.
138            plot = _newPlot();
139            plot.setTitle(getName());
140            plot.setButtons(true);
141        }
142
143        if (((BooleanToken) automaticRescale.getToken()).booleanValue()) {
144            plot.setAutomaticRescale(true);
145        }
146
147        if (_getImplementation().getFrame() == null
148                && _getImplementation().getPlatformContainer() == null) {
149            _getImplementation().initializeEffigy();
150            _implementDeferredConfigurations();
151            _getImplementation().updateSize();
152        } else {
153            if (plot instanceof PlotInterface) {
154                // FIXME: super.preinitialize() calls PlotBoxInterface.clear(), which
155                // in Plot.java is likely to set the the number of datasets to 0.
156                // This, this code is likely to not actually clear the datasets as
157                // the clearing has already been done.
158                // Another issue is that this super.preinitialize() calls clear in
159                // the Swing event thread, but so the clear might not have happened
160                // when we read the value of the number of datasets.  Thus, we could
161                // get the value, preinitialize() could clear it and then we call
162                // clear again below.
163                int width = ((PlotInterface) plot).getNumDataSets();
164                int offset = ((IntToken) startingDataset.getToken()).intValue();
165                for (int i = width - 1; i >= 0; i--) {
166                    ((PlotInterface) plot).clear(i + offset);
167                }
168
169                plot.repaint();
170            } else {
171                plot.clear(false);
172                plot.repaint();
173            }
174        }
175
176        _getImplementation().bringToFront();
177    }
178}