001/* This actor opens a window to display the specified model and applies its inputs to the model. 002 003 @Copyright (c) 2007-2016 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.awt.Container; 031import java.awt.Dimension; 032import java.net.URL; 033import java.util.List; 034 035import diva.graph.GraphPane; 036import diva.graph.JGraph; 037import ptolemy.actor.TypedIOPort; 038import ptolemy.actor.gui.AbstractPlaceableActor; 039import ptolemy.actor.gui.Configuration; 040import ptolemy.actor.gui.Effigy; 041import ptolemy.actor.gui.PtolemyEffigy; 042import ptolemy.actor.gui.SizeAttribute; 043import ptolemy.actor.gui.Tableau; 044import ptolemy.actor.gui.TableauFrame; 045import ptolemy.data.StringToken; 046import ptolemy.data.expr.FileParameter; 047import ptolemy.data.type.BaseType; 048import ptolemy.kernel.CompositeEntity; 049import ptolemy.kernel.util.Attribute; 050import ptolemy.kernel.util.ChangeListener; 051import ptolemy.kernel.util.ChangeRequest; 052import ptolemy.kernel.util.IllegalActionException; 053import ptolemy.kernel.util.InternalErrorException; 054import ptolemy.kernel.util.NameDuplicationException; 055import ptolemy.kernel.util.NamedObj; 056import ptolemy.kernel.util.Workspace; 057import ptolemy.moml.MoMLChangeRequest; 058import ptolemy.moml.MoMLParser; 059import ptolemy.moml.ParserAttribute; 060import ptolemy.vergil.actor.ActorEditorGraphController; 061import ptolemy.vergil.actor.ActorGraphModel; 062 063/////////////////////////////////////////////////////////////////// 064//// ModelDisplay 065 066/** 067 This actor opens a window to display the specified model. 068 If inputs are provided, they are expected to be MoML strings 069 that are to be applied to the model. This can be used, for 070 example, to create animations. 071 072 @author Edward A. Lee, Elaine Cheong 073 @version $Id$ 074 @since Ptolemy II 8.0 075 @Pt.ProposedRating Yellow (eal) 076 @Pt.AcceptedRating Red (cxh) 077 */ 078public class ModelDisplay extends AbstractPlaceableActor 079 implements ChangeListener { 080 081 /** Construct an actor with the specified container and name. 082 * @param container The container. 083 * @param name The name of this actor. 084 * @exception IllegalActionException If the entity cannot be contained 085 * by the proposed container. 086 * @exception NameDuplicationException If the container already has an 087 * actor with this name. 088 */ 089 public ModelDisplay(CompositeEntity container, String name) 090 throws IllegalActionException, NameDuplicationException { 091 super(container, name); 092 modelURL = new FileParameter(this, "modelURL"); 093 input = new TypedIOPort(this, "input", true, false); 094 input.setTypeEquals(BaseType.STRING); 095 } 096 097 /////////////////////////////////////////////////////////////////// 098 //// ports and parameters //// 099 100 /** The file or URL from which to read the starting point model. 101 * The model is read when this parameter is set or changed. 102 */ 103 public FileParameter modelURL; 104 105 /** The input port through which to provide MoML to modify the model. 106 * This has type string. 107 */ 108 public TypedIOPort input; 109 110 /////////////////////////////////////////////////////////////////// 111 //// public methods //// 112 113 /** React to a change in an attribute. If the attribute is 114 * modelURL, then read the specified URL and parse it to create 115 * the entity to display. 116 * @param attribute The attribute that changed. 117 * @exception IllegalActionException If the change is not acceptable 118 * to this container (not thrown in this base class). 119 */ 120 @Override 121 public void attributeChanged(Attribute attribute) 122 throws IllegalActionException { 123 if (attribute == modelURL) { 124 URL url = modelURL.asURL(); 125 if (url != null) { 126 MoMLParser parser = new MoMLParser(); 127 try { 128 _entity = parser.parse(null, url); 129 ParserAttribute parserAttribute = new ParserAttribute( 130 _entity, "_parser"); 131 parserAttribute.setParser(parser); 132 } catch (Exception ex) { 133 throw new IllegalActionException(this, ex, 134 "Failed to read model from: " + url); 135 } 136 } else { 137 // No URL given, so we should create a blank entity. 138 _entity = _createBlankEntity(); 139 } 140 // Make sure there is no display of the old entity. 141 place(null); 142 } else { 143 super.attributeChanged(attribute); 144 } 145 } 146 147 /** Do nothing. 148 * @param change The change that succeeded. 149 */ 150 @Override 151 public void changeExecuted(ChangeRequest change) { 152 } 153 154 /** Stop executing the model. 155 * @param change The change. 156 * @param exception The exception. 157 */ 158 @Override 159 public void changeFailed(ChangeRequest change, Exception exception) { 160 stop(); 161 } 162 163 /** Read the input, if there is any, and issue a change 164 * request to apply the MoML in the input to the displayed model. 165 * @exception IllegalActionException If there is an error reading 166 * the input. 167 */ 168 @Override 169 public void fire() throws IllegalActionException { 170 super.fire(); 171 if (input.isOutsideConnected() && input.hasToken(0)) { 172 String moml = ((StringToken) input.get(0)).stringValue(); 173 MoMLChangeRequest request = new MoMLChangeRequest(this, _entity, 174 moml); 175 request.addChangeListener(this); 176 _entity.requestChange(request); 177 } 178 } 179 180 /** Clone the actor into the specified workspace. 181 * @param workspace The workspace for the new object. 182 * @return A new actor. 183 * @exception CloneNotSupportedException If a derived class has an 184 * attribute that cannot be cloned. 185 */ 186 @Override 187 public Object clone(Workspace workspace) throws CloneNotSupportedException { 188 ModelDisplay newObject = (ModelDisplay) super.clone(workspace); 189 newObject._entity = _createBlankEntity(); 190 return newObject; 191 } 192 193 /** If the model is not yet displayed, then display it in its 194 * own window. 195 * @exception IllegalActionException If there is an constructing 196 * the display. 197 */ 198 @Override 199 public void initialize() throws IllegalActionException { 200 super.initialize(); 201 202 // If we have no entity at this point, then create a simple 203 // top-level entity into which we can put attributes. 204 if (_entity == null) { 205 _entity = _createBlankEntity(); 206 } 207 208 // If there is no graph display yet, then create a 209 // standalone window in which to display the model. 210 if (_graph == null) { 211 Effigy containerEffigy = Configuration.findEffigy(toplevel()); 212 try { 213 _effigy = new PtolemyEffigy(containerEffigy, 214 "ModelDisplay Effigy"); 215 _effigy.setModel(_entity); 216 _tableau = new Tableau(_effigy, "tableau"); 217 } catch (NameDuplicationException e) { 218 throw new IllegalActionException(this, e, 219 "Failed to create tableau."); 220 } 221 _frame = new TableauFrame(_tableau); 222 setFrame(_frame); 223 _tableau.setFrame(_frame); 224 place(_frame.getContentPane()); 225 _frame.pack(); 226 } 227 if (_frame != null) { 228 ((TableauFrame) _frame).show(); 229 _frame.toFront(); 230 } 231 } 232 233 /** Place the display in the specified container. 234 * @param container The container, or null to remove it from any 235 * existing container. 236 */ 237 @Override 238 public void place(Container container) { 239 if (container == null) { 240 if (_frame != null) { 241 _frame.dispose(); 242 } 243 _frame = null; 244 if (_tableau != null) { 245 try { 246 _tableau.setContainer(null); 247 _effigy.setContainer(null); 248 } catch (Exception e) { 249 throw new InternalErrorException(e); 250 } 251 } 252 _tableau = null; 253 _graph = null; 254 } else { 255 ActorEditorGraphController controller = new ActorEditorGraphController(); 256 // _entity might be null, in which case we have to make an empty model. 257 if (_entity == null) { 258 _entity = _createBlankEntity(); 259 } 260 261 ActorGraphModel graphModel = new ActorGraphModel(_entity); 262 GraphPane graphPane = new GraphPane(controller, graphModel); 263 _graph = new JGraph(graphPane); 264 265 // If the model has a recorded size, use it. 266 List size = _entity.attributeList(SizeAttribute.class); 267 if (size.size() > 0) { 268 ((SizeAttribute) size.get(0)).setSize(_graph); 269 } else { 270 _graph.setMinimumSize(new Dimension(200, 200)); 271 _graph.setMaximumSize(new Dimension(200, 200)); 272 _graph.setPreferredSize(new Dimension(200, 200)); 273 _graph.setSize(200, 200); 274 } 275 // _graph.setBackground(Color.white); 276 277 container.add(_graph); 278 } 279 } 280 281 /////////////////////////////////////////////////////////////////// 282 //// private methods //// 283 284 /** Create a blank entity associated with this display. 285 */ 286 private static NamedObj _createBlankEntity() { 287 String moml = "<entity name=\"top\" class=\"ptolemy.kernel.CompositeEntity\"/>"; 288 NamedObj entity = null; 289 MoMLParser parser = new MoMLParser(); 290 try { 291 entity = parser.parse(null, moml); 292 ParserAttribute parserAttribute = new ParserAttribute(entity, 293 "_parser"); 294 parserAttribute.setParser(parser); 295 } catch (Exception ex) { 296 throw new InternalErrorException(ex); 297 } 298 return entity; 299 } 300 301 /////////////////////////////////////////////////////////////////// 302 //// private variables //// 303 304 /** The effigy representing the model. */ 305 private PtolemyEffigy _effigy; 306 307 /** The top-level entity read from the file or URL. */ 308 private NamedObj _entity; 309 310 /** The graph display pane. */ 311 private JGraph _graph; 312 313 /** The tableau, if the model is displayed in its own window. */ 314 private Tableau _tableau; 315}