001/*  This parameter, when inserted into a model, causes the ports in the model to display their unconsumed inputs.
002
003 @Copyright (c) 2007-2014 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.vergil.actor.lib;
029
030import java.util.List;
031
032import ptolemy.actor.Actor;
033import ptolemy.actor.CompositeActor;
034import ptolemy.actor.Executable;
035import ptolemy.actor.IOPort;
036import ptolemy.actor.Initializable;
037import ptolemy.data.BooleanToken;
038import ptolemy.data.expr.SingletonParameter;
039import ptolemy.kernel.util.ChangeRequest;
040import ptolemy.kernel.util.IllegalActionException;
041import ptolemy.kernel.util.InternalErrorException;
042import ptolemy.kernel.util.NameDuplicationException;
043import ptolemy.kernel.util.NamedObj;
044import ptolemy.kernel.util.Settable;
045import ptolemy.kernel.util.SingletonAttribute;
046
047///////////////////////////////////////////////////////////////////
048//// MonitorReceiverContents
049
050/**
051 This parameter, when inserted into a model or an opaque composite actor,
052 causes all input ports to acquire an attribute that makes them display
053 their contents on the screen.  This works by piggybacking on the
054 initialize() method of the container to insert the relevant parameters
055 into the ports. It also piggybacks on postfire() and wrapup() to issue
056 a ChangeRequest, which causes a repaint of the screen in Vergil.
057 To stop monitoring the queue contents, simply delete
058 this attribute from the model.
059 To use this one option is to instantiate an attribute of type
060 ptolemy.vergil.actor.lib.MonitorReceiverContents
061
062 @author  Edward A. Lee, Contributor: Bert Rodiers
063 @version $Id$
064 @since Ptolemy II 8.0
065 @Pt.ProposedRating Yellow (eal)
066 @Pt.AcceptedRating Red (cxh)
067 */
068public class MonitorReceiverContents extends SingletonAttribute {
069
070    /** Construct an actor with the specified container and name.
071     *  @param container The container.
072     *  @param name The name of this actor.
073     *  @exception IllegalActionException If the entity cannot be contained
074     *   by the proposed container.
075     *  @exception NameDuplicationException If the container already has an
076     *   actor with this name.
077     */
078    public MonitorReceiverContents(NamedObj container, String name)
079            throws IllegalActionException, NameDuplicationException {
080        super(container, name);
081
082        // The icon.
083        _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-60\" y=\"-10\" "
084                + "width=\"180\" height=\"20\" " + "style=\"fill:#00FFFF\"/>\n"
085                + "<text x=\"-55\" y=\"5\" "
086                + "style=\"font-size:14; font-family:SansSerif; fill:blue\">\n"
087                + "MonitorReceiverContents\n" + "</text>\n" + "</svg>\n");
088
089        // Hide the name.
090        SingletonParameter hideName = new SingletonParameter(this, "_hideName");
091        hideName.setToken(BooleanToken.TRUE);
092        hideName.setVisibility(Settable.EXPERT);
093    }
094
095    ///////////////////////////////////////////////////////////////////
096    ////                         public methods                    ////
097
098    /** Specify the container. If the container is not the same as the
099     *  previous container, then stop monitoring queue contents in the
100     *  previous container, and start monitoring them in the new one.
101     *  @param container The container to attach this attribute to..
102     *  @exception IllegalActionException If this attribute is not of the
103     *   expected class for the container, or it has no name,
104     *   or the attribute and container are not in the same workspace, or
105     *   the proposed container would result in recursive containment.
106     *  @exception NameDuplicationException If the container already has
107     *   an attribute with the name of this attribute.
108     *  @see #getContainer()
109     */
110    @Override
111    public void setContainer(final NamedObj container)
112            throws IllegalActionException, NameDuplicationException {
113        NamedObj previousContainer = getContainer();
114        if (previousContainer == container) {
115            return;
116        }
117        if (previousContainer != null
118                && previousContainer instanceof CompositeActor) {
119            // _piggybackContainer should be non-null, but we check anyway.
120            if (_piggybackContainer != null) {
121                _piggybackContainer.removePiggyback(_executable);
122            }
123            _executable = null;
124            // Also, remove all _showInfo attributes in the ports of the previous container.
125            List<Actor> entities = ((CompositeActor) previousContainer)
126                    .deepEntityList();
127            for (Actor entity : entities) {
128                List<IOPort> ports = entity.inputPortList();
129                for (IOPort port : ports) {
130                    List<MonitorReceiverAttribute> attributes = port
131                            .attributeList(MonitorReceiverAttribute.class);
132                    for (MonitorReceiverAttribute attribute : attributes) {
133                        attribute.setContainer(null);
134                    }
135                }
136            }
137        }
138        super.setContainer(container);
139
140        if (container != null && container instanceof CompositeActor) {
141            if (_executable == null) {
142                // The inner class will be piggybacked as an executable for the container to
143                // execute change request at the appropriate times. These change request will
144                // lead to repaints of the GUI.
145                _executable = new Executable() {
146
147                    @Override
148                    public void initialize() throws IllegalActionException {
149                        // Add _showInfo attributes to any input port that does not already have one.
150                        try {
151                            workspace().getWriteAccess();
152                            List<Actor> entities = ((CompositeActor) container)
153                                    .deepEntityList();
154                            for (Actor entity : entities) {
155                                List<IOPort> ports = entity.inputPortList();
156                                for (IOPort port : ports) {
157                                    if (port.getAttribute(
158                                            "_showInfo") == null) {
159                                        MonitorReceiverAttribute attribute = new MonitorReceiverAttribute(
160                                                port, "_showInfo");
161                                        attribute.setPersistent(false);
162                                    }
163                                }
164                            }
165                        } catch (NameDuplicationException ex) {
166                            throw new InternalErrorException(ex);
167                        } finally {
168                            workspace().doneTemporaryWriting();
169                        }
170                    }
171
172                    // Request repaint on postfire() and wrapup().
173                    @Override
174                    public boolean postfire() {
175                        ChangeRequest request = new ChangeRequest(this,
176                                "SetVariable change request",
177                                true /*Although this not a structural change in my point of view
178                                     , we however for some reason need to specify it is, otherwise the GUI won't update.*/
179                        ) {
180                            @Override
181                            protected void _execute()
182                                    throws IllegalActionException {
183                            }
184                        };
185                        // To prevent prompting for saving the model, mark this
186                        // change as non-persistent.
187                        request.setPersistent(false);
188                        requestChange(request);
189                        return true;
190                    }
191
192                    @Override
193                    public void wrapup() {
194                        ChangeRequest request = new ChangeRequest(this,
195                                "SetVariable change request", true) {
196                            @Override
197                            protected void _execute()
198                                    throws IllegalActionException {
199                            }
200                        };
201                        // To prevent prompting for saving the model, mark this
202                        // change as non-persistent.
203                        request.setPersistent(false);
204                        requestChange(request);
205                    }
206
207                    // All other methods are empty.
208                    @Override
209                    public void fire() throws IllegalActionException {
210                    }
211
212                    @Override
213                    public boolean isFireFunctional() {
214                        return true;
215                    }
216
217                    @Override
218                    public boolean isStrict() {
219                        return true;
220                    }
221
222                    @Override
223                    public int iterate(int count) {
224                        return Executable.COMPLETED;
225                    }
226
227                    @Override
228                    public boolean prefire() throws IllegalActionException {
229                        return true;
230                    }
231
232                    @Override
233                    public void stop() {
234                    }
235
236                    @Override
237                    public void stopFire() {
238                    }
239
240                    @Override
241                    public void terminate() {
242                    }
243
244                    @Override
245                    public void addInitializable(Initializable initializable) {
246                    }
247
248                    @Override
249                    public void preinitialize() throws IllegalActionException {
250                    }
251
252                    @Override
253                    public void removeInitializable(
254                            Initializable initializable) {
255                    }
256                };
257            }
258
259            _piggybackContainer = (CompositeActor) container;
260            _piggybackContainer.addPiggyback(_executable);
261        }
262    }
263
264    ///////////////////////////////////////////////////////////////////
265    ////                         private variables                 ////
266
267    /** The executable that creates the monitor attributes in initialize(). */
268    private Executable _executable;
269
270    /** The last container on which we piggybacked. */
271    private CompositeActor _piggybackContainer;
272}