001/* The graph controller for the vergil viewer for finite state machines. 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.modal; 029 030import diva.canvas.Figure; 031import diva.canvas.interactor.SelectionDragger; 032import diva.graph.EdgeController; 033import diva.graph.GraphPane; 034import diva.graph.JGraph; 035import diva.graph.NodeController; 036import ptolemy.actor.gui.Configuration; 037import ptolemy.domains.modal.kernel.State; 038import ptolemy.domains.modal.kernel.StateEvent; 039import ptolemy.domains.modal.modal.ModalController; 040import ptolemy.kernel.Entity; 041import ptolemy.kernel.Port; 042import ptolemy.kernel.util.Attribute; 043import ptolemy.kernel.util.DebugEvent; 044import ptolemy.kernel.util.Locatable; 045import ptolemy.vergil.basic.LocatableNodeController; 046import ptolemy.vergil.basic.NamedObjController; 047import ptolemy.vergil.basic.RunnableGraphController; 048import ptolemy.vergil.kernel.AnimationRenderer; 049import ptolemy.vergil.kernel.AttributeController; 050import ptolemy.vergil.modal.modal.ModalTransitionController; 051 052/////////////////////////////////////////////////////////////////// 053//// FSMViewerGraphController 054 055/** 056 A graph controller for the Ptolemy II finite-state machine viewer. 057 This controller allows states to be moved and context menus to be accessed, 058 but does not provide interaction for adding or removing states or 059 transitions. 060 061 @author Steve Neuendorffer, Contributor: Edward A. Lee 062 @version $Id$ 063 @since Ptolemy II 8.0 064 @Pt.ProposedRating Red (eal) 065 @Pt.AcceptedRating Red (johnr) 066 */ 067public class FSMViewerGraphController extends RunnableGraphController { 068 069 /** Create a new controller with default port, state, and transition 070 * controllers. 071 */ 072 public FSMViewerGraphController() { 073 _createControllers(); 074 075 // The following is a fallback controller used when encountering 076 // instances of Locatable that have no container. Do not create 077 // this in _createControllers() because that is overridden by 078 // derived classes. 079 _locatableController = new LocatableNodeController(this); 080 } 081 082 /////////////////////////////////////////////////////////////////// 083 //// public methods //// 084 085 /** React to an event by highlighting the new state. 086 * @param event The debug event. 087 */ 088 @Override 089 public void event(DebugEvent event) { 090 if (event instanceof StateEvent) { 091 State state = ((StateEvent) event).getState(); 092 093 if (state != null) { 094 Object location = state.getAttribute("_location"); 095 096 if (location != null) { 097 Figure figure = getFigure(location); 098 099 if (figure != null) { 100 if (_animationRenderer == null) { 101 _animationRenderer = new AnimationRenderer(); 102 } 103 104 if (_animated != figure) { 105 // Deselect previous one. 106 if (_animated != null) { 107 _animationRenderer.renderDeselected(_animated); 108 } 109 110 _animationRenderer.renderSelected(figure); 111 _animated = figure; 112 113 long animationDelay = getAnimationDelay(); 114 115 if (animationDelay > 0) { 116 try { 117 Thread.sleep(animationDelay); 118 } catch (InterruptedException ex) { 119 } 120 } 121 } 122 } 123 } 124 } 125 } 126 } 127 128 /** Return the node controller appropriate for the given node. 129 */ 130 @Override 131 public NodeController getNodeController(Object object) { 132 // Defer to the superclass if it can provide a controller. 133 NodeController result = super.getNodeController(object); 134 135 if (result != null) { 136 return result; 137 } 138 139 // Superclass cannot provide a controller. Use defaults. 140 if (object instanceof Locatable) { 141 Object semanticObject = getGraphModel().getSemanticObject(object); 142 143 if (semanticObject instanceof Entity) { 144 return _stateController; 145 } else if (semanticObject instanceof Attribute) { 146 return _attributeController; 147 } else if (semanticObject instanceof Port) { 148 return _portController; 149 } else { 150 return _locatableController; 151 } 152 } 153 154 throw new RuntimeException( 155 "Node with unknown semantic object: " + object); 156 } 157 158 /** Return the edge controller appropriate for the given node. 159 */ 160 @Override 161 public EdgeController getEdgeController(Object edge) { 162 if (((FSMGraphModel) getGraphModel()) 163 .getPtolemyModel() instanceof ModalController) { 164 return _modalTransitionController; 165 } else { 166 return _transitionController; 167 } 168 } 169 170 /** Set the configuration. This is may be used by derived controllers 171 * to open files or URLs. 172 * @param configuration The configuration. 173 */ 174 @Override 175 public void setConfiguration(Configuration configuration) { 176 super.setConfiguration(configuration); 177 _attributeController.setConfiguration(configuration); 178 _stateController.setConfiguration(configuration); 179 _transitionController.setConfiguration(configuration); 180 _modalTransitionController.setConfiguration(configuration); 181 } 182 183 /////////////////////////////////////////////////////////////////// 184 //// protected methods //// 185 186 /** Add hot keys to the actions in the given JGraph. 187 * 188 * @param jgraph The JGraph to which hot keys are to be added. 189 */ 190 @Override 191 protected void _addHotKeys(JGraph jgraph) { 192 super._addHotKeys(jgraph); 193 194 // NOTE: The transition controller's LookInsideAction is designed 195 // to handle both State and Transition. We can't associate more 196 // than one with the hot key, so that one handles both. 197 _transitionController.addHotKeys(jgraph); 198 199 _attributeController.addHotKeys(jgraph); 200 } 201 202 /** Create the controllers for nodes in this graph. 203 * In this base class, controllers with PARTIAL access are created. 204 * This is called by the constructor, so derived classes that 205 * override this must be careful not to reference local variables 206 * defined in the derived classes, because the derived classes 207 * will not have been fully constructed by the time this is called. 208 */ 209 @Override 210 protected void _createControllers() { 211 super._createControllers(); 212 _attributeController = new AttributeController(this, 213 AttributeController.PARTIAL); 214 _stateController = new StateController(this, 215 AttributeController.PARTIAL); 216 _modalTransitionController = new ModalTransitionController(this); 217 _transitionController = new TransitionController(this); 218 } 219 220 /** Initialize all interaction on the graph pane. This method 221 * is called by the setGraphPane() method of the superclass. 222 * This initialization cannot be done in the constructor because 223 * the controller does not yet have a reference to its pane 224 * at that time. 225 */ 226 @Override 227 protected void initializeInteraction() { 228 // NOTE: This method name does not have a leading underscore 229 // because it is a diva method. 230 GraphPane pane = getGraphPane(); 231 232 // Create and set up the selection dragger 233 _selectionDragger = new SelectionDragger(pane); 234 _selectionDragger.addSelectionModel(getSelectionModel()); 235 236 // If the selectionDragger is consuming, then popup menus don't 237 // disappear properly. 238 _selectionDragger.setConsuming(false); 239 240 super.initializeInteraction(); 241 } 242 243 /////////////////////////////////////////////////////////////////// 244 //// protected variables //// 245 246 /** The attribute controller. */ 247 protected NamedObjController _attributeController; 248 249 /** The state controller. */ 250 protected StateController _stateController; 251 252 /** The transition controller. */ 253 protected TransitionController _transitionController; 254 255 /** The modal transition controller. */ 256 protected TransitionController _modalTransitionController; 257 258 /////////////////////////////////////////////////////////////////// 259 //// private variables //// 260 261 /** The default controller, used only for instances of Locatable 262 * that have no container. 263 */ 264 private LocatableNodeController _locatableController; 265 266 // The selection interactor for drag-selecting nodes 267 private SelectionDragger _selectionDragger; 268 269}