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}