001/* Top-level window containing a Ptolemy II model. 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// FIXME: To do: 028// - Fix printing. 029// - Handle file changes (warn when discarding modified models). 030package ptolemy.actor.gui; 031 032import java.awt.BorderLayout; 033import java.awt.Color; 034 035import javax.swing.JOptionPane; 036 037import ptolemy.actor.CompositeActor; 038import ptolemy.actor.ExecutionListener; 039import ptolemy.actor.Manager; 040import ptolemy.kernel.util.NamedObj; 041import ptolemy.moml.Documentation; 042 043/////////////////////////////////////////////////////////////////// 044//// ModelFrame 045 046/** 047 ModelFrame is a top-level window containing a Ptolemy II model control panel. 048 It contains a ModelPane, and has a menu bar and a status bar for 049 message reporting. This class is intended to be used with 050 composite actors, which are executable models. 051 052 @see ModelPane 053 @author Edward A. Lee 054 @version $Id$ 055 @since Ptolemy II 0.4 056 @Pt.ProposedRating Green (eal) 057 @Pt.AcceptedRating Yellow (janneck) 058 */ 059@SuppressWarnings("serial") 060public class ModelFrame extends PtolemyFrame implements ExecutionListener { 061 // FIXME: Possibly this class could also handle atomic actors. 062 // This might be useful for code generation. 063 064 /** Construct a frame to control the specified Ptolemy II model. 065 * After constructing this, it is necessary to call 066 * setVisible(true) to make the frame appear. This creates an 067 * instance of ModelPane and puts it in a top-level window. This 068 * is typically done by calling show() on the controlling 069 * tableau. 070 * @see ModelPane 071 * @see Tableau#show() 072 * @see ModelPane 073 * @param model The model to put in this frame, or null if none. 074 */ 075 public ModelFrame(CompositeActor model) { 076 this(model, null); 077 } 078 079 /** Construct a frame to control the specified Ptolemy II model. 080 * After constructing this, it is necessary to call 081 * setVisible(true) to make the frame appear. This creates an 082 * instance of ModelPane and puts it in a top-level window. This 083 * is typically done by calling show() on the controlling 084 * tableau. 085 * @see ModelPane 086 * @see Tableau#show() 087 * @param model The model to put in this frame, or null if none. 088 * @param tableau The tableau responsible for this frame, or null if none. 089 */ 090 public ModelFrame(CompositeActor model, Tableau tableau) { 091 this(model, tableau, new ModelPane(model)); 092 } 093 094 /** Construct a frame to control the specified Ptolemy II model. 095 * After constructing this, it is necessary to call 096 * setVisible(true) to make the frame appear. This creates an 097 * instance of ModelPane and puts it in a top-level window. 098 * @see ModelPane 099 * @see Tableau#show() 100 * @param model The model to put in this frame, or null if none. 101 * @param tableau The tableau responsible for this frame, or null if none. 102 * @param pane The model pane to place inside the frame. 103 */ 104 public ModelFrame(CompositeActor model, Tableau tableau, ModelPane pane) { 105 super(model, tableau); 106 107 _pane = pane; 108 getContentPane().add(_pane, BorderLayout.CENTER); 109 110 Manager manager = model.getManager(); 111 112 if (manager != null) { 113 manager.addExecutionListener(this); 114 } 115 116 // Make the go button the default. 117 _pane.setDefaultButton(); 118 119 // FIXME: Need to do something with the progress bar in the status bar. 120 } 121 122 /////////////////////////////////////////////////////////////////// 123 //// public methods //// 124 125 /** Report that an execution error has occurred. This method 126 * is called by the specified manager. 127 * @param manager The manager calling this method. 128 * @param throwable The throwable being reported. 129 */ 130 @Override 131 public void executionError(Manager manager, Throwable throwable) { 132 report(throwable); 133 } 134 135 /** Report that execution of the model has finished. 136 * @param manager The manager calling this method. 137 */ 138 @Override 139 public void executionFinished(Manager manager) { 140 // Display the amount of time and memory used. 141 // See http://bugzilla.ecoinformatics.org/show_bug.cgi?id=5571 142 // There is similar code in ptolemy/vergil/basic/RunnableGraphController.java 143 String statusMessage = manager.getStatusMessage(); 144 if (!statusMessage.isEmpty()) { 145 statusMessage = ": " + statusMessage; 146 } else { 147 statusMessage = "."; 148 } 149 report("execution finished" + statusMessage); 150 } 151 152 /** Report that a manager state has changed. 153 * This method is called by the specified manager. 154 * @param manager The manager calling this method. 155 */ 156 @Override 157 public void managerStateChanged(Manager manager) { 158 Manager.State newState = manager.getState(); 159 160 if (newState != _previousState) { 161 // There is similar code in ptolemy/vergil/basic/RunnableGraphController.java 162 String statusMessage = manager.getStatusMessage(); 163 if (statusMessage.equals(_previousStatusMessage)) { 164 _previousStatusMessage = statusMessage; 165 statusMessage = ""; 166 } else { 167 _previousStatusMessage = statusMessage; 168 } 169 170 if (!statusMessage.isEmpty()) { 171 statusMessage = ": " + statusMessage; 172 } else { 173 statusMessage = "."; 174 } 175 report(manager.getState().getDescription() + statusMessage); 176 177 _previousState = newState; 178 } 179 } 180 181 /** Return the container into which to place placeable objects. 182 * These are objects in a Ptolemy II model that have their own 183 * user interface, such as plotters. 184 * @return A container for graphical displays. 185 */ 186 public ModelPane modelPane() { 187 return _pane; 188 } 189 190 /** Set background color. This overrides the base class to set the 191 * background of the contained ModelPane. 192 * @param background The background color. 193 */ 194 @Override 195 public void setBackground(Color background) { 196 super.setBackground(background); 197 getContentPane().setBackground(background); 198 199 // This seems to be called in a base class constructor, before 200 // this variable has been set. Hence the test against null. 201 if (_pane != null) { 202 _pane.setBackground(background); 203 } 204 } 205 206 /** Set the associated model. This overrides the base class to add 207 * this object as an execution listener to the manager, if there is 208 * one. 209 * @param model The associated model. 210 */ 211 public void setModel(CompositeActor model) { 212 super.setModel(model); 213 214 if (model != null) { 215 if (_pane != null) { 216 _pane.setModel(model); 217 } 218 219 Manager manager = model.getManager(); 220 221 if (manager != null) { 222 manager.addExecutionListener(this); 223 } 224 } 225 } 226 227 /////////////////////////////////////////////////////////////////// 228 //// protected methods //// 229 230 /** Clear the current contents. First, check to see whether 231 * the contents have been modified, and if so, then prompt the user 232 * to save them. A return value of false 233 * indicates that the user has canceled the action. 234 * Then, if the user does not cancel, replace the model with a 235 * new, blank composite actor. 236 * @return False if the user cancels the clear. 237 */ 238 @Override 239 protected boolean _clear() { 240 if (super._clear()) { 241 setModel(new CompositeActor()); 242 return true; 243 } else { 244 return false; 245 } 246 } 247 248 /** Close the window. Override the base class to remove the 249 * execution listener from the manager, and to notify the contained 250 * ModelPane. 251 * @return False if the user cancels on a save query. 252 */ 253 @Override 254 protected boolean _close() { 255 boolean result = super._close(); 256 257 // FIXME: Shouldn't the following only be done if the 258 // above returns true. 259 NamedObj model = getModel(); 260 261 if (model instanceof CompositeActor) { 262 Manager manager = ((CompositeActor) model).getManager(); 263 264 if (manager != null) { 265 manager.removeExecutionListener(this); 266 } 267 } 268 269 if (_pane != null) { 270 _pane.stopRun(); 271 272 // The second argument is supposed to be a button name, but there 273 // is no button that would have triggered this. 274 _pane.windowClosed(this, ""); 275 } 276 277 return result; 278 } 279 280 /** Display more detailed information than given by _about(). 281 * This class displays information contained by Documentation 282 * attributes in the associated model. 283 * @see Documentation 284 */ 285 @Override 286 protected void _help() { 287 String message = "Ptolemy II model."; 288 NamedObj model = getModel(); 289 290 if (model != null) { 291 String tip = Documentation.consolidate(model); 292 293 if (tip != null) { 294 message = "Ptolemy II model:\n" + tip; 295 } 296 } 297 298 JOptionPane.showMessageDialog(this, message, "About " + getTitle(), 299 JOptionPane.INFORMATION_MESSAGE); 300 } 301 302 /////////////////////////////////////////////////////////////////// 303 //// private variables //// 304 // The pane in which the model data is displayed. 305 private ModelPane _pane; 306 307 /** The previous state of the manager, to avoid reporting it if it hasn't 308 * changed. 309 */ 310 private Manager.State _previousState; 311 312 /** The Manager status message from the previous state. 313 */ 314 private String _previousStatusMessage = ""; 315}