001/* A GUI widget for configuring breakpoints. 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.vergil.debugger; 029 030import javax.swing.BoxLayout; 031 032import ptolemy.actor.Actor; 033import ptolemy.actor.Director; 034import ptolemy.actor.FiringEvent; 035import ptolemy.actor.FiringEvent.FiringEventType; 036import ptolemy.gui.Query; 037import ptolemy.kernel.Entity; 038import ptolemy.kernel.util.ChangeListener; 039import ptolemy.kernel.util.ChangeRequest; 040import ptolemy.kernel.util.InternalErrorException; 041import ptolemy.moml.MoMLChangeRequest; 042import ptolemy.vergil.basic.BasicGraphController; 043 044/////////////////////////////////////////////////////////////////// 045//// BreakpointConfigurer 046 047/** 048 A GUI widget for configuring breakpoints. This class is an editor to 049 configure the breakpoints of an actor in an SDF model. 050 The user can set breakpoints before or after iterate(). 051 052 <p>There is further documentation in the 053 <a href="package-summary.html">package summary</a>. 054 055 @see ptolemy.actor.gui.PortConfigurerDialog 056 057 @author Elaine Cheong, Contributor: Christopher Brooks 058 @version $Id$ 059 @since Ptolemy II 2.1 060 @Pt.ProposedRating Red (celaine) 061 @Pt.AcceptedRating Red (celaine) 062 */ 063@SuppressWarnings("serial") 064public class BreakpointConfigurer extends Query implements ChangeListener { 065 /** Construct a breakpoint configurer for the specified entity. 066 * @param object The entity to configure. 067 * @param graphController The associated graph controller for the object. 068 */ 069 public BreakpointConfigurer(Entity object, 070 BasicGraphController graphController) { 071 super(); 072 073 // FIXME: Perhaps this dialog should have a help button? 074 // The text in $PTII/doc/coding/debugging.htm could be used. 075 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 076 setTextWidth(15); 077 078 // Make sure the object we are trying to set a breakpoint on 079 // is an Actor. 080 if (object instanceof Actor) { 081 _actor = (Actor) object; 082 } else { 083 // This should not be thrown because the context menu 084 // (BreakpointDialogFactory) would not have allowed the 085 // breakpoint option for non-Actor objects. 086 throw new InternalErrorException( 087 "Object selected is not an actor."); 088 } 089 090 // Save the GraphController associated with _actor. 091 _graphController = graphController; 092 093 // Get the director associated with _actor. 094 Director director = _actor.getExecutiveDirector(); 095 096 if (director == null) { 097 // This should not be thrown because the context menu 098 // (BreakpointDialogFactory) would not have allowed the 099 // breakpoint option for actors without a director. 100 throw new InternalErrorException( 101 "No director associated with this actor."); 102 } else { 103 // FIXME: Currently, it seems that this facility 104 // only works in SDF. 105 // Perhaps this constructor should throw IllegalActionException. 106 if (_sdfDirectorClass == null) { 107 try { 108 _sdfDirectorClass = Class 109 .forName("ptolemy.domains.sdf.kernel.SDFDirector"); 110 } catch (Throwable throwable) { 111 throw new InternalErrorException(object, throwable, 112 "The breakpoint facility only works with " 113 + "that are instances of SDFDirector. The " 114 + "SDFDirector was not found."); 115 } 116 } 117 118 if (!_sdfDirectorClass.isInstance(director)) { 119 throw new InternalErrorException(director, null, 120 "The breakpoint facility only works with directors " 121 + "that are instances of SDFDirector. The director " 122 + "of this model is a '" + director + "'."); 123 } 124 125 // See if the director already has a DebugController. 126 DebugController debugController = (DebugController) director 127 .getAttribute(_DEBUGCONTROLLER); 128 129 // See if the DebugController has a DebugProfile for this 130 // actor. Make a new DebugProfile if one does not already 131 // exist. 132 _actorProfile = null; 133 134 if (debugController != null) { 135 _actorProfile = debugController.getDebugProfile(_actor); 136 } 137 138 if (_actorProfile == null) { 139 _actorProfile = new DebugProfile(_graphController); 140 } 141 142 // Generate checkbox entries in dialog box. 143 for (int i = 0; i < _firingEventTypes.length; i++) { 144 if (_actorProfile.isListening(_firingEventTypes[i])) { 145 addCheckBox(_firingEventTypeLabels[i], 146 _firingEventTypeLabels[i], true); 147 } else { 148 addCheckBox(_firingEventTypeLabels[i], 149 _firingEventTypeLabels[i], false); 150 } 151 } 152 } 153 } 154 155 /////////////////////////////////////////////////////////////////// 156 //// public methods //// 157 158 /** Set up and save the new breakpoint configuration for this actor. 159 */ 160 public void apply() { 161 boolean breakpointsSelected = false; 162 163 // Make a new DebugProfile. 164 _actorProfile = new DebugProfile(_graphController); 165 166 for (int i = 0; i < _firingEventTypes.length; i++) { 167 // Configure the DebugProfile with the selected FiringEventTypes. 168 if (getBooleanValue(_firingEventTypeLabels[i])) { 169 _actorProfile.listenForEvent(_firingEventTypes[i]); 170 breakpointsSelected = true; 171 } else { 172 _actorProfile.unlistenForEvent(_firingEventTypes[i]); 173 } 174 } 175 176 // The director should not be null because we already checked 177 // in the constructor. 178 Director director = _actor.getExecutiveDirector(); 179 DebugController debugController = (DebugController) director 180 .getAttribute(_DEBUGCONTROLLER); 181 182 // If some breakpoints were selected 183 if (breakpointsSelected) { 184 if (debugController != null) { 185 // Add this actor to the set of objects being debugged. 186 debugController.putDebugProfile(_actor, _actorProfile); 187 } else { 188 // If the director does not already have a 189 // DebugController, create one. 190 String moml = "<property name=\"" + _DEBUGCONTROLLER 191 + "\" class=\"ptolemy.vergil.debugger.DebugController\"/>"; 192 ChangeRequest request = new MoMLChangeRequest(this, // originator 193 director, // context 194 moml); 195 request.addChangeListener(this); 196 director.requestChange(request); 197 } 198 } else { 199 // If BreakpointConfigurerDialog()._handlClosing() 200 // calls this in appropriately, then debugController might be 201 // null. 202 if (debugController != null) { 203 // Remove profile if there are no longer any 204 // breakpoints selected for this _actor. 205 debugController.removeDebugProfile(_actor); 206 } 207 208 // FIXME: removeDebugListener if no more actors have breakpoints. 209 } 210 } 211 212 /** React to a change request has been successfully executed. 213 * This method is called after a change request 214 * has been executed successfully. 215 * @param change The change that has been executed, or null if 216 * the change was not done via a ChangeRequest. 217 */ 218 @Override 219 public void changeExecuted(ChangeRequest change) { 220 Director director = _actor.getExecutiveDirector(); 221 // The DebugController should not be null since the change 222 // request should have added the DebugController to the 223 // director. 224 DebugController debugController = (DebugController) director 225 .getAttribute(_DEBUGCONTROLLER); 226 227 // Register a new DebugController with the director. 228 director.addDebugListener(debugController); 229 230 // Add this actor to the set of objects being debugged. 231 debugController.putDebugProfile(_actor, _actorProfile); 232 233 director.removeChangeListener(this); 234 } 235 236 /** React to a change request has resulted in an exception. 237 * This method is called after a change request was executed, 238 * but during the execution an exception was thrown. 239 * @param change The change that was attempted or null if 240 * the change was not done via a ChangeRequest. 241 * @param exception The exception that resulted. 242 */ 243 @Override 244 public void changeFailed(ChangeRequest change, Exception exception) { 245 throw new InternalErrorException( 246 "Could not add DebugController to the director"); 247 } 248 249 /////////////////////////////////////////////////////////////////// 250 //// protected variables //// 251 252 /** Firing event type labels. 253 * To add firing events for debugging, you must make changes in 2 254 * places in this file: _firingEventTypeLabels, _firingEventTypes 255 * Labels of FiringEventTypes to show in the dialog box. 256 */ 257 protected static String[] _firingEventTypeLabels = { 258 259 // FIXME: Only BEFORE_ITERATE and AFTER_ITERATE work with SDF 260 //"before prefire", 261 //"after prefire", 262 //"before fire", 263 //"after fire", 264 //"before postfire", 265 //"after postfire", 266 "before iterate", "after iterate" }; 267 268 /** FiringEventTypes that the user can set breakpoints on. */ 269 protected static FiringEventType[] _firingEventTypes = { 270 271 // FIXME: Only BEFORE_ITERATE and AFTER_ITERATE work with SDF 272 //FiringEvent.BEFORE_PREFIRE, 273 //FiringEvent.AFTER_PREFIRE, 274 //FiringEvent.BEFORE_FIRE, 275 //FiringEvent.AFTER_FIRE, 276 //FiringEvent.BEFORE_POSTFIRE, 277 //FiringEvent.AFTER_POSTFIRE, 278 FiringEvent.BEFORE_ITERATE, FiringEvent.AFTER_ITERATE }; 279 280 /////////////////////////////////////////////////////////////////// 281 //// private variables //// 282 // Name of the DebugController to attach to the director. 283 private static String _DEBUGCONTROLLER = "_DebugController"; 284 285 // The object that this configurer configures. 286 private Actor _actor; 287 288 // DebugProfile associated with _actor. 289 private DebugProfile _actorProfile; 290 291 // The GraphController associated with _actor. 292 private BasicGraphController _graphController; 293 294 // The class of ptolemy.domains.sdf.Director 295 private static Class _sdfDirectorClass = null; 296}