001/* Basic applet that constructs a Ptolemy II model from a MoML file.
002
003 Copyright (c) 1998-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.actor.gui;
029
030import java.net.URL;
031
032import ptolemy.actor.CompositeActor;
033import ptolemy.actor.Manager;
034import ptolemy.kernel.ComponentEntity;
035import ptolemy.kernel.CompositeEntity;
036import ptolemy.kernel.attributes.VersionAttribute;
037import ptolemy.kernel.util.IllegalActionException;
038import ptolemy.kernel.util.NamedObj;
039import ptolemy.kernel.util.Workspace;
040import ptolemy.moml.Documentation;
041import ptolemy.moml.MoMLParser;
042import ptolemy.moml.filter.BackwardCompatibility;
043import ptolemy.moml.filter.RemoveGraphicalClasses;
044
045///////////////////////////////////////////////////////////////////
046//// MoMLApplet
047
048/**
049 This is an applet that constructs a Ptolemy II model from a MoML file.
050 "MoML" stands for "Modeling Markup Language." It is an XML schema for
051 constructing Ptolemy II models.
052 <p>
053 This class offers a number of alternatives that control the visual
054 appearance of the applet. By default, the applet places on the screen
055 a set of control buttons that can be used to start, stop, pause, and
056 resume the model.  Below those buttons, it places the visual elements
057 of any actors in the model that implement the Placeable interface,
058 such as plotters or textual output.
059 <p>
060 The applet parameters are:
061 <ul>
062 <li>
063 <i>background</i>: The background color, typically given as a hex
064 number of the form "#<i>rrggbb</i>" where <i>rr</i> gives the red
065 component, <i>gg</i> gives the green component, and <i>bb</i> gives
066 the blue component.
067 <li>
068 <i>controls</i>:
069 This gives a comma-separated list
070 of any subset of the words "buttons", "topParameters", and
071 "directorParameters" (case insensitive), or the word "none".
072 If this parameter is not given, then it is equivalent to
073 giving "buttons", and only the control buttons mentioned above
074 will be displayed.  If the parameter is given, and its value is "none",
075 then no controls are placed on the screen.  If the word "topParameters"
076 is included in the comma-separated list, then controls for the
077 top-level parameters of the model are placed on the screen, below
078 the buttons.  If the word "directorParameters" is included,
079 then controls for the director parameters are also included.
080 <li>
081 <i>modelURL</i>: The name of a URI (or URL) containing the
082 MoML file that defines the model.
083 <li>
084 <i>orientation</i>: This can have value "horizontal", "vertical", or
085 "controls_only" (case insensitive).  If it is "vertical", then the
086 controls are placed above the visual elements of the Placeable actors.
087 This is the default.  If it is "horizontal", then the controls
088 are placed to the left of the visual elements.  If it is "controls_only"
089 then no visual elements are placed.
090 </ul>
091 <p>
092 To create a model in a different way, say without a <i>modelClass</i>
093 applet parameter, you may extend this class and override the
094 protected method _createModel().  If you wish to alter the way
095 that the model is represented on the screen, you can extend this
096 class an override the _createView() method.  The rendition in this class
097 is an instance of ModelPane.
098
099 @author  Edward A. Lee, Christopher Hylands
100 @version $Id$
101 @since Ptolemy II 0.4
102 @Pt.ProposedRating Yellow (eal)
103 @Pt.AcceptedRating Red (eal)
104 */
105@SuppressWarnings("serial")
106public class MoMLApplet extends PtolemyApplet {
107    ///////////////////////////////////////////////////////////////////
108    ////                         public methods                    ////
109
110    /** Return applet information. If the top-level model element
111     *  contains a <i>doc</i> element, then the contents of that element
112     *  is included in the applet information.
113     *  @return A string giving information about the applet.
114     */
115    @Override
116    public String getAppletInfo() {
117        // Include the release and build number to aid in user support.
118        String version = "Ptolemy II " + VersionAttribute.CURRENT_VERSION;
119        String build = "\n(Build: $Id$)";
120
121        if (_toplevel != null) {
122            String tip = Documentation.consolidate(_toplevel);
123
124            if (tip != null) {
125                return version + " model given in MoML:\n" + tip + build;
126            } else {
127                return version + " model given in MoML." + build;
128            }
129        }
130
131        return "MoML applet for " + version
132                + "\nPtolemy II comes from UC Berkeley, Department of EECS.\n"
133                + "See http://ptolemy.eecs.berkeley.edu/ptolemyII" + build;
134    }
135
136    /** Describe the applet parameters.
137     *  @return An array describing the applet parameters.
138     */
139    @Override
140    public String[][] getParameterInfo() {
141        String[][] newInfo = { { "modelURL", "", "URL for the MoML file" }, };
142        return _concatStringArrays(super.getParameterInfo(), newInfo);
143    }
144
145    ///////////////////////////////////////////////////////////////////
146    ////                         protected methods                 ////
147
148    /** Read the model from the <i>modelURL</i> applet parameter
149     *  and filter out any graphical classes that might require us
150     *  to have diva.jar in the classpath.
151     *  @param workspace The workspace in which to create the model.
152     *  @return A model.
153     *  @exception Exception If something goes wrong.
154     */
155    @Override
156    protected NamedObj _createModel(Workspace workspace) throws Exception {
157        // Filter out graphical classes.
158        return _createModel(workspace, true);
159    }
160
161    /** Read the model from the <i>modelURL</i> applet parameter.
162     *  @param workspace The workspace in which to create the model.
163     *  @param filterGraphicalClasses  If true, then filter out graphical
164     *  classes that might require diva.jar to be in the classpath
165     *  @return A model.
166     *  @exception Exception If something goes wrong.
167     */
168    protected NamedObj _createModel(Workspace workspace,
169            boolean filterGraphicalClasses) throws Exception {
170        // ptolemy.vergil.MoMLViewerApplet() calls this with
171        // filterGraphicalClasses set to false.
172        _modelURL = _readModelURLParameter();
173
174        MoMLParser parser = new MoMLParser();
175
176        // FIXME: if we call _createModel twice, then we will add
177        // this filter twice.  We reset the filter list here,
178        // though we will lose any other filters.
179        MoMLParser.setMoMLFilters(null);
180
181        MoMLParser.setMoMLFilters(BackwardCompatibility.allFilters());
182
183        RemoveGraphicalClasses removeNonAppletClasses = new RemoveGraphicalClasses();
184        // If filterGraphicalClasses is true, then we filter out
185        // graphical classes so that we do not require diva.jar.  If
186        // it is false, then we clear the filter.  In both cases we
187        // add some classes that are always filtered.
188        if (!filterGraphicalClasses) {
189            RemoveGraphicalClasses.clear();
190        }
191
192        // Exclude the code generator
193        removeNonAppletClasses.put(
194                "ptolemy.codegen.kernel.StaticSchedulingCodeGenerator", null);
195        removeNonAppletClasses.put(
196                "ptolemy.vergil.kernel.attributes.DocumentationAttribute",
197                null);
198        MoMLParser.addMoMLFilter(removeNonAppletClasses);
199
200        URL docBase = getDocumentBase();
201        URL xmlFile = new URL(docBase, _modelURL);
202        _manager = null;
203
204        NamedObj toplevel = parser.parse(docBase, xmlFile);
205        _workspace = toplevel.workspace();
206
207        if (_fragment != null && !_fragment.trim().equals("")) {
208            // A fragment was specified, so we should look inside.
209            ComponentEntity inside = null;
210
211            if (toplevel instanceof CompositeEntity) {
212                inside = ((CompositeEntity) toplevel).getEntity(_fragment);
213            }
214
215            if (inside == null) {
216                throw new IllegalActionException(toplevel,
217                        "No such contained entity: " + _fragment);
218            }
219
220            toplevel = inside;
221        } else if (toplevel instanceof CompositeActor) {
222            CompositeActor result = (CompositeActor) toplevel;
223            _manager = result.getManager();
224
225            if (_manager == null) {
226                _manager = new Manager(_workspace, "manager");
227                result.setManager(_manager);
228            }
229
230            _manager.addExecutionListener(this);
231        }
232
233        return toplevel;
234    }
235
236    /** Read the modelURL applet parameter.
237     *  If the modelURL applet parameter does not exist, then
238     *  read the model applet parameter.  As a side effect,
239     *  the _fragment field is set with any text after a "#".
240     *  @exception Exception Thrown if there is no modelURL or model
241     *  applet parameter.
242     *  @return the value of the modelURL or model parameter.
243     */
244    protected String _readModelURLParameter() throws Exception {
245        _modelURL = getParameter("modelURL");
246
247        if (_modelURL == null) {
248            // For backward compatibility, try name "model".
249            _modelURL = getParameter("model");
250
251            if (_modelURL == null) {
252                throw new Exception("Applet does not not specify a modelURL.");
253            }
254        }
255
256        // NOTE: Regrettably, Java's URL class is too dumb
257        // to handle a fragment part of a URL.  Thus, if
258        // there is one, we have to remove it.  Note that
259        // Java calls this a "fragment", a "ref", and
260        // and "reference", all in different parts of the
261        // docs.
262        int sharp = _modelURL.indexOf("#");
263
264        if (sharp > 0) {
265            _fragment = _modelURL.substring(sharp + 1);
266            _modelURL = _modelURL.substring(0, sharp);
267        }
268
269        return _modelURL;
270    }
271
272    ///////////////////////////////////////////////////////////////////
273    ////                         protected fields                  ////
274
275    /** The fragment of the modelURL, if any.  This field is set after
276     *  _readMoMLAppletParameter() is called.
277     */
278    protected String _fragment = "";
279
280    /** The modelURL.  This field is set after
281     * _readMoMLAppletParameter() is called.
282     */
283    protected String _modelURL = "";
284}