001/**  A controller to do scheduled repaints at certain user specified moments. */
002
003/*
004 Copyright (c) 2008-2014 The Regents of the University of California.
005 All rights reserved.
006
007 Permission is hereby granted, without written agreement and without
008 license or royalty fees, to use, copy, modify, and distribute this
009 software and its documentation for any purpose, provided that the above
010 copyright notice and the following two paragraphs appear in all copies
011 of this software.
012
013 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
014 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
015 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
016 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
017 SUCH DAMAGE.
018
019 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
020 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
021 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
022 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
023 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
024 ENHANCEMENTS, OR MODIFICATIONS.
025 */
026
027package ptolemy.actor.gui;
028
029import ptolemy.actor.CompositeActor;
030import ptolemy.actor.Executable;
031import ptolemy.actor.Initializable;
032import ptolemy.data.BooleanToken;
033import ptolemy.data.expr.Parameter;
034import ptolemy.data.expr.SingletonParameter;
035import ptolemy.data.type.BaseType;
036import ptolemy.kernel.util.Attribute;
037import ptolemy.kernel.util.ChangeRequest;
038import ptolemy.kernel.util.IllegalActionException;
039import ptolemy.kernel.util.NameDuplicationException;
040import ptolemy.kernel.util.NamedObj;
041import ptolemy.kernel.util.Settable;
042import ptolemy.kernel.util.Workspace;
043
044///////////////////////////////////////////////////////////////////
045//// ModelRepaintController
046
047/**
048 * A class to do scheduled repaints at certain user specified moments in
049 * the execution of the model. This component piggy-backs with the execution
050 * of its container, and allows you to define that repaints need to happen when
051 * certain functions of its container are executed. Currently only repaints at
052 * wrapup or post-fire can be scheduled.
053 *
054 * @author Bert Rodiers
055 * @version $Id$
056 * @since Ptolemy II 8.0
057 * @Pt.ProposedRating Red (rodiers)
058 * @Pt.AcceptedRating Red (rodiers)
059 */
060public class ModelRepaintController extends Attribute {
061    /** Construct an instance of the ModelRepaintController.
062     *  @param container The container.
063     *  @param name The name.
064     *  @exception IllegalActionException If the attribute is not of an
065     *   acceptable class for the container, or if the name contains a period.
066     *  @exception NameDuplicationException If the name coincides with
067     *   an attribute already in the container.
068     */
069    public ModelRepaintController(NamedObj container, String name)
070            throws IllegalActionException, NameDuplicationException {
071
072        super(container, name);
073
074        _repaintOnWrapUp = new Parameter(this, "repaintOnWrapUp");
075        _repaintOnWrapUp.setTypeEquals(BaseType.BOOLEAN);
076        _repaintOnWrapUp.setExpression("true");
077
078        _repaintOnPostFire = new Parameter(this, "repaintOnPostFire");
079        _repaintOnPostFire.setTypeEquals(BaseType.BOOLEAN);
080        _repaintOnPostFire.setExpression("false");
081
082        // The icon.
083        _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-60\" y=\"-10\" "
084                + "width=\"135\" height=\"20\" " + "style=\"fill:#00FFFF\"/>\n"
085                + "<text x=\"-55\" y=\"5\" "
086                + "style=\"font-size:14; font-family:SansSerif; fill:blue\">\n"
087                + "RepaintController\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    /** Clone the controller into the specified workspace. This calls the
099     *  base class and then sets the attribute public members to refer
100     *  to the attributes of the new controller
101     *  @param workspace The workspace for the new controller
102     *  @return A new controller
103     *  @exception CloneNotSupportedException If a derived class contains
104     *  an attribute that cannot be cloned.
105     */
106    @Override
107    public Object clone(Workspace workspace) throws CloneNotSupportedException {
108        ModelRepaintController newObject = (ModelRepaintController) super.clone(
109                workspace);
110        newObject._executable = null;
111        newObject._repaintOnPostFire = (Parameter) newObject
112                .getAttribute("repaintOnPostFire");
113        newObject._repaintOnWrapUp = (Parameter) newObject
114                .getAttribute("repaintOnWrapUp");
115        return newObject;
116    }
117
118    /** Specify the container NamedObj, adding this attribute to the
119     *  list of attributes in the container.  If the container already
120     *  contains an attribute with the same name, then throw an exception
121     *  and do not make any changes.  Similarly, if the container is
122     *  not in the same workspace as this attribute, throw an exception.
123     *  If this attribute is already contained by the NamedObj, do nothing.
124     *  If the attribute already has a container, remove
125     *  this attribute from its attribute list first.  Otherwise, remove
126     *  it from the directory of the workspace, if it is there.
127     *  If the argument is null, then remove it from its container.
128     *  It is not added to the workspace directory, so this could result in
129     *  this object being garbage collected.
130     *  Note that since an Attribute is a NamedObj, it can itself have
131     *  attributes.  However, recursive containment is not allowed, where
132     *  an attribute is an attribute of itself, or indirectly of any attribute
133     *  it contains.  This method is write-synchronized on the
134     *  workspace and increments its version number.
135     *
136     *  @param container The container to attach this attribute to..
137     *  @exception IllegalActionException If this attribute is not of the
138     *   expected class for the container, or it has no name,
139     *   or the attribute and container are not in the same workspace, or
140     *   the proposed container would result in recursive containment.
141     *  @exception NameDuplicationException If the container already has
142     *   an attribute with the name of this attribute.
143     *  @see #getContainer()
144     */
145    @Override
146    public void setContainer(NamedObj container)
147            throws IllegalActionException, NameDuplicationException {
148        if (_executable == null) {
149            // The inner class will be piggybacked as an executable for the container to
150            // execute change request at the appropriate times. These change request will
151            // lead to repaints of the GUI.
152            _executable = new Executable() {
153                @Override
154                public void fire() throws IllegalActionException {
155                }
156
157                @Override
158                public boolean isFireFunctional() {
159                    return true;
160                }
161
162                @Override
163                public boolean isStrict() throws IllegalActionException {
164                    return true;
165                }
166
167                @Override
168                public int iterate(int count) throws IllegalActionException {
169                    return Executable.COMPLETED;
170                }
171
172                @Override
173                public boolean postfire() throws IllegalActionException {
174                    _scheduleRepaint(_repaintOnPostFire);
175                    return true;
176                }
177
178                @Override
179                public boolean prefire() throws IllegalActionException {
180                    return true;
181                }
182
183                @Override
184                public void stop() {
185                }
186
187                @Override
188                public void stopFire() {
189                }
190
191                @Override
192                public void terminate() {
193                }
194
195                @Override
196                public void addInitializable(Initializable initializable) {
197                }
198
199                @Override
200                public void initialize() throws IllegalActionException {
201                }
202
203                @Override
204                public void preinitialize() throws IllegalActionException {
205                }
206
207                @Override
208                public void removeInitializable(Initializable initializable) {
209                }
210
211                @Override
212                public void wrapup() throws IllegalActionException {
213                    _scheduleRepaint(_repaintOnWrapUp);
214                }
215            };
216        }
217
218        // Don't piggy back on previous container anymore.
219        NamedObj previousContainer = getContainer();
220        if (previousContainer instanceof CompositeActor) {
221            ((CompositeActor) previousContainer).removePiggyback(_executable);
222        }
223        super.setContainer(container);
224
225        if (container instanceof CompositeActor) {
226            ((CompositeActor) container).addPiggyback(_executable);
227        }
228    }
229
230    ///////////////////////////////////////////////////////////////////
231    ////                         private methods                   ////
232
233    /** Schedule a repaint in case the value parameter equals True.
234     *  This is done by requesting a ChangeRequest.
235     *  @param parameter The parameter.
236     */
237    private void _scheduleRepaint(Parameter parameter) {
238        if (parameter.getExpression().equals("true")) {
239            // The ChangeRequest has false as third argument to avoid complete
240            // repaints of the model.
241            ChangeRequest request = new ChangeRequest(this,
242                    "SetVariable change request", true) {
243                @Override
244                protected void _execute() throws IllegalActionException {
245                }
246            };
247
248            // To prevent prompting for saving the model, mark this
249            // change as non-persistent.
250            request.setPersistent(false);
251            requestChange(request);
252        }
253    }
254
255    ///////////////////////////////////////////////////////////////////
256    ////                       private parameters                   ////
257
258    // An inner class that will be notified on certain events.
259    // The inner class will be piggybacked as an executable for the container to
260    // execute change request at the appropriate times. These change request will
261    // lead to repaints of the GUI.
262    private Executable _executable;
263
264    // A flag that specifies whether a repaint should happen on wrapup.
265    private Parameter _repaintOnWrapUp;
266
267    // A flag that specifies whether a repaint should happen on post-fire.
268    private Parameter _repaintOnPostFire;
269}