blob: 81c515fd46b9a6fe2e0c74df978e9edc21361c04 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2013 University of Utah School of Computing
* 50 S Central Campus Dr. 3190 Salt Lake City, UT 84112
* http://www.cs.utah.edu/formal_verification/
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Alan Humphrey - Initial API and implementation
* Christopher Derrick - Initial API and implementation
* Prof. Ganesh Gopalakrishnan - Project Advisor
*******************************************************************************/
package org.eclipse.ptp.internal.gem.views;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.ptp.internal.gem.GemPlugin;
import org.eclipse.ptp.internal.gem.messages.Messages;
import org.eclipse.ptp.internal.gem.preferences.PreferenceConstants;
import org.eclipse.ptp.internal.gem.util.Envelope;
import org.eclipse.ptp.internal.gem.util.GemUtilities;
import org.eclipse.ptp.internal.gem.util.InternalIssueOrderSorter;
import org.eclipse.ptp.internal.gem.util.ListElement;
import org.eclipse.ptp.internal.gem.util.ProgramOrderSorter;
import org.eclipse.ptp.internal.gem.util.Transitions;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.ViewPart;
/**
* The GEM Analyzer View.
*/
public class GemAnalyzer extends ViewPart {
// Listens for double-clicks and jumps to that line of code in the editor
private class DoubleClickListener implements IDoubleClickListener {
public void doubleClick(DoubleClickEvent event) {
final ISelection selection = event.getSelection();
final StructuredSelection structure = (StructuredSelection) selection;
final ListElement element = (ListElement) structure.getFirstElement();
if (element != null) {
final IFile sourceFile = element.getFile();
final int lineNumber = element.getLineNumber();
openEditor(lineNumber, sourceFile);
}
}
}
// The ID for this view
public static final String ID = "org.eclipse.ptp.gem.views.GemAnalyzer"; //$NON-NLS-1$
// Data structures and more complex members
private Transitions transitions;
private LinkedList<Shell> activeShells;
// Container objects and viewers
private Composite parent;
private ListViewer leftViewer;
private ListViewer rightViewer;
private Action getHelp;
private Action terminateButton;
// Simple members
private int numRanks;
private int lockedRank;
private IFile currLeftFile;
private IFile currRightFile;
// SWT Buttons
private Button firstTransitionButton;
private Button previousTransitionButton;
private Button nextTransitionButton;
private Button lastTransitionButton;
private Button firstInterleavingButton;
private Button previousInterleavingButton;
private Button nextInterleavingButton;
private Button lastInterleavingButton;
private Button deadlockInterleavingButton;
private Button internalIssueOrderButton;
private Button programOrderButton;
private Button launchHpvButton;
private Button browseCallsButton;
private Button runGemButton;
private Combo lockRanksComboList;
private Combo setNumProcsComboList;
// Groups that need to be accessed multiple times
private Group interleavingsGroup;
private Group transitionsGroup;
private Group stepOrderGroup;
// SWT Labels
private Label errorMessageLabel;
private Label leftCodeWindowLabel;
private Label rightCodeWindowLabel;
private CLabel leftCodeWindowExplenationLabel;
private CLabel rightCodeWindowExplenationLabel;
// Used for the transition label
private int transitionLabelIndex;
private int transitionLabelCount;
// Things for highlighting the appropriate line in the code windows
private int leftIndex;
private int rightIndex;
private int previousLeftIndex;
// Listeners for the code viewers
private SelectionListener singleListener;
private DoubleClickListener doubleListener;
// The active file resource needed for various operations
private IFile activeFile;
// Threads
private Thread analyzerUpdateThread;
private Thread clearAnalyzerThread;
private Thread disableTerminateButtonThread;
// Misc
private int leftLines;
private int rightLines;
private boolean aborted;
/**
* Constructor.
*
* @param none
*/
public GemAnalyzer() {
this.lockedRank = -1;
this.aborted = false;
}
/**
* Brings this ViewPart to the front and gives it focus.
*
* @param none
* @return none
*/
public void activate() {
final Thread activationThread = new Thread() {
@Override
public void run() {
final IWorkbench wb = PlatformUI.getWorkbench();
final IWorkbenchWindow window = wb.getActiveWorkbenchWindow();
final IWorkbenchPage page = window.getActivePage();
if (page != null) {
page.activate(GemAnalyzer.this);
}
}
};
// We need to switch to the thread that is allowed to change the UI
Display.getDefault().syncExec(activationThread);
}
/**
* Runs a thread that clears the Analyzer view.
*
* @param none
* @return void
*/
public void clear() {
Display.getDefault().syncExec(this.clearAnalyzerThread);
this.aborted = false;
}
/*
* Calls finer grained methods, populating the view action bar.
*/
private void contributeToActionBars() {
final IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
/*
* Helper method called by createPartControl.
*/
private void createCodeWindowsGroup(Composite parent) {
// Get images for buttons from image cache
final Image sourceCallImage = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/source-call.gif")); //$NON-NLS-1$
final Image matchCallImage = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/match-call.gif")); //$NON-NLS-1$
// Create the layout for the Analyzer windows and call info labels
final Group codeWindowsGroup = new Group(parent, SWT.NONE | SWT.SHADOW_IN);
codeWindowsGroup.setText(Messages.GemAnalyzer_0);
final GridLayout codeWindowsLayout = new GridLayout();
codeWindowsLayout.numColumns = 2;
codeWindowsLayout.marginHeight = 10;
codeWindowsLayout.marginWidth = 10;
codeWindowsLayout.horizontalSpacing = 15;
codeWindowsGroup.setLayout(codeWindowsLayout);
codeWindowsGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
// Create code window labels and their respective layouts, etc.
final String newline = System.getProperty("line.separator"); //$NON-NLS-1$
this.leftCodeWindowLabel = new Label(codeWindowsGroup, SWT.WRAP);
this.leftCodeWindowLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
final Font leftCodeWindowLabelFont = setFontSize(this.leftCodeWindowLabel.getFont(), 9);
this.leftCodeWindowLabel.setFont(leftCodeWindowLabelFont);
this.leftCodeWindowLabel.setText(newline);
this.rightCodeWindowLabel = new Label(codeWindowsGroup, SWT.WRAP);
this.rightCodeWindowLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
final Font rightCodeWindowLabelFont = setFontSize(this.rightCodeWindowLabel.getFont(), 9);
this.rightCodeWindowLabel.setFont(rightCodeWindowLabelFont);
this.rightCodeWindowLabel.setText(newline);
// The short explanations of each of the code windows
this.leftCodeWindowExplenationLabel = new CLabel(codeWindowsGroup, SWT.WRAP | SWT.NULL);
this.rightCodeWindowExplenationLabel = new CLabel(codeWindowsGroup, SWT.WRAP | SWT.NULL);
this.leftCodeWindowExplenationLabel.setImage(sourceCallImage);
this.rightCodeWindowExplenationLabel.setImage(matchCallImage);
this.leftCodeWindowExplenationLabel.setText(Messages.GemAnalyzer_1);
this.rightCodeWindowExplenationLabel.setText(Messages.GemAnalyzer_2);
// Create the Analyzer list viewers
this.leftViewer = new ListViewer(codeWindowsGroup, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
this.rightViewer = new ListViewer(codeWindowsGroup, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
final Font leftViewerFont = setFontSize(this.leftViewer.getControl().getFont(), 8);
final Font rightViewerFont = setFontSize(this.rightViewer.getControl().getFont(), 8);
this.leftViewer.getControl().setFont(leftViewerFont);
this.rightViewer.getControl().setFont(rightViewerFont);
this.leftViewer.getList().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
this.rightViewer.getList().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
/*
* Create two listeners for these viewers. SelectionListener is to
* prevent user from changing the selected line. DoubleListener maps
* selected line to the editor view
*/
this.singleListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
final org.eclipse.swt.widgets.List list = (org.eclipse.swt.widgets.List) e.getSource();
final String entry = list.getItem(0).toString();
// Determine if collective call clicked in the Right Viewer
if (!entry.contains(Messages.GemAnalyzer_3) || !entry.contains(Messages.GemAnalyzer_4)) {
updateSelectedLine(false);
}
}
};
// SelectionListener prevents user from changing selected viewer line
this.doubleListener = new DoubleClickListener();
this.leftViewer.getList().addSelectionListener(this.singleListener);
this.rightViewer.getList().addSelectionListener(this.singleListener);
this.leftViewer.addDoubleClickListener(this.doubleListener);
this.rightViewer.addDoubleClickListener(this.doubleListener);
}
/*
* Helper method called by createPartControl.
*/
private void createInterleavingsGroup(Composite parent) {
// Get images for buttons from image cache
final Image firstItemImage = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/first-item.gif")); //$NON-NLS-1$
final Image lastItemImage = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/last-item.gif")); //$NON-NLS-1$
final Image prevItemImage = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/prev-item.gif")); //$NON-NLS-1$
final Image nextItemImage = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/next-item.gif")); //$NON-NLS-1$
final Image deadlockImage = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/deadlock.gif")); //$NON-NLS-1$
// Group and FormLayout data for interleaving buttons and labels
this.interleavingsGroup = new Group(parent, SWT.SHADOW_IN);
this.interleavingsGroup.setText(Messages.GemAnalyzer_5);
this.interleavingsGroup.setToolTipText(Messages.GemAnalyzer_6);
final FormData interleavingsFormData = new FormData();
interleavingsFormData.bottom = new FormAttachment(100, -5);
interleavingsFormData.left = new FormAttachment(44, 0);
this.interleavingsGroup.setLayoutData(interleavingsFormData);
this.interleavingsGroup.setLayout(new FormLayout());
// First interleaving button
this.firstInterleavingButton = new Button(this.interleavingsGroup, SWT.PUSH);
this.firstInterleavingButton.setImage(firstItemImage);
this.firstInterleavingButton.setToolTipText(Messages.GemAnalyzer_7);
this.firstInterleavingButton.setEnabled(false);
final FormData ifirstFormData = new FormData();
ifirstFormData.left = new FormAttachment(0, 5);
ifirstFormData.bottom = new FormAttachment(100, -5);
this.firstInterleavingButton.setLayoutData(ifirstFormData);
// Previous interleaving button
this.previousInterleavingButton = new Button(this.interleavingsGroup, SWT.PUSH);
this.previousInterleavingButton.setImage(prevItemImage);
this.previousInterleavingButton.setToolTipText(Messages.GemAnalyzer_8);
this.previousInterleavingButton.setEnabled(false);
final FormData iprevFormData = new FormData();
iprevFormData.left = new FormAttachment(this.firstInterleavingButton, 3);
iprevFormData.bottom = new FormAttachment(100, -5);
this.previousInterleavingButton.setLayoutData(iprevFormData);
// Next interleaving button
this.nextInterleavingButton = new Button(this.interleavingsGroup, SWT.PUSH);
this.nextInterleavingButton.setImage(nextItemImage);
this.nextInterleavingButton.setToolTipText(Messages.GemAnalyzer_9);
this.nextInterleavingButton.setEnabled(false);
final FormData inextFormData = new FormData();
inextFormData.left = new FormAttachment(this.previousInterleavingButton, 3);
inextFormData.bottom = new FormAttachment(100, -5);
this.nextInterleavingButton.setLayoutData(inextFormData);
// Last interleaving button
this.lastInterleavingButton = new Button(this.interleavingsGroup, SWT.PUSH);
this.lastInterleavingButton.setImage(lastItemImage);
this.lastInterleavingButton.setToolTipText(Messages.GemAnalyzer_10);
this.lastInterleavingButton.setEnabled(false);
final FormData ilastFormData = new FormData();
ilastFormData.left = new FormAttachment(this.nextInterleavingButton, 3);
ilastFormData.bottom = new FormAttachment(100, -5);
this.lastInterleavingButton.setLayoutData(ilastFormData);
// Deadlock interleaving button
this.deadlockInterleavingButton = new Button(this.interleavingsGroup, SWT.PUSH);
this.deadlockInterleavingButton.setImage(deadlockImage);
this.deadlockInterleavingButton.setToolTipText(Messages.GemAnalyzer_11);
this.deadlockInterleavingButton.setEnabled(false);
final FormData deadlockButtonFormData = new FormData();
deadlockButtonFormData.left = new FormAttachment(this.lastInterleavingButton, 3);
deadlockButtonFormData.bottom = new FormAttachment(100, -5);
deadlockButtonFormData.right = new FormAttachment(100, -5);
this.deadlockInterleavingButton.setLayoutData(deadlockButtonFormData);
}
/**
* Callback that allows us to create the viewer and initialize it.
*
* @param parent
* The parent Composite for this View.
* @return void
*/
@Override
public void createPartControl(Composite parent) {
this.parent = parent;
// Create layout for the parent Composite
final GridLayout parentLayout = new GridLayout();
parentLayout.numColumns = 1;
parentLayout.marginHeight = 10;
parentLayout.marginWidth = 10;
parent.setLayout(parentLayout);
// Create container for transition and interleaving button groups
final Composite runtimeComposite = new Composite(parent, SWT.NULL);
runtimeComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
runtimeComposite.setLayout(new FormLayout());
final Composite buttonGroupsComposite = new Composite(parent, SWT.NULL);
buttonGroupsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
buttonGroupsComposite.setLayout(new FormLayout());
// Create groups and selection listeners
createRuntimeGroup(runtimeComposite);
createTransitionsGroup(buttonGroupsComposite);
createInterleavingsGroup(buttonGroupsComposite);
createStepOrderGroup(buttonGroupsComposite);
createCodeWindowsGroup(parent);
createSelectionListeners();
// create actions & connect to buttons, context menus and pull-downs
makeActions();
hookContextMenu();
contributeToActionBars();
}
/*
* Helper method called by createPartControl.
*/
private void createRuntimeGroup(Composite parent) {
// Get images for buttons from image cache
final Image noErrorImage = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/no-error.gif")); //$NON-NLS-1$
final Image hbvImage = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/hbv-trident.gif")); //$NON-NLS-1$
final Image trident = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/trident.gif")); //$NON-NLS-1$
// Runtime information group
final Group runtimeInfoGroup = new Group(parent, SWT.SHADOW_IN);
runtimeInfoGroup.setText(Messages.GemAnalyzer_12);
final FormData grid = new FormData();
grid.left = new FormAttachment(0, 0);
grid.right = new FormAttachment(100, -5);
grid.bottom = new FormAttachment(100, -5);
runtimeInfoGroup.setLayoutData(grid);
runtimeInfoGroup.setLayout(new FormLayout());
// Error message label
this.errorMessageLabel = new Label(runtimeInfoGroup, SWT.NONE);
final FormData deadlockMessageFormData = new FormData();
deadlockMessageFormData.left = new FormAttachment(0, 5);
deadlockMessageFormData.top = new FormAttachment(0, 5);
deadlockMessageFormData.width = 300;
this.errorMessageLabel.setLayoutData(deadlockMessageFormData);
final Font errorMessageLabelFont = setFontSize(this.errorMessageLabel.getFont(), 10);
this.errorMessageLabel.setFont(errorMessageLabelFont);
// Browse calls button
this.browseCallsButton = new Button(runtimeInfoGroup, SWT.PUSH);
this.browseCallsButton.setImage(noErrorImage);
this.browseCallsButton.setText(Messages.GemAnalyzer_79);
this.browseCallsButton.setToolTipText(Messages.GemAnalyzer_14);
this.browseCallsButton.setEnabled(false);
final FormData browseCallsFormData = new FormData();
browseCallsFormData.right = new FormAttachment(100, -5);
browseCallsFormData.bottom = new FormAttachment(100, -5);
this.browseCallsButton.setLayoutData(browseCallsFormData);
// Launch ispUI button
this.launchHpvButton = new Button(runtimeInfoGroup, SWT.PUSH);
this.launchHpvButton.setImage(hbvImage);
this.launchHpvButton.setText(Messages.GemAnalyzer_15);
this.launchHpvButton.setToolTipText(Messages.GemAnalyzer_16);
this.launchHpvButton.setEnabled(false);
final FormData launchIspUIFormData = new FormData();
launchIspUIFormData.right = new FormAttachment(this.browseCallsButton, -5);
launchIspUIFormData.bottom = new FormAttachment(100, -5);
this.launchHpvButton.setLayoutData(launchIspUIFormData);
// Run GEM button
this.runGemButton = new Button(runtimeInfoGroup, SWT.PUSH);
this.runGemButton.setImage(trident);
this.runGemButton.setToolTipText(Messages.GemAnalyzer_17);
final FormData runGemFormData = new FormData();
runGemFormData.right = new FormAttachment(this.launchHpvButton, -20);
runGemFormData.bottom = new FormAttachment(100, -5);
this.runGemButton.setLayoutData(runGemFormData);
this.runGemButton.setEnabled(true);
// Set number of processes button
this.setNumProcsComboList = new Combo(runtimeInfoGroup, SWT.DROP_DOWN);
final Font setRankComboFont = setFontSize(this.setNumProcsComboList.getFont(), 9);
this.setNumProcsComboList.setFont(setRankComboFont);
final String[] items = new String[] {};
this.setNumProcsComboList.setItems(items);
this.setNumProcsComboList.setText(" "); //$NON-NLS-1$
this.setNumProcsComboList.setToolTipText(Messages.GemAnalyzer_18);
final FormData setRankFormData = new FormData();
setRankFormData.width = 50;
setRankFormData.right = new FormAttachment(this.runGemButton, -5);
setRankFormData.bottom = new FormAttachment(100, -5);
this.setNumProcsComboList.setLayoutData(setRankFormData);
this.setNumProcsComboList.setEnabled(true);
setNumProcItems();
updateDropDown();
// Font for the buttons
final Font buttonFont = setFontSize(this.errorMessageLabel.getFont(), 8);
this.launchHpvButton.setFont(buttonFont);
this.browseCallsButton.setFont(buttonFont);
this.setNumProcsComboList.setFont(buttonFont);
}
/*
* Helper method called by createPartControl.
*/
private void createSelectionListeners() {
// SelectionListeners for transitions group buttons
this.firstTransitionButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateFirstTransition(true);
}
});
this.previousTransitionButton
.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updatePreviousTransition();
}
});
this.nextTransitionButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateNextTransition(true);
}
});
this.lastTransitionButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateLastTransition();
}
});
this.lockRanksComboList.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
if (GemAnalyzer.this.lockRanksComboList.getText() == null) {
return;
}
try {
final int selectionIndex = GemAnalyzer.this.lockRanksComboList.getSelectionIndex();
final String selectionText = GemAnalyzer.this.lockRanksComboList.getItems()[selectionIndex];
final Pattern rankPattern = Pattern.compile("^([a-zA-Z]+?)\\s+([0-9]+?)\\s+([a-zA-Z]+?)$"); //$NON-NLS-1$
final Matcher rankPatternMatcher = rankPattern.matcher(selectionText);
if (rankPatternMatcher.matches()) {
final String rankStr = rankPatternMatcher.group(2);
GemAnalyzer.this.lockedRank = Integer.parseInt(rankStr);
} else {
GemAnalyzer.this.lockedRank = -1;
}
updateTransitionLabels(true);
} catch (final Exception e) {
GemUtilities.logExceptionDetail(e);
GemAnalyzer.this.lockedRank = -1;
}
}
});
// SelectionListeners for interleavings group buttons
this.firstInterleavingButton
.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (GemAnalyzer.this.transitions.hasPreviousInterleaving()) {
while (GemAnalyzer.this.transitions.setPreviousInterleaving()) {
// do nothing
}
updateTransitionLabels(true);
} else {
GemUtilities.showInformationDialog(Messages.GemAnalyzer_19);
}
}
});
this.previousInterleavingButton
.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (GemAnalyzer.this.transitions.hasPreviousInterleaving()) {
GemAnalyzer.this.transitions.setPreviousInterleaving();
updateTransitionLabels(true);
} else {
GemUtilities.showInformationDialog(Messages.GemAnalyzer_20);
}
}
});
this.nextInterleavingButton
.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (GemAnalyzer.this.transitions.hasNextInterleaving()) {
GemAnalyzer.this.transitions.setNextInterleaving();
updateTransitionLabels(true);
} else {
GemUtilities.showInformationDialog(Messages.GemAnalyzer_21);
}
}
});
this.lastInterleavingButton
.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
while (GemAnalyzer.this.transitions.hasNextInterleaving()) {
GemAnalyzer.this.transitions.setNextInterleaving();
}
updateTransitionLabels(true);
}
});
this.deadlockInterleavingButton
.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
GemAnalyzer.this.transitions.deadlockInterleaving();
updateTransitionLabels(true);
}
});
// Selection listeners for step order group
this.internalIssueOrderButton
.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (GemAnalyzer.this.internalIssueOrderButton.getSelection()) {
if (GemAnalyzer.this.transitions != null) {
final ArrayList<ArrayList<Envelope>> tlists = GemAnalyzer.this.transitions.getTransitionList();
// Sort by internal issue order
final int size = tlists.size();
for (int i = 0; i < size; i++) {
Collections.sort(tlists.get(i), new InternalIssueOrderSorter());
}
}
// Reset preference store value for this preference
GemPlugin.getDefault().getPreferenceStore()
.setValue(PreferenceConstants.GEM_PREF_STEP_ORDER, "issueOrder"); //$NON-NLS-1$
reset();
}
}
});
this.programOrderButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (GemAnalyzer.this.programOrderButton.getSelection()) {
// Sort by internal issue order
if (GemAnalyzer.this.transitions != null) {
final ArrayList<ArrayList<Envelope>> tlists = GemAnalyzer.this.transitions.getTransitionList();
final int size = tlists.size();
for (int i = 0; i < size; i++) {
Collections.sort(tlists.get(i), new ProgramOrderSorter());
}
}
// Reset preference store value for this preference
GemPlugin.getDefault().getPreferenceStore()
.setValue(PreferenceConstants.GEM_PREF_STEP_ORDER, "programOrder"); //$NON-NLS-1$
reset();
}
}
});
// To conveniently run GEM from this view
this.runGemButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
final IPreferenceStore pstore = GemPlugin.getDefault().getPreferenceStore();
URI inputLocation = null;
IPath path = null;
try {
inputLocation = new URI(pstore.getString(PreferenceConstants.GEM_PREF_MOST_RECENT_FILE));
} catch (final URISyntaxException e) {
GemUtilities.logExceptionDetail(e);
}
if (inputLocation != null) {
path = new Path(inputLocation.getPath());
}
if (GemAnalyzer.this.activeFile == null) {
GemUtilities.setTaskStatus(GemUtilities.TaskStatus.ABORTED);
return;
}
final IFile file = GemUtilities.getCurrentProject(GemAnalyzer.this.activeFile).getFile(path.lastSegment());
path = file.getFullPath();
final String extension = file.getFileExtension();
boolean isSourceFile = false;
if (extension != null) {
// The most common C & C++ source file extensions
isSourceFile = extension.equals("c") //$NON-NLS-1$
|| extension.equals("cpp") || extension.equals("c++") //$NON-NLS-1$ //$NON-NLS-2$
|| extension.equals("cc") || extension.equals("cp"); //$NON-NLS-1$ //$NON-NLS-2$
}
// ask for command line arguments
GemUtilities.setCommandLineArgs();
// Open Analyzer and Browser Views in preference order
// Find the active editor
final IWorkbench wb = PlatformUI.getWorkbench();
final IWorkbenchWindow window = wb.getActiveWorkbenchWindow();
final IWorkbenchPage page = window.getActivePage();
try {
final String activeView = pstore.getString(PreferenceConstants.GEM_ACTIVE_VIEW);
if (activeView.equals("analyzer")) { //$NON-NLS-1$
page.showView(GemBrowser.ID);
page.showView(GemAnalyzer.ID);
} else {
page.showView(GemAnalyzer.ID);
page.showView(GemBrowser.ID);
}
GemUtilities.initGemViews(file, isSourceFile, true);
} catch (final PartInitException e) {
GemUtilities.logExceptionDetail(e);
}
}
});
// Selection listeners for runtime information group buttons
this.setNumProcsComboList.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
if (GemAnalyzer.this.setNumProcsComboList.getText() == null) {
return;
}
final int selectionIndex = GemAnalyzer.this.setNumProcsComboList.getSelectionIndex();
final String nprocsStr = GemAnalyzer.this.setNumProcsComboList.getItems()[selectionIndex];
final int newNumProcs = Integer.parseInt(nprocsStr);
// Reset the numProcs value in the preference store
GemPlugin.getDefault().getPreferenceStore().setValue(PreferenceConstants.GEM_PREF_NUMPROCS, newNumProcs);
// If the browser is open updates its drop down
try {
final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
final IViewPart browserPart = window.getActivePage().findView(GemBrowser.ID);
final GemBrowser browser = (GemBrowser) browserPart;
browser.updateDropDown();
} catch (final Exception e) {
GemUtilities.logExceptionDetail(e);
}
}
});
this.launchHpvButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
final URI uri = GemUtilities.getMostRecentURI();
IPath sourceFilePath = null;
IFile sourceFile = null;
if (uri != null) {
sourceFilePath = new Path(uri.getPath());
}
final IProject currentProject = GemUtilities.getProjectLogFile().getProject();
final String currentProjectPath = currentProject.getLocationURI().getPath();
if (sourceFilePath != null) {
sourceFilePath = sourceFilePath.makeRelativeTo(new Path(currentProjectPath));
sourceFile = currentProject.getFile(sourceFilePath);
}
if (sourceFile != null) {
if (GemUtilities.isRemoteProject(GemAnalyzer.this.activeFile)
|| GemUtilities.isSynchronizedProject(GemAnalyzer.this.activeFile)) {
GemUtilities.showInformationDialog(Messages.GemAnalyzer_23);
return;
}
// Otherwise launch the HB viewer
GemUtilities.doHbv(sourceFile);
} else {
// There was a local error while creating the log file.
final String message = Messages.GemAnalyzer_13;
// GemUtilities.showErrorDialog(message);
}
}
});
this.browseCallsButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (GemAnalyzer.this.transitions == null) {
final String message = Messages.GemAnalyzer_24;
GemUtilities.showErrorDialog(message);
return;
}
final class CallBrowserDisplay implements Runnable {
public void run() {
final IWorkbench wb = PlatformUI.getWorkbench();
final Display display = wb.getDisplay();
final Shell shell = new Shell();
shell.setText(Messages.GemAnalyzer_68);
shell.setImage(GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/magnified-trident.gif"))); //$NON-NLS-1$
shell.setLayout(new GridLayout());
final CLabel fileNameLabel = new CLabel(shell, SWT.BORDER_SOLID);
fileNameLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
final CLabel numProcsLabel = new CLabel(shell, SWT.BORDER_SOLID);
numProcsLabel.setImage(GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/processes.gif"))); //$NON-NLS-1$
numProcsLabel.setText(Messages.GemAnalyzer_69 + GemAnalyzer.this.numRanks);
numProcsLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
final Tree tree = new Tree(shell, SWT.BORDER);
tree.setLinesVisible(true);
tree.setLayoutData(new GridData(GridData.FILL_BOTH));
tree.setFont(setFontSize(tree.getFont(), 8));
// Declare everything we'll be working with
TreeItem interleavingItem = null;
TreeItem callItem = null;
final int currentInter = GemAnalyzer.this.transitions.getCurrentInterleaving();
// Loop over all interleavings
final int numInterleavings = GemAnalyzer.this.transitions.getTotalInterleavings() + 1; // 0-based
for (int currentInterleaving = 1; currentInterleaving < numInterleavings; currentInterleaving++) {
// Create a root node for each interleaving
interleavingItem = new TreeItem(tree, SWT.NULL);
interleavingItem.setText(Messages.GemAnalyzer_70 + currentInterleaving);
// Loop over all envelopes (transitions) in the current interleaving
final ArrayList<Envelope> envelopes = GemAnalyzer.this.transitions
.getInterleavingEnvelopes(currentInterleaving);
final int listSize = envelopes.size();
Envelope env = null;
String functionName = null;
String fileName = null;
int lineNumber = -1;
int envRank = -1;
try {
for (int envIndex = 0; envIndex < listSize; envIndex++) {
env = envelopes.get(envIndex);
// Don't display resource leaks
if (env.isLeak()) {
continue;
}
// Create the leaf node representing the call
callItem = new TreeItem(interleavingItem, SWT.NULL);
functionName = env.getFunctionName();
fileName = new Path(env.getFilePath()).lastSegment().toString();
lineNumber = env.getLinenumber();
envRank = env.getRank();
// make all calls have same name length
while (functionName.length() < 12) {
functionName += " "; //$NON-NLS-1$
}
final StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("Rank: "); //$NON-NLS-1$
stringBuffer.append(envRank);
stringBuffer.append("\t\t"); //$NON-NLS-1$
stringBuffer.append(functionName);
stringBuffer.append("\t\t"); //$NON-NLS-1$
stringBuffer.append(fileName);
stringBuffer.append(":"); //$NON-NLS-1$
stringBuffer.append(lineNumber);
final String callItemText = stringBuffer.toString();
callItem.setText(callItemText);
// Mark the calls with errors red
if (env.getIssueIndex() == -1) {
callItem.setForeground(new Color(null, 255, 0, 0));
}
// Mark the current call(s) blue
String currentFile = null;
int currentLine = -1;
if (GemAnalyzer.this.transitions.getCurrentTransition() != null) {
currentFile = GemAnalyzer.this.transitions.getCurrentTransition().getFilePath();
currentLine = GemAnalyzer.this.transitions.getCurrentTransition().getLinenumber();
}
if (currentFile != null) {
if (currentLine == env.getLinenumber() && currentFile.equals(env.getFilePath())
&& currentInter == env.getInterleaving()) {
callItem.setForeground(new Color(null, 0, 0, 255));
// Comment this out if you don't want items expanded
revealTreeItem(callItem);
}
}
}
} catch (final Exception e) {
GemUtilities.logExceptionDetail(e);
}
}
// Open up the Call Browser window with the specified size
shell.setSize(550, 550);
shell.open();
if (GemAnalyzer.this.activeShells == null) {
GemAnalyzer.this.activeShells = new LinkedList<Shell>();
}
GemAnalyzer.this.activeShells.add(shell);
// Set up the event loop for disposal
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
final CallBrowserDisplay browser = new CallBrowserDisplay();
Display.getDefault().syncExec(browser);
}
});
}
/*
* Helper method called by createPartControl.
*/
private void createStepOrderGroup(Composite parent) {
// Group and FormLayout data for step order radio buttons
this.stepOrderGroup = new Group(parent, SWT.SHADOW_IN);
this.stepOrderGroup.setText(Messages.GemAnalyzer_25);
this.stepOrderGroup.setToolTipText(Messages.GemAnalyzer_26);
final FormData stepOrderFormData = new FormData();
// stepOrderFormData.left = new FormAttachment(this.interleavingsGroup,
// 20);
stepOrderFormData.right = new FormAttachment(100, -5);
stepOrderFormData.bottom = new FormAttachment(100, -5);
this.stepOrderGroup.setLayoutData(stepOrderFormData);
this.stepOrderGroup.setLayout(new GridLayout(3, false));
// Step order radio buttons
this.internalIssueOrderButton = new Button(this.stepOrderGroup, SWT.RADIO);
this.internalIssueOrderButton.setText(Messages.GemAnalyzer_27);
this.internalIssueOrderButton.setToolTipText(Messages.GemAnalyzer_28);
this.programOrderButton = new Button(this.stepOrderGroup, SWT.RADIO);
this.programOrderButton.setText(Messages.GemAnalyzer_29);
this.programOrderButton.setToolTipText(Messages.GemAnalyzer_30);
// Choose which one is to be enabled from the Preference Store setting
final String stepOrder = GemPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.GEM_PREF_STEP_ORDER);
if (stepOrder.equals("issueOrder")) { //$NON-NLS-1$
this.internalIssueOrderButton.setSelection(true);
} else {
this.programOrderButton.setSelection(true);
}
// Font for the radio buttons
final Font buttonFont = setFontSize(this.programOrderButton.getFont(), 8);
this.internalIssueOrderButton.setFont(buttonFont);
this.programOrderButton.setFont(buttonFont);
}
/*
* Helper method called by createPartControl.
*/
private void createTransitionsGroup(Composite parent) {
// Get images for buttons from image cache
final Image firstItemImage = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/first-item.gif")); //$NON-NLS-1$
final Image lastItemImage = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/last-item.gif")); //$NON-NLS-1$
final Image prevItemImage = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/prev-item.gif")); //$NON-NLS-1$
final Image nextItemImage = GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/next-item.gif")); //$NON-NLS-1$
// Group and FormLayout data for transition buttons and labels
this.transitionsGroup = new Group(parent, SWT.SHADOW_IN);
this.transitionsGroup.setText(Messages.GemAnalyzer_32);
this.transitionsGroup.setToolTipText(Messages.GemAnalyzer_33);
final FormData transitionsFormData = new FormData();
transitionsFormData.left = new FormAttachment(0, 0);
transitionsFormData.bottom = new FormAttachment(100, -5);
this.transitionsGroup.setLayoutData(transitionsFormData);
this.transitionsGroup.setLayout(new FormLayout());
// First transition button
this.firstTransitionButton = new Button(this.transitionsGroup, SWT.PUSH);
this.firstTransitionButton.setImage(firstItemImage);
this.firstTransitionButton.setToolTipText(Messages.GemAnalyzer_34);
this.firstTransitionButton.setEnabled(false);
final FormData tfirstFormData = new FormData();
tfirstFormData.left = new FormAttachment(0, 5);
tfirstFormData.bottom = new FormAttachment(100, -5);
this.firstTransitionButton.setLayoutData(tfirstFormData);
// Previous transition button
this.previousTransitionButton = new Button(this.transitionsGroup, SWT.PUSH);
this.previousTransitionButton.setImage(prevItemImage);
this.previousTransitionButton.setToolTipText(Messages.GemAnalyzer_35);
this.previousTransitionButton.setEnabled(false);
final FormData tprevFormData = new FormData();
tprevFormData.left = new FormAttachment(this.firstTransitionButton, 3);
tprevFormData.bottom = new FormAttachment(100, -5);
this.previousTransitionButton.setLayoutData(tprevFormData);
// Next transition buttons
this.nextTransitionButton = new Button(this.transitionsGroup, SWT.PUSH);
this.nextTransitionButton.setImage(nextItemImage);
this.nextTransitionButton.setToolTipText(Messages.GemAnalyzer_36);
this.nextTransitionButton.setEnabled(false);
final FormData tnextFormData = new FormData();
tnextFormData.left = new FormAttachment(this.previousTransitionButton, 3);
tnextFormData.bottom = new FormAttachment(100, -5);
this.nextTransitionButton.setLayoutData(tnextFormData);
// Last transition button
this.lastTransitionButton = new Button(this.transitionsGroup, SWT.PUSH);
this.lastTransitionButton.setImage(lastItemImage);
this.lastTransitionButton.setToolTipText(Messages.GemAnalyzer_37);
this.lastTransitionButton.setEnabled(false);
final FormData tlastFormData = new FormData();
tlastFormData.left = new FormAttachment(this.nextTransitionButton, 3);
tlastFormData.bottom = new FormAttachment(100, -5);
this.lastTransitionButton.setLayoutData(tlastFormData);
// Lock ranks button
this.lockRanksComboList = new Combo(this.transitionsGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
final Font lockRanksComboFont = setFontSize(this.lockRanksComboList.getFont(), 8);
this.lockRanksComboList.setFont(lockRanksComboFont);
final String[] items = new String[] { Messages.GemAnalyzer_83 };
this.lockRanksComboList.setItems(items);
this.lockRanksComboList.setToolTipText(Messages.GemAnalyzer_39);
final FormData lockRanksFormData = new FormData();
lockRanksFormData.left = new FormAttachment(this.lastTransitionButton, 10);
lockRanksFormData.right = new FormAttachment(100, -5);
lockRanksFormData.bottom = new FormAttachment(100, -5);
this.lockRanksComboList.setLayoutData(lockRanksFormData);
}
/*
* Uses the right code window to display all calls associated with the
* collective operation displayed in the left code view window.
*/
private void displayCollectiveInfo() {
final Envelope env = this.transitions.getCurrentTransition();
final ArrayList<Envelope> matches = env.getCommunicator_matches();
if (matches != null) {
final int listSize = matches.size();
for (int i = 0; i < listSize; i++) {
final Envelope currentMatchEnvelope = matches.get(i);
final String matchFilePathString = currentMatchEnvelope.getFilePath();
final IFile sourceFile = GemUtilities.getSourceFile(matchFilePathString, this.activeFile);
// Add the match to the right code view window
this.rightViewer.add(new ListElement(sourceFile, sourceFile.getName() + Messages.GemAnalyzer_40
+ currentMatchEnvelope.getLinenumber()
+ Messages.GemAnalyzer_41
+ currentMatchEnvelope.getRank(), currentMatchEnvelope.getLinenumber(), false));
}
}
}
/*
* Displays the specified envelope and it's matches if they exist.
*/
private void displayEnvelopes(Envelope env) {
// If the envelope is null, it's a new interleaving, start over
if (env == null) {
return;
}
// Set the indexes for the highlighted line updater
this.leftIndex = env.getLinenumber();
boolean hasMatch = true;
try {
final Envelope match = env.getMatch_envelope();
if (match != null) {
this.rightIndex = match.getLinenumber();
} else {
hasMatch = false;
}
} catch (final Exception e) {
GemUtilities.logExceptionDetail(e);
}
// Set font color for code window labels
Color textColor = new Color(this.parent.getShell().getDisplay(), new RGB(0, 0, 255));
this.leftCodeWindowLabel.setForeground(textColor);
this.rightCodeWindowLabel.setForeground(textColor);
// Build up the Strings for the Label text
final String leftResult = getCallText(env, true);
this.leftCodeWindowLabel.setText(leftResult);
// If a match exists update the right side
if (hasMatch) {
final Envelope match = env.getMatch_envelope();
final String rightResult = getCallText(match, false);
this.rightCodeWindowLabel.setText(rightResult);
} else {
this.rightIndex = -1;
this.rightViewer.getList().deselectAll();
this.rightCodeWindowLabel.setText(""); //$NON-NLS-1$
}
if (env.getIssueIndex() == -1) {
textColor = new Color(this.parent.getShell().getDisplay(), new RGB(255, 0, 0));
this.rightCodeWindowLabel.setForeground(textColor);
if (env.getFunctionName().equals("MPI_Abort")) { //$NON-NLS-1$
this.rightCodeWindowLabel.setText(""); //$NON-NLS-1$
} else if (this.transitions.hasDeadlock()) {
this.rightCodeWindowLabel.setText(Messages.GemAnalyzer_46);
} else {
this.rightCodeWindowLabel.setText(Messages.GemAnalyzer_47);
}
}
}
/**
* Disposes of all shell windows when the instance of Eclipse that created
* them exits.
*
* @param none
* @return void
*/
@Override
public void dispose() {
if (this.activeShells != null) {
for (final Shell s : this.activeShells) {
if (s != null) {
s.dispose();
}
}
}
super.dispose();
}
/*
* Populates the view context menu.
*/
private void fillContextMenu(IMenuManager manager) {
manager.add(this.terminateButton);
this.terminateButton.setText(Messages.GemAnalyzer_48);
manager.add(this.getHelp);
this.getHelp.setText(Messages.GemAnalyzer_49);
// Other plug-ins can contribute their actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
/*
* Populates the view pull-down menu.
*/
private void fillLocalPullDown(IMenuManager manager) {
manager.add(this.terminateButton);
this.terminateButton.setText(Messages.GemAnalyzer_50);
manager.add(new Separator());
manager.add(this.getHelp);
this.getHelp.setText(Messages.GemAnalyzer_51);
manager.add(new Separator());
// Other plug-ins can contribute their actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
/*
* Contributes icons and actions to the tool bar.
*/
private void fillLocalToolBar(IToolBarManager manager) {
manager.add(this.terminateButton);
manager.add(this.getHelp);
// Other plug-ins can contribute their actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
/*
* Returns a String representing all information relative to a particular
* successful MPI call.
*/
private String getCallText(Envelope env, boolean isLeft) {
final String newline = System.getProperty("line.separator"); //$NON-NLS-1$
final String sourceFilePathString = env.getFilePath();
final IFile sourceFile = GemUtilities.getSourceFile(sourceFilePathString, this.activeFile);
final String fileName = sourceFile.getName();
final StringBuffer stringBuffer = new StringBuffer();
// determine which ranks are involved; by default only call's rank
String ranks = Messages.GemAnalyzer_53 + env.getRank()
+ (System.getProperty("os.name").contains("Windows") ? "\t" : newline); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (env.isCollective() && this.lockedRank == -1) {
// If it was a group call then discover who else is here
final int numRanksInvolved[] = new int[1];
if (this.lockedRank == -1) {
// Also see if we're looking at a single rank or not
ranks = this.transitions.getRanksInvolved(numRanksInvolved);
}
// This is currently the max #processes GEM drop-down boxes allow
final int MAX = 16;
if (numRanksInvolved[0] > MAX) {
// display only first ten ranks
String tempRanks = ranks;
int total = 0;
for (int i = 0; i < MAX; i++) {
// May be multi-digit numbers, hence this code
total += tempRanks.indexOf(",") + 1; //$NON-NLS-1$
tempRanks = tempRanks.substring(tempRanks.indexOf(",") + 1); //$NON-NLS-1$
}
stringBuffer.append(Messages.GemAnalyzer_22);
stringBuffer.append(ranks.substring(0, total - 1));
stringBuffer.append("..."); //$NON-NLS-1$
stringBuffer.append(newline);
} else {
stringBuffer.append(Messages.GemAnalyzer_55);
stringBuffer.append(ranks);
stringBuffer.append(newline);
}
// count number of ":" to determine how many ranks involved
int ranksCommunicatedTo = 0;
String communicator = env.getCommunicator_ranks_string();
while (communicator != null && communicator.contains(":")) { //$NON-NLS-1$
communicator = communicator.substring(communicator.indexOf(":") + 1); //$NON-NLS-1$
ranksCommunicatedTo++;
}
if (ranksCommunicatedTo != 0 && numRanksInvolved[0] / ranksCommunicatedTo > 1) {
stringBuffer.append(Messages.GemAnalyzer_56);
stringBuffer.append(numRanksInvolved[0] / ranksCommunicatedTo);
stringBuffer.append(Messages.GemAnalyzer_57);
stringBuffer.append(ranksCommunicatedTo);
stringBuffer.append(Messages.GemAnalyzer_58);
}
}
if (!env.isCollective()) {
stringBuffer.append(ranks);
}
stringBuffer.append(Messages.GemAnalyzer_60);
stringBuffer.append(fileName);
stringBuffer.append("\t"); //$NON-NLS-1$
stringBuffer.append(Messages.GemAnalyzer_61);
stringBuffer.append(isLeft ? this.leftIndex : this.rightIndex);
return stringBuffer.toString();
}
/*
* Adds MenuListeners to hook selections from the context menu.
*/
private void hookContextMenu() {
final MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
GemAnalyzer.this.fillContextMenu(manager);
}
});
final Menu leftMenu = menuMgr.createContextMenu(this.leftViewer.getControl());
this.leftViewer.getControl().setMenu(leftMenu);
getSite().registerContextMenu(menuMgr, this.leftViewer);
final Menu rightMenu = menuMgr.createContextMenu(this.rightViewer.getControl());
this.rightViewer.getControl().setMenu(rightMenu);
getSite().registerContextMenu(menuMgr, this.rightViewer);
}
/**
* Initializing everything and creates threads to be used by the main UI
* thread to do updates.
*
* @param resource
* The resource to initialize this view with.
* @return void
*/
public void init(IResource resource) {
this.activeFile = GemUtilities.adaptResource(resource);
this.analyzerUpdateThread = new Thread() {
@Override
public void run() {
// If just aborted then don't fill viewers with incomplete data
if (GemAnalyzer.this.aborted) {
Display.getDefault().syncExec(GemAnalyzer.this.disableTerminateButtonThread);
Display.getDefault().syncExec(GemAnalyzer.this.clearAnalyzerThread);
GemAnalyzer.this.aborted = false;
return;
}
// if the log file contained no MPI calls
if (GemAnalyzer.this.activeFile == null) {
Display.getDefault().syncExec(GemAnalyzer.this.disableTerminateButtonThread);
clear();
return;
}
reset();
parseSourceFile(GemAnalyzer.this.activeFile, GemAnalyzer.this.activeFile);
Display.getDefault().syncExec(GemAnalyzer.this.disableTerminateButtonThread);
}
};
this.clearAnalyzerThread = new Thread() {
@Override
public void run() {
final String emptyString = ""; //$NON-NLS-1$
GemAnalyzer.this.transitionsGroup.setText("Transition:" + " 0/0"); //$NON-NLS-1$ //$NON-NLS-2$
GemAnalyzer.this.interleavingsGroup.setText("Interleaving:" + " 0/0"); //$NON-NLS-1$ //$NON-NLS-2$
GemAnalyzer.this.firstTransitionButton.setEnabled(false);
GemAnalyzer.this.previousTransitionButton.setEnabled(false);
GemAnalyzer.this.nextTransitionButton.setEnabled(false);
GemAnalyzer.this.lastTransitionButton.setEnabled(false);
GemAnalyzer.this.firstInterleavingButton.setEnabled(false);
GemAnalyzer.this.previousInterleavingButton.setEnabled(false);
GemAnalyzer.this.nextInterleavingButton.setEnabled(false);
GemAnalyzer.this.lastInterleavingButton.setEnabled(false);
GemAnalyzer.this.deadlockInterleavingButton.setEnabled(false);
GemAnalyzer.this.internalIssueOrderButton.setEnabled(false);
GemAnalyzer.this.programOrderButton.setEnabled(false);
GemAnalyzer.this.launchHpvButton.setEnabled(false);
GemAnalyzer.this.browseCallsButton.setEnabled(false);
GemAnalyzer.this.terminateButton.setEnabled(false);
GemAnalyzer.this.errorMessageLabel.setText(emptyString);
GemAnalyzer.this.transitions = null;
GemAnalyzer.this.leftViewer.refresh();
GemAnalyzer.this.rightViewer.refresh();
GemAnalyzer.this.leftCodeWindowLabel.setText(emptyString);
GemAnalyzer.this.rightCodeWindowLabel.setText(emptyString);
final String[] items = new String[] { emptyString };
GemAnalyzer.this.lockRanksComboList.setItems(items);
GemUtilities.setTaskStatus(GemUtilities.TaskStatus.IDLE);
GemAnalyzer.this.runGemButton.setEnabled(true);
}
};
this.disableTerminateButtonThread = new Thread() {
@Override
public void run() {
GemAnalyzer.this.terminateButton.setEnabled(false);
GemAnalyzer.this.runGemButton.setEnabled(true);
GemAnalyzer.this.internalIssueOrderButton.setEnabled(true);
GemAnalyzer.this.programOrderButton.setEnabled(true);
}
};
// start things up now
this.terminateButton.setEnabled(true);
this.runGemButton.setEnabled(false);
}
/*
* Launches the call browser as a separate shell window. This will yield a
* list of MPI calls sorted by interleaving -> rank -> MPI call. Calls are
* also color coded to distinguish the currently selected line in analyzer
* code windows (blue), as well as uncompleted calls due to a deadlock in
* the particular interleaving (red).
*/
/*
* Creates the actions associated with the action bar buttons and context
* menu items.
*/
private void makeActions() {
this.getHelp = new Action() {
@Override
public void run() {
PlatformUI.getWorkbench().getHelpSystem().displayHelpResource("/org.eclipse.ptp.gem.help/html/analyzerView.html"); //$NON-NLS-1$
}
};
this.getHelp.setToolTipText(Messages.GemAnalyzer_73);
this.getHelp.setImageDescriptor(GemPlugin.getImageDescriptor("icons/help-contents.gif")); //$NON-NLS-1$
this.terminateButton = new Action() {
@Override
public void run() {
GemAnalyzer.this.aborted = true;
GemUtilities.terminateOperation();
}
};
this.terminateButton.setImageDescriptor(GemPlugin.getImageDescriptor("icons/progress_stop.gif")); //$NON-NLS-1$
this.terminateButton.setToolTipText(Messages.GemAnalyzer_74);
this.terminateButton.setEnabled(false);
}
/*
* Opens the editor with the current source file active and jump to the line
* number that is passed in.
*/
private void openEditor(int lineNum, IFile sourceFile) {
try {
final IEditorPart editor = IDE.openEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(),
sourceFile, true);
final IMarker marker = sourceFile.createMarker(IMarker.MARKER);
marker.setAttribute(IMarker.LINE_NUMBER, lineNum);
IDE.gotoMarker(editor, marker);
} catch (final Exception e) {
GemUtilities.logExceptionDetail(e);
}
}
/*
* Returns whether or not the specified String has a matching number of left
* and right. parenthesis.
*/
private boolean parenthesesMatched(String call) {
int numRightParens = 0;
int numLeftParens = 0;
call = removeComments(call);
for (int i = 0; i < call.length(); i++) {
if (call.charAt(i) == '(') {
numLeftParens++;
}
if (call.charAt(i) == ')') {
numRightParens++;
}
}
return (numRightParens == numLeftParens);
}
/**
* Reads in the contents of the specified file and populates the
* ListViewers.
*
* @param leftSourceFile
* The handle on the file resource for the left code view window.
* @param rightSourceFile
* The handle on the file resource for the right code view
* window.
* @return void
*/
public void parseSourceFile(IFile leftSourceFile, IFile rightSourceFile) {
final Boolean updateLeftFile = this.currLeftFile == null || !this.currLeftFile.equals(leftSourceFile);
final Boolean updateRightFile = this.currRightFile == null || rightSourceFile == null
|| !this.currRightFile.equals(rightSourceFile);
this.currLeftFile = leftSourceFile;
this.currRightFile = rightSourceFile;
// Clear the left viewer list
if (updateLeftFile) {
this.leftViewer.getList().removeAll();
}
boolean isCollective = false;
if (this.transitions != null && this.transitions.getCurrentTransition() != null) {
isCollective = this.transitions.getCurrentTransition().isCollective();
}
// Clear the right viewer list
if (isCollective || updateRightFile) {
this.rightViewer.getList().removeAll();
}
// Populate the viewers with the source file contents
InputStream leftSourceFileStream = null;
InputStream rightSourceFileStream = null;
String line = ""; //$NON-NLS-1$
// Populate the left code window
try {
leftSourceFileStream = leftSourceFile.getContents(true);
final Scanner s = new Scanner(leftSourceFileStream);
int lineNum = 0;
while (updateLeftFile && s.hasNext()) {
lineNum++;
line = s.nextLine();
this.leftViewer.add(new ListElement(leftSourceFile, line, lineNum, false));
}
} catch (final CoreException e) {
GemUtilities.logExceptionDetail(e);
this.leftViewer.add(new ListElement(null, Messages.GemAnalyzer_76, -1, false));
}
// Populate the right code window
try {
if (rightSourceFile != null) {
rightSourceFileStream = rightSourceFile.getContents();
final Scanner s = new Scanner(rightSourceFileStream);
int lineNum = 0;
while (s.hasNext()) {
lineNum++;
line = s.nextLine();
this.rightViewer.add(new ListElement(rightSourceFile, line, lineNum, false));
}
} else {
final Envelope env = this.transitions.getCurrentTransition();
if (env.isCollective()) {
displayCollectiveInfo();
} else {
this.rightViewer.add(new ListElement(null, "", -1, false)); //$NON-NLS-1$
}
}
} catch (final Exception e) {
GemUtilities.logExceptionDetail(e);
this.rightViewer.add(new ListElement(null, Messages.GemAnalyzer_78, -1, false));
}
// Close the open InputStreams
try {
if (leftSourceFileStream != null) {
leftSourceFileStream.close();
}
if (rightSourceFileStream != null) {
rightSourceFileStream.close();
}
} catch (final IOException e) {
GemUtilities.logExceptionDetail(e);
}
}
/*
* Removes comments from the specified call String.
*/
private String removeComments(String call) {
// remove any c-style comments
while (call.contains("/*")) { //$NON-NLS-1$
if (!call.contains("*/")) { //$NON-NLS-1$
break;
}
call = call.substring(0, call.indexOf("/*")) + call.substring(call.indexOf("*/") + 2); //$NON-NLS-1$ //$NON-NLS-2$
}
// remove any c++-style comments
while (call.contains("//")) { //$NON-NLS-1$
call = call.substring(0, call.indexOf("//")); //$NON-NLS-1$
}
return call;
}
/*
* Resets everything to default values. Used when a new file is analyzed.
*/
private void reset() {
// By making the current files null we force the code viewers to update
this.currLeftFile = null;
this.currRightFile = null;
this.transitions.currentInterleaving = 0;
this.transitions.currentTransitionIndex = 0;
// Update labels and combo lists
setMessageLabelText();
setLockRankItems();
setNumProcItems();
// Update global indices
this.leftIndex = 0;
this.rightIndex = 0;
this.lockedRank = -1;
// Runtime group buttons
this.deadlockInterleavingButton.setEnabled(this.transitions.getDeadlockInterleavings() != null);
this.browseCallsButton.setEnabled(true);
this.browseCallsButton.setImage(GemPlugin.getImage(GemPlugin.getImageDescriptor("icons/browse.gif"))); //$NON-NLS-1$
this.launchHpvButton.setEnabled(true);
// Update transition related items w/o displaying
updateTransitionLabels(false);
// TODO Let's clean this up
// This section is needed since the scroll bars are unresponsive
// until the view is fully created. For this reason we need to back up
// to Transition 0 and update the labels.
this.transitionLabelIndex = 0;
this.transitionsGroup.setText("Transition " + this.transitionLabelIndex + "/" + this.transitionLabelCount); //$NON-NLS-1$ //$NON-NLS-2$
this.transitions.currentTransitionIndex = -1;
this.leftIndex = 0;
this.rightIndex = 0;
this.previousLeftIndex = 0;
setButtonEnabledState();
updateSelectedLine(true);
setMessageLabelText();
GemUtilities.setTaskStatus(GemUtilities.TaskStatus.IDLE);
}
/*
* To make an item visible we must expand each of its parents. Sadly the
* root must be expanded first and work its way down to the goal. So we
* recursively find parents and then expand once all of the current item's
* parents has been expanded.
*/
private void revealTreeItem(TreeItem callItem) {
if (callItem.getParentItem() == null) {
callItem.setExpanded(true);
} else {
revealTreeItem(callItem.getParentItem());
callItem.setExpanded(true);
}
}
/*
* Sets the enabled property of all buttons to the appropriate state.
*/
private void setButtonEnabledState() {
this.firstTransitionButton.setEnabled(this.transitions.hasValidPreviousTransition(this.lockedRank));
this.previousTransitionButton.setEnabled(this.transitions.hasValidPreviousTransition(this.lockedRank));
this.nextTransitionButton.setEnabled(this.transitions.hasValidNextTransition(this.lockedRank));
this.lastTransitionButton.setEnabled(this.transitions.hasValidNextTransition(this.lockedRank));
this.firstInterleavingButton.setEnabled(this.transitions.hasPreviousInterleaving());
this.previousInterleavingButton.setEnabled(this.transitions.hasPreviousInterleaving());
this.nextInterleavingButton.setEnabled(this.transitions.hasNextInterleaving());
this.lastInterleavingButton.setEnabled(this.transitions.hasNextInterleaving());
this.deadlockInterleavingButton.setEnabled(this.transitions.getDeadlockInterleavings() != null);
}
/**
* see org.eclipse.ui.IWorkbenchPart
*/
@Override
public void setFocus() {
this.runGemButton.setFocus();
}
/*
* Given the initial Font, this helper method returns that Font with the new
* specified size.
*/
private Font setFontSize(Font font, int size) {
final FontData[] fontData = font.getFontData();
for (final FontData element : fontData) {
element.setHeight(size);
}
return new Font(this.parent.getDisplay(), fontData);
}
/*
* Populates the lock ranks combo-box with the correct number of entries for
* the current analyzation.
*/
private void setLockRankItems() {
final String[] ranks = new String[this.numRanks + 1];
ranks[0] = Messages.GemAnalyzer_83;
for (int i = 1; i <= this.numRanks; i++) {
final StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(Messages.GemAnalyzer_84);
stringBuffer.append((Integer) (i - 1));
stringBuffer.append(Messages.GemAnalyzer_85);
ranks[i] = stringBuffer.toString();
}
this.lockRanksComboList.setItems(ranks);
this.lockRanksComboList.setText(ranks[0]);
}
/*
* Sets the label text in the interleavings buttons group.
*/
private void setMessageLabelText() {
// This is for foreground coloring
final Display display = this.parent.getShell().getDisplay();
final Color RED = new Color(display, new RGB(255, 0, 0));
final Color GREEN = new Color(display, new RGB(0, 200, 0));
final Color BLUE = new Color(display, new RGB(0, 0, 255));
// Interleaving label
this.interleavingsGroup.setText("Interleaving: " + this.transitions.getCurrentInterleaving() + "/" //$NON-NLS-1$ //$NON-NLS-2$
+ this.transitions.getTotalInterleavings());
// Transition Label
this.transitionsGroup.setText("Transition: " + this.transitionLabelIndex + "/" + this.transitionLabelCount); //$NON-NLS-1$ //$NON-NLS-2$
// Error message label
if (this.transitions.hasDeadlock()) {
this.errorMessageLabel.setForeground(RED);
final ArrayList<Integer> deadlockList = this.transitions.getDeadlockInterleavings();
String deadlocks = ""; //$NON-NLS-1$
if (deadlockList.size() == 1) {
deadlocks = deadlockList.get(0).toString();
} else {
for (int i = 0; i < deadlockList.size(); i++) {
final String num = deadlockList.get(i).toString();
deadlocks += (i != deadlockList.size() - 1) ? num + ", " : num; //$NON-NLS-1$
}
}
String errorMsg = Messages.GemAnalyzer_89;
errorMsg += deadlocks.length() == 1 ? " " : "s "; //$NON-NLS-1$ //$NON-NLS-2$
this.errorMessageLabel.setText(errorMsg + deadlocks);
} else if (this.transitions.hasAssertion()) {
this.errorMessageLabel.setForeground(RED);
this.errorMessageLabel.setText(Messages.GemAnalyzer_91 + this.transitions.getTotalInterleavings());
} else if (this.transitions.hasError()) {
this.errorMessageLabel.setForeground(RED);
this.errorMessageLabel.setText(Messages.GemAnalyzer_92);
} else {
if (this.transitions.hasResourceLeak() || this.transitions.hasFIB()) {
this.errorMessageLabel.setForeground(BLUE);
this.errorMessageLabel.setText(Messages.GemAnalyzer_93);
} else {
this.errorMessageLabel.setForeground(GREEN);
this.errorMessageLabel.setText(Messages.GemAnalyzer_31);
}
}
}
/*
* Populates the num-procs combo-box with choices the user can use to set
* the number of processes for the next analyzer run.
*/
private void setNumProcItems() {
final String[] ranks = new String[16];
for (int i = 1; i <= 16; i++) {
ranks[i - 1] = ((Integer) i).toString();
}
this.setNumProcsComboList.setItems(ranks);
final Integer nprocs = GemPlugin.getDefault().getPreferenceStore().getInt(PreferenceConstants.GEM_PREF_NUMPROCS);
this.setNumProcsComboList.setText(nprocs.toString());
}
/*
* This method eliminates displaying of redundant collective call
* information in the Analyzer code windows. If you are moving forward
* direction should be 1, if backward -1, otherwise the behavior is
* undefined.
*/
private Envelope skipRepeats(int direction) {
Envelope env = this.transitions.getCurrentTransition();
while (true) {
if (env == null) {
return null;
}
if (env.getLinenumber() == this.previousLeftIndex) {
if (direction == 1) {
env = this.transitions.getNextTransition(this.lockedRank);
} else {
env = this.transitions.getPreviousTransition(this.lockedRank);
}
} else {
break;
}
}
return env;
}
/**
* Updates the Analyzer view.
*
* @param sourceFile
* The source file resource to display in the Analyzer View's
* code windows.
* @param transitions
* The Transitions object holding holding all transitions per
* interleaving.
* @return void
*/
public void update(IFile sourceFile, Transitions transitions) {
if (transitions == null) {
clear();
return;
}
this.transitions = transitions;
this.numRanks = transitions.getNumRanks();
this.activeFile = sourceFile;
Display.getDefault().syncExec(this.analyzerUpdateThread);
}
/*
* Only changes the code windows content, does not change the highlighting.
* First time through, current Envelope is null, no update needed.
*/
private void updateCodeViewers() {
final String emptyString = ""; //$NON-NLS-1$
Envelope env = this.transitions.getCurrentTransition();
if (env != null) {
final String nextLeftFileInfo = env.getFilePath();
String nextRightFileInfo = emptyString;
env = this.transitions.getCurrentTransition().getMatch_envelope();
if (env != null) {
nextRightFileInfo = env.getFilePath();
}
final IPath nextLeftFilePath = new Path(nextLeftFileInfo);
final String nextLeftFileName = nextLeftFilePath.lastSegment();
String nextRightFileName = emptyString;
if (nextRightFileInfo.length() != 0) {
final IPath nextRightFilePath = new Path(nextRightFileInfo);
nextRightFileName = nextRightFilePath.lastSegment();
}
final boolean updateWindowContent = this.currLeftFile == null || this.currRightFile == null
|| !nextLeftFileName.equals(this.currLeftFile.getName())
|| !nextRightFileName.equals(this.currRightFile.getName()) || nextRightFileInfo.equals(emptyString);
if (updateWindowContent) {
final String projectName = this.activeFile.getProject().getName();
final IProject currentProject = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
// Get the next left and right source files for the code viewers
final IFile nextLeftSourceFile = GemUtilities.getSourceFile(nextLeftFileInfo, this.activeFile);
if (!nextLeftSourceFile.exists()) {
GemUtilities.refreshProject(currentProject);
}
IFile nextRightSourceFile = null;
final boolean isEmptyPath = nextRightFileInfo.length() == 0;
if (!isEmptyPath) {
nextRightSourceFile = GemUtilities.getSourceFile(nextRightFileInfo, this.activeFile);
if (!nextRightSourceFile.exists()) {
GemUtilities.refreshProject(currentProject);
}
}
// Now parse the files for new code viewer window content
parseSourceFile(nextLeftSourceFile, (isEmptyPath) ? null : nextRightSourceFile);
}
}
}
/**
* Calling this method will update the drop down so that it has the correct
* number of processes displayed. This method is used when another location
* changes the number of processes preference.
*
* @param none
* @return void
*/
public void updateDropDown() {
final Integer nprocs = GemPlugin.getDefault().getPreferenceStore().getInt(PreferenceConstants.GEM_PREF_NUMPROCS);
this.setNumProcsComboList.setText(nprocs.toString());
}
/*
* Goes to the First Transition and updates all relevant data
*/
private void updateFirstTransition(boolean update) {
// Goes to null
Envelope env = this.transitions.getFirstTransition(this.lockedRank);
env = this.transitions.getCurrentTransition();
if (env != null) {
this.previousLeftIndex = env.getLinenumber();
}
if (env == null) {
GemUtilities.showInformationDialog(Messages.GemAnalyzer_94);
return;
}
if (update) {
setButtonEnabledState();
updateCodeViewers();
displayEnvelopes(env);
updateSelectedLine(true);
this.transitionLabelIndex = 1;
setMessageLabelText();
}
}
/*
* Goes to the last transition and updates relevant information
*/
private void updateLastTransition() {
Envelope env = this.transitions.getLastTransition(this.lockedRank);
// stepToLastTransition puts us at the last iteration of Finalize
// other code always assumes we are on the first iteration of
// each call though, so here we go back to the first iteration
if (env.getFunctionName().equals("MPI_Finalize")) { //$NON-NLS-1$
while (true) {
env = this.transitions.getPreviousTransition(this.lockedRank);
if (env == null) {
GemUtilities.showInformationDialog(Messages.GemAnalyzer_95);
return;
}
// If there was only one finalize go back to it
if (!env.getFunctionName().equals("MPI_Finalize")) { //$NON-NLS-1$
env = this.transitions.getNextTransition(this.lockedRank);
break;
}
}
}
if (env == null) {
GemUtilities.showInformationDialog(Messages.GemAnalyzer_96);
return;
}
this.previousLeftIndex = env.getLinenumber();
setButtonEnabledState();
updateCodeViewers();
displayEnvelopes(env);
updateSelectedLine(true);
this.transitionLabelIndex = this.transitionLabelCount;
setMessageLabelText();
}
/*
* This method is used to highlight ALL lines involved in a call when the
* call is spread over multiple lines in the source code file.
*/
private void updateLineCount() {
final List leftList = this.leftViewer.getList();
final List rightList = this.rightViewer.getList();
final String emptyString = ""; //$NON-NLS-1$
String curr = emptyString;
this.leftLines = 1;
if (this.leftIndex <= 0) {
this.leftLines = 0;
return;
}
while (this.leftLines < this.leftIndex + 1) {
// Get current string
curr = emptyString;
for (int i = this.leftLines; i > 0; i--) {
curr += leftList.getItem(this.leftIndex - i);
curr = removeComments(curr);
}
if (this.parenthesesMatched(curr)) {
break;
}
this.leftLines++;
}
// Be sure to include the MPI Call
curr = curr.substring(0, curr.indexOf("(") - 1); //$NON-NLS-1$
if (curr.trim().length() == 0) {
this.leftLines++;
}
if (this.rightIndex == -1) {
return;
}
this.rightLines = 1;
while (this.rightLines < this.rightIndex + 1) {
// Get current string
curr = emptyString;
for (int i = this.rightLines; i > 0; i--) {
curr += rightList.getItem(this.rightIndex - i);
curr = removeComments(curr);
}
if (this.parenthesesMatched(curr)) {
break;
}
this.rightLines++;
}
curr = curr.substring(0, curr.indexOf("(") - 1); //$NON-NLS-1$
if (curr.trim().length() == 0) {
this.rightLines++;
}
}
/*
* Go to the next transition. Returns 1 if successful, -1 if there was no
* where to go.
*/
private int updateNextTransition(boolean update) {
int returnValue = 1;
Envelope env = this.transitions.getNextTransition(this.lockedRank);
if (env.isCollective() && this.lockedRank == -1) {
env = skipRepeats(1);
}
if (env == null) {
returnValue = -1;
} else {
this.previousLeftIndex = env.getLinenumber();
}
if (update) {
setButtonEnabledState();
updateCodeViewers();
displayEnvelopes(env);
updateSelectedLine(true);
this.transitionLabelIndex++;
setMessageLabelText();
}
return returnValue;
}
/*
* Goes to the previous transition and updates relevant data
*/
private void updatePreviousTransition() {
Envelope env = this.transitions.getPreviousTransition(this.lockedRank);
this.previousLeftIndex = env.getLinenumber();
// Go back until you reach the first call or beginning
if (env.isCollective() && this.lockedRank == -1) {
while (true) {
env = this.transitions.getPreviousTransition(this.lockedRank);
if (env == null) {
updateFirstTransition(true);
return;
}
if (env.getLinenumber() != this.previousLeftIndex) {
env = this.transitions.getNextTransition(this.lockedRank);
break;
}
}
}
this.previousLeftIndex = env.getLinenumber();
setButtonEnabledState();
updateCodeViewers();
displayEnvelopes(env);
updateSelectedLine(true);
this.transitionLabelIndex--;
setMessageLabelText();
}
/*
* Updates the relative position of the scroll bar for the list viewers in
* the code windows.
*/
private void updateScrollBars() {
final List leftList = this.leftViewer.getList();
final List rightList = this.rightViewer.getList();
try {
if (leftList != null && leftList.getSelection().length != 0) {
this.leftViewer.reveal(this.leftViewer.getElementAt(0));
this.leftViewer.reveal(this.leftViewer.getElementAt(this.leftIndex - 1));
}
if (rightList != null && rightList.getSelection().length != 0) {
this.rightViewer.reveal(this.rightViewer.getElementAt(0));
this.rightViewer.reveal(this.rightViewer.getElementAt(this.rightIndex - 1));
}
} catch (final Exception e) {
GemUtilities.logExceptionDetail(e);
}
}
/*
* Updates which line of the log file that is currently in focus.
*/
private void updateSelectedLine(Boolean scroll) {
updateCodeViewers();
// Deselect Everything
final List leftList = this.leftViewer.getList();
final List rightList = this.rightViewer.getList();
leftList.deselectAll();
rightList.deselectAll();
updateLineCount();
// Update left view (-1, 0-based)
for (int i = 0; i < this.leftLines; i++) {
leftList.select((this.leftIndex - i) - 1);
}
// Update right view (-1, 0-based)
for (int i = 0; i < this.rightLines; i++) {
rightList.select((this.rightIndex - i) - 1);
}
if (scroll) {
updateScrollBars();
}
}
// ONLY CALL WHEN YOU HAVE STARTED A NEW INTERLEAVING!!!
// As it searches it will never display the envelope
// displayEnvelope decides whether or not the final destination is displayed
private void updateTransitionLabels(boolean displayEnvelope) {
updateFirstTransition(false);
// because only incremented if next transition is also valid
this.transitionLabelCount = 1;
final Envelope env = this.transitions.getCurrentTransition();
int test = 1;
while (test == 1 && env != null) {
if (this.transitions.hasValidNextTransition(this.lockedRank)) {
this.transitionLabelCount++;
test = updateNextTransition(false);
} else {
break;
}
}
updateFirstTransition(displayEnvelope);
}
}