001/* This actor implements a communication aspect Monitor.
002
003@Copyright (c) 2010-2014 The Regents of the University of California.
004All rights reserved.
005
006Permission is hereby granted, without written agreement and without
007license or royalty fees, to use, copy, modify, and distribute this
008software and its documentation for any purpose, provided that the
009above copyright notice and the following two paragraphs appear in all
010copies of this software.
011
012IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016SUCH DAMAGE.
017
018THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023ENHANCEMENTS, OR MODIFICATIONS.
024
025                                                PT_COPYRIGHT_VERSION_2
026                                                COPYRIGHTENDKEY
027
028
029 */
030
031package ptolemy.actor.gui;
032
033import java.awt.Color;
034import java.awt.Frame;
035import java.util.ArrayList;
036import java.util.List;
037
038import ptolemy.actor.Actor;
039import ptolemy.actor.CommunicationAspect;
040import ptolemy.actor.CommunicationAspectListener;
041import ptolemy.actor.CompositeActor;
042import ptolemy.actor.Director;
043import ptolemy.actor.TypedAtomicActor;
044import ptolemy.data.BooleanToken;
045import ptolemy.data.expr.SingletonParameter;
046import ptolemy.kernel.CompositeEntity;
047import ptolemy.kernel.util.IllegalActionException;
048import ptolemy.kernel.util.InternalErrorException;
049import ptolemy.kernel.util.NameDuplicationException;
050import ptolemy.kernel.util.NamedObj;
051import ptolemy.kernel.util.Settable;
052import ptolemy.plot.Plot;
053
054/** This actor implements a Communication aspect Monitor.
055 *  This monitor shows when communication aspects in the model receive messages
056 *  and send messages in a 2D plot. The x-Axis is the time, the y-Axis shows how
057 *  many messages are currently processed by the communication aspect.
058 *
059 *  @author Patricia Derler
060 *  @version $Id$
061 *  @since Ptolemy II 10.0
062 *  @Pt.ProposedRating Yellow (derler)
063 *  @Pt.AcceptedRating Red (derler)
064 */
065public class CommunicationAspectMonitor extends TypedAtomicActor
066        implements CommunicationAspectListener {
067
068    /** Construct a factory with the specified container and name.
069     *  @param container The container.
070     *  @param name The name of the factory.
071     *  @exception IllegalActionException
072     *      If the factory is not of an acceptable attribute for
073     *      the container.
074     *  @exception NameDuplicationException
075     *      If the name coincides with an attribute already in the
076     *      container.
077     */
078    public CommunicationAspectMonitor(CompositeEntity container, String name)
079            throws IllegalActionException, NameDuplicationException {
080        super(container, name);
081
082        _attachText("_iconDescription", "<svg>\n"
083                + "<rect x=\"-50\" y=\"-20\" width=\"130\" height=\"40\" "
084                + "style=\"fill:blue\"/>" + "<text x=\"-40\" y=\"-5\" "
085                + "style=\"font-size:12; font-family:SansSerif; fill:white\">"
086                + "Double click to\nplot the schedule.</text></svg>");
087
088        new CommunicationAspectMonitorEditorFactory(this, "_editorFactory");
089
090        SingletonParameter hide = new SingletonParameter(this, "_hideName");
091        hide.setToken(BooleanToken.TRUE);
092        hide.setVisibility(Settable.EXPERT);
093
094    }
095
096    ///////////////////////////////////////////////////////////////////
097    //                            public variables                   //
098
099    /** The plotter. */
100    public Plot plot;
101
102    ///////////////////////////////////////////////////////////////////
103    //                           public methods                      //
104
105    /** The event is displayed.
106     *  @param qm The communication aspect that sent the event.
107     *  @param source The source actor that caused the event in the
108     *      communication aspect.
109     *  @param messageId The ID of the message that caused the event in
110     *      the communication aspect.
111     *  @param messageCnt The amount of messages currently being processed
112     *      by the communication aspect.
113     *  @param time The time when the event happened.
114     *  @param event The type of the event. e.g. message received, message sent, ...
115     */
116    @Override
117    public void event(final CommunicationAspect qm, Actor source, int messageId,
118            int messageCnt, double time, EventType event) {
119
120        if (plot == null) {
121            return;
122        }
123
124        double x = time;
125        double y = 0;
126        int actorDataset = _communicationAspects.indexOf(qm);
127        if (event == null) {
128            plot.addPoint(actorDataset, x, y, false);
129        } else if (event == EventType.RECEIVED) {
130            plot.addPoint(actorDataset, x, y + 0.1 * messageCnt, true);
131        } else if (event == EventType.SENT) {
132            plot.addPoint(actorDataset, x, y + 0.1 * messageCnt, true);
133        }
134        plot.fillPlot();
135        plot.repaint();
136    }
137
138    Color[] colors;
139
140    /** Initialize the plot and the legend with the list of communication aspects used
141     *  in this model.
142     *  @exception IllegalActionException If thrown by the parent class.
143     */
144    @Override
145    public void initialize() throws IllegalActionException {
146        super.initialize();
147        _communicationAspects = new ArrayList<CommunicationAspect>();
148        if (getContainer() instanceof CompositeActor) {
149            Director director = ((CompositeActor) getContainer()).getDirector();
150            List<Actor> list = ((CompositeActor) director.getContainer())
151                    .entityList();
152            for (Actor actor : list) {
153                if (actor instanceof CommunicationAspect) {
154                    _communicationAspects.add((CommunicationAspect) actor);
155                    ((CommunicationAspect) actor).registerListener(this);
156                }
157            }
158        }
159
160        if (plot != null) {
161            plot.clear(false);
162            plot.clearLegends();
163            colors = new Color[_communicationAspects.size()];
164            for (CommunicationAspect aspect : _communicationAspects) {
165                int idx = _communicationAspects.indexOf(aspect);
166                plot.addLegend(idx, ((NamedObj) aspect).getName());
167                plot.addPoint(idx, 0.0, /*idx*/0, false);
168                colors[idx] = ((ColorAttribute) ((NamedObj) aspect)
169                        .getAttribute(
170                                CommunicationAspect.decoratorHighlightColorName))
171                                        .asColor();
172            }
173
174            plot.doLayout();
175        }
176        // FIXME: This affects all plots in the model:
177        // plot.setColors(colors);
178    }
179
180    ///////////////////////////////////////////////////////////////////
181    //                           private variables                   //
182
183    /** List of communication aspects used in the model. */
184    private List<CommunicationAspect> _communicationAspects;
185
186    ///////////////////////////////////////////////////////////////////
187    //                        inner classes                          //
188
189    /** Factory that creates the schedule plotter. */
190    public class CommunicationAspectMonitorEditorFactory extends EditorFactory {
191        // This class needs to be public for shallow code generation.
192        /**
193         * Constructs a SchedulePlotter$SchedulePlotterEditorFactory object.
194         *
195         * @param container
196         *                The container.
197         * @param name
198         *                The name of the factory.
199         * @exception IllegalActionException
200         *                    If the factory is not of an acceptable attribute
201         *                    for the container.
202         * @exception NameDuplicationException
203         *                    If the name coincides with an attribute already in
204         *                    the container.
205         */
206        public CommunicationAspectMonitorEditorFactory(NamedObj container,
207                String name)
208                throws IllegalActionException, NameDuplicationException {
209            super(container, name);
210        }
211
212        /**
213         * Create an editor for configuring the specified object with the
214         * specified parent window.
215         *
216         * @param object
217         *                The object to configure.
218         * @param parent
219         *                The parent window, or null if there is none.
220         */
221        @Override
222        public void createEditor(NamedObj object, Frame parent) {
223            try {
224                Configuration configuration = ((TableauFrame) parent)
225                        .getConfiguration();
226
227                NamedObj container = object.getContainer();
228
229                plot = new Plot();
230                plot.setTitle("communication aspect Monitor");
231                plot.setButtons(true);
232                plot.setMarksStyle("dots");
233
234                // We put the plotter as a sub-effigy of the toplevel effigy,
235                // so that it closes when the model is closed.
236                Effigy effigy = Configuration.findEffigy(toplevel());
237                PlotEffigy schedulePlotterEffigy = new PlotEffigy(effigy,
238                        container.uniqueName("schedulePlotterEffigy"));
239                schedulePlotterEffigy.setPlot(plot);
240                schedulePlotterEffigy.setModel(this.getContainer());
241                schedulePlotterEffigy.identifier.setExpression("Monitor");
242
243                configuration.createPrimaryTableau(schedulePlotterEffigy);
244
245                plot.setVisible(true);
246            } catch (Throwable throwable) {
247                throw new InternalErrorException(object, throwable,
248                        "Cannot create Plotter");
249            }
250        }
251    }
252
253}