001/* Applet that displays a vergil block diagram.
002
003 Copyright (c) 1998-2016 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.vergil;
029
030import java.awt.BorderLayout;
031import java.awt.Dimension;
032import java.net.URL;
033import java.util.Locale;
034
035import diva.graph.GraphModel;
036import diva.graph.GraphPane;
037import diva.graph.JGraph;
038import ptolemy.actor.gui.Configuration;
039import ptolemy.actor.gui.ConfigurationApplication;
040import ptolemy.actor.gui.MoMLApplet;
041import ptolemy.actor.gui.SizeAttribute;
042import ptolemy.domains.modal.kernel.FSMActor;
043import ptolemy.kernel.CompositeEntity;
044import ptolemy.kernel.util.NamedObj;
045import ptolemy.kernel.util.Workspace;
046import ptolemy.vergil.actor.ActorGraphModel;
047import ptolemy.vergil.actor.ActorViewerGraphController;
048import ptolemy.vergil.modal.FSMGraphController;
049import ptolemy.vergil.modal.FSMGraphModel;
050
051///////////////////////////////////////////////////////////////////
052//// MoMLViewerApplet
053
054/**
055 This applet displays a graph view of a specified MoML file.
056 <p>
057 The applet parameters are:
058 <ul>
059 <li>
060 <i>background</i>: The background color, typically given as a hex
061 number of the form "#<i>rrggbb</i>" where <i>rr</i> gives the red
062 component, <i>gg</i> gives the green component, and <i>bb</i> gives
063 the blue component.
064 <li>
065 <i>configuration</i>:
066 The relative pathname to a Ptolemy II xml configuration file.
067 for example, if the configuration applet parameter is set to
068 "ptolemy/configs/full/configuration.xml", then the user will
069 have the full vergil interface, including look inside capability.
070 (<b>Experimental</b>).
071 <li>
072 <i>controls</i>:
073 This gives a comma-separated list
074 of any subset of the words "buttons", "topParameters", and
075 "directorParameters" (case insensitive), or the word "none".
076 If this parameter is not given, then it is equivalent to
077 giving "buttons", and only the control buttons mentioned above
078 will be displayed.  If the parameter is given, and its value is "none",
079 then no controls are placed on the screen.  If the word "topParameters"
080 is included in the comma-separated list, then controls for the
081 top-level parameters of the model are placed on the screen, below
082 the buttons.  If the word "directorParameters" is included,
083 then controls for the director parameters are also included.
084 This parameter is ignored unless <i>includeRunPanel</i> is given as "true".
085 <li>
086 <i>includeRunPanel</i>: An indicator to include a run panel below the
087 schematic.  The value must be "true" or no run panel will be displayed.
088 <li>
089 <i>modelURL</i>: The name of a URI (or URL) containing the
090 MoML file that defines the model.
091 <li>
092 <i>orientation</i>: This can have value "horizontal", "vertical", or
093 "controls_only" (case insensitive).  If it is "vertical", then the
094 controls are placed above the visual elements of the Placeable actors.
095 This is the default.  If it is "horizontal", then the controls
096 are placed to the left of the visual elements.  If it is "controls_only"
097 then no visual elements are placed.
098 </ul>
099
100 @author  Steve Neuendorffer and Edward A. Lee
101 @version $Id$
102 @since Ptolemy II 1.0
103 @Pt.ProposedRating Red (eal)
104 @Pt.AcceptedRating Red (eal)
105 */
106@SuppressWarnings("serial")
107public class MoMLViewerApplet extends MoMLApplet {
108    // FIXME: this is a total hack as a placeholder for a general
109    // implementation going through configurations.
110    // FIXME: Perhaps the context menu
111    // should have a run-model option?
112    ///////////////////////////////////////////////////////////////////
113    ////                         public methods                    ////
114
115    /** Describe the applet parameters.
116     *  @return An array describing the applet parameters.
117     */
118    @Override
119    public String[][] getParameterInfo() {
120        String[][] newinfo = {
121                { "includeRunPanel", "", "Indicator to include run panel" },
122                { "configuration", "", "Ptolemy II configuration" }, };
123        return _concatStringArrays(super.getParameterInfo(), newinfo);
124    }
125
126    /** Override the base class to not start
127     *  execution of the model. This method is called by the
128     *  browser or applet viewer to inform this applet that it should
129     *  start its execution. It is called after the init method
130     *  and each time the applet is revisited in a Web page.
131     */
132    @Override
133    public void start() {
134    }
135
136    ///////////////////////////////////////////////////////////////////
137    ////                         protected methods                 ////
138
139    /** Read the model from the <i>modelURL</i> applet parameter
140     *  and do not filter out any graphical classes.
141     *  @param workspace The workspace in which to create the model.
142     *  @return A model.
143     *  @exception Exception If something goes wrong.
144     */
145    @Override
146    protected NamedObj _createModel(Workspace workspace) throws Exception {
147        // Do not filter out graphical classes.
148        // FIXME: if we have a configuration, then we are parsing
149        // the model twice!!!
150        return _createModel(workspace, false);
151    }
152
153    /** Override the base class to create a schematic view instead of
154     *  a ModelPane.  If the toplevel model created by _createModel()
155     *  is not an instance of CompositeEntity, then do nothing.
156     */
157    @Override
158    protected void _createView() {
159        if (!(_toplevel instanceof CompositeEntity)) {
160            return;
161        }
162
163        // Get the configuration, if any
164        String configurationPath = getParameter("configuration");
165
166        if (configurationPath != null) {
167            try {
168                URL specificationURL = ConfigurationApplication
169                        .specToURL(configurationPath);
170                _configuration = ConfigurationApplication
171                        .readConfiguration(specificationURL);
172                report("Opened '" + specificationURL + "': " + _configuration);
173            } catch (Exception ex) {
174                throw new RuntimeException(
175                        "Failed to open '" + configurationPath + "':", ex);
176            }
177        }
178
179        //        if (_configuration != null) {
180        //            // We have a configuration
181        //            try {
182        //                //URL docBase = getDocumentBase();
183        //                //URL inURL = new URL(docBase, _modelURL);
184        //                //String key = inURL.toExternalForm();
185        //                // Now defer to the model reader.
186        //                //Tableau tableau = _configuration.openModel(inURL, inURL,
187        //                //        key);
188        //                //JFrame frame = new JFrame();
189        //                //tableau.setFrame(frame);
190        //                //getContentPane().add(tableau.getFrame().getContentPane(),
191        //                //        BorderLayout.NORTH);
192        //            } catch (Exception ex) {
193        //                throw new RuntimeException("Failed to open '" + _modelURL
194        //                        + "'.", ex);
195        //            }
196        //        }
197
198        GraphPane pane = null;
199
200        // FIXME: Temporary hack so we can view FSMs properly.
201        // This should be replaced with a proper tableau mechanism.
202        if (_toplevel instanceof FSMActor) {
203            FSMGraphController controller = new FSMGraphController();
204            FSMGraphModel graphModel = new FSMGraphModel((FSMActor) _toplevel);
205
206            // FIXME: To get things like open documentation to work, have
207            // to specify a configuration.  But currently, there isn't one.
208            if (_configuration != null) {
209                controller.setConfiguration(_configuration);
210            }
211
212            pane = new GraphPane(controller, graphModel);
213        } else {
214            // top level is not an FSM actor.
215            ActorViewerGraphController controller = new ActorViewerGraphController();
216
217            // FIXME: To get things like open documentation to work, have
218            // to specify a configuration.  But currently, there isn't one.
219            if (_configuration != null) {
220                controller.setConfiguration(_configuration);
221            }
222
223            GraphModel model = new ActorGraphModel(_toplevel);
224            pane = new GraphPane(controller, model);
225        }
226
227        JGraph modelViewer = new JGraph(pane);
228
229        // Get dimensions from the model, if they are present.
230        // Otherwise, use the same defaults used by vergil.
231        boolean boundsSet = false;
232
233        try {
234            SizeAttribute vergilBounds = (SizeAttribute) _toplevel
235                    .getAttribute("_vergilSize", SizeAttribute.class);
236            if (vergilBounds != null) {
237                boundsSet = vergilBounds.setSize(modelViewer);
238            }
239        } catch (Throwable throwable) {
240            // Ignore and set to default.
241        }
242
243        if (!boundsSet) {
244            // Set default size
245            Dimension size = new Dimension(400, 300);
246            modelViewer.setMinimumSize(size);
247            modelViewer.setPreferredSize(size);
248        }
249
250        // Inherit the background color from the applet parameter.
251        modelViewer.setBackground(getBackground());
252
253        // Do not include a scroll pane, since generally we size the
254        // applet to show the entire model.
255        // JScrollPane scrollPane = new JScrollPane(modelViewer);
256        // getContentPane().add(scrollPane, BorderLayout.NORTH);
257        // scrollPane.setBackground(getBackground());
258        getContentPane().add(modelViewer, BorderLayout.NORTH);
259
260        // Call the superclass here to get a control panel
261        // below the schematic.
262        String panelFlag = getParameter("includeRunPanel");
263
264        if (panelFlag != null && panelFlag.trim()
265                .toLowerCase(Locale.getDefault()).equals("true")) {
266            // NOTE: We could create a separator between the schematic
267            // and the control panel here.
268            super._createView();
269        }
270    }
271
272    ///////////////////////////////////////////////////////////////////
273    ////                         private fields                    ////
274
275    /** The configuration that is read from the configuration applet param. */
276    private Configuration _configuration;
277}