001/*
002 * Copyright (c) 2015 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2015-11-02 20:00:34 +0000 (Mon, 02 Nov 2015) $' 
007 * '$Revision: 34198 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029package org.kepler.profiling.gui;
030
031import java.awt.Container;
032import java.awt.event.ActionEvent;
033import java.awt.event.ActionListener;
034
035import javax.swing.JMenuItem;
036import javax.swing.JTabbedPane;
037
038import org.kepler.gui.ModelToFrameManager;
039import org.kepler.gui.TabPane;
040import org.kepler.gui.TabPaneFactory;
041import org.kepler.gui.frame.TabbedKeplerGraphFrame;
042import org.kepler.moml.NamedObjId;
043import org.kepler.provenance.ProvenanceRecorder;
044import org.kepler.provenance.QueryException;
045import org.kepler.provenance.Queryable;
046import org.kepler.provenance.RecordPlayer;
047import org.kepler.provenance.RecordingException;
048
049import ptolemy.actor.gui.Configuration;
050import ptolemy.actor.gui.Effigy;
051import ptolemy.actor.gui.Tableau;
052import ptolemy.actor.gui.TableauFrame;
053import ptolemy.kernel.ComponentEntity;
054import ptolemy.kernel.util.ChangeListener;
055import ptolemy.kernel.util.ChangeRequest;
056import ptolemy.kernel.util.IllegalActionException;
057import ptolemy.kernel.util.NameDuplicationException;
058import ptolemy.kernel.util.NamedObj;
059import ptolemy.util.MessageHandler;
060import ptolemy.vergil.basic.BasicGraphFrame;
061
062/** A panel that displays actor execution information for the workflow
063 *  contained by the parent frame that creates the panel. 
064 * 
065 *  @author Daniel Crawl
066 *  @version $Id: CurrentExecutionPanel.java 34198 2015-11-02 20:00:34Z crawl $
067 * 
068 */
069public class CurrentExecutionPanel extends ExecutionMonitorPanel
070    implements ChangeListener {
071
072    /** Create a new CurrentExecutionPanel with the specified name. */
073    public CurrentExecutionPanel(String name) {
074        super(name);
075    }
076
077    /** A changed occurred in the workflow structure. */
078    @Override
079    public void changeExecuted(ChangeRequest change) {
080        
081        // see if we've already created the recording
082        if(_executionMonitorRecording == null) {
083            // see if the default provenance recorder is present.
084            // if so, create a new recording to receive provenance 
085            // events and stop listening for workflow change events.
086            ProvenanceRecorder recorder = ProvenanceRecorder.getDefaultProvenanceRecorder(_workflow);
087            if(recorder != null) {
088                try {
089                    _executionMonitorRecording = new ExecutionMonitorRecording();
090                    recorder.addPiggyback(_executionMonitorRecording);
091                } catch (RecordingException e) {
092                    MessageHandler.error("Error creating Execution Monitor Recordiner", e);
093                }
094                _workflow.removeChangeListener(this);
095                // receive a notification when provenance turned on/off
096                recorder.addEnabledListener(this);
097            }
098        }
099    }
100
101    /** A change failed in the workflow structure. */
102    @Override
103    public void changeFailed(ChangeRequest change, Exception exception) {
104        // do nothing.
105    };
106
107    /** Initialize the tab. */
108    @Override
109    public void initializeTab() throws Exception {
110        super.initializeTab();
111        // listen for changes in the workflow so that we can get
112        // a reference to the default provenance recorder.
113        _workflow.addChangeListener(this);
114        
115        _statusLabel.setText("Run workflow to see execution information.");
116    }
117    
118    /** A factory to create the tab pane. */
119    public static class Factory extends TabPaneFactory {
120
121        public Factory(NamedObj container, String name)
122                throws IllegalActionException, NameDuplicationException {
123            super(container, name);
124        }
125
126        @Override
127        public TabPane createTabPane(TableauFrame parent) {
128            CurrentExecutionPanel pane = new CurrentExecutionPanel(getName());
129            return pane;
130        }
131    }
132    
133    /** Initialize the pop up menu for the execution table. */
134    @Override
135    protected void _initContextMenu() {
136        super._initContextMenu();
137    
138        // add an item that goes to the actor in the selected row.
139        JMenuItem goToActor = new JMenuItem("Go To Actor");
140        goToActor.addActionListener(new ActionListener() {
141            @Override
142            public void actionPerformed(ActionEvent event) {
143                // get the selected row
144                ActorInfo info = _getSelectedRowInfo();
145                if(info != null) {
146                    
147                    // get the actor in the selected row
148                    ComponentEntity<?> entity = _workflow.getEntity(info.name);
149                    if(entity != null) {
150                                                
151                        // open the frame for the actor and center on the actor
152                        // if there is already a frame opened for this actor, then
153                        // this just centers it on the actor.
154                        BasicGraphFrame.openComposite(_frame, entity);
155                        
156                        // if the actor was already opened in a tabbed frame,
157                        // then we want to set that tab to be selected.
158                        // first, we get the frame.
159                        
160                        NamedObj container = entity.getContainer();
161
162                        Effigy effigy = Configuration.findEffigy(entity.toplevel());
163                        if (effigy == null) {
164                            MessageHandler.error("Failed to find an "
165                                    + "effigy for the toplevel "
166                                    + entity.toplevel().getFullName());
167                            return;
168                        }
169                        
170                        Configuration configuration = (Configuration) effigy.toplevel();
171                        
172                        Tableau tableau = null;
173                        try {
174                            tableau = configuration.openInstance(container);
175                        } catch (Exception e) {
176                            MessageHandler.error("Error opening window for " + container, e);
177                            return;
178                        }
179                        
180                        BasicGraphFrame frame = (BasicGraphFrame) tableau.getFrame();
181                        
182                        // now select the tab containing the container of the actor
183                        // (if the frame is a TabbedKeplerGraphFrame)
184                        if(frame instanceof TabbedKeplerGraphFrame) {
185                            ((TabbedKeplerGraphFrame)frame).setSelectedTab(container);
186                        } else if(frame == null) {
187                            frame = ModelToFrameManager.getInstance().getFrame(container);
188                            if(frame instanceof TabbedKeplerGraphFrame) {
189                                ((TabbedKeplerGraphFrame)frame).setSelectedTab(container);
190                            }
191                        }
192                        
193                        // finally, set canvas tab to be selected.
194                        Container jgraphTabbedContainer = frame.getJGraph().getParent().getParent().getParent();
195                        if(jgraphTabbedContainer instanceof JTabbedPane) {
196                            ((JTabbedPane) jgraphTabbedContainer).setSelectedIndex(0);
197                        }
198                        
199                        if(frame == CurrentExecutionPanel.this._frame) {
200                            
201                            // switch to Workflow tab
202                            JTabbedPane tabbedPane = (JTabbedPane) CurrentExecutionPanel.this.getParent();
203                            tabbedPane.setSelectedIndex(0);
204                        }
205                        
206                    }
207                }
208            }
209        });     
210        _executionTableContextMenu.add(goToActor);        
211
212    }
213    
214    /** Replay the last execution. */
215    @Override
216    protected void _replay() {
217        if(_executionMonitorRecording != null) {
218            try {
219                Queryable query = ProvenanceRecorder.getDefaultQueryable(_workflow);
220                Integer execId = query.getLastExecutionForWorkflow(NamedObjId.getIdFor(_workflow));
221                if(execId == null) {
222                    MessageHandler.error("Could not find execution id for workflow.");
223                    return;
224                }
225                RecordPlayer player = new RecordPlayer(query, _executionMonitorRecording);
226                player.setPlayPortEvents(false);
227                // NOTE: play using the existing workflow. otherwise the workflow is loaded
228                // and parsed from provenance and subsequent executions of the existing
229                // workflow results in the actor names being wrong in the execution panel.
230                player.play(execId, _workflow);
231            } catch (QueryException | RecordingException e) {
232                // TODO Auto-generated catch block
233                e.printStackTrace();
234            }
235        }
236    }
237}