/******************************************************************************* * Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH and others. * 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 *******************************************************************************/ package de.gebit.integrity.eclipse.views; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.Serializable; import java.net.UnknownHostException; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.LinkedBlockingQueue; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.search.IJavaSearchConstants; import org.eclipse.jdt.core.search.IJavaSearchScope; import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jdt.core.search.SearchMatch; import org.eclipse.jdt.core.search.SearchParticipant; import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.core.search.SearchRequestor; import org.eclipse.jdt.ui.JavaUI; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; 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.dialogs.Dialog; import org.eclipse.jface.dialogs.InputDialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; 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.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; 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.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IActionBars; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.HyperlinkGroup; import org.eclipse.ui.forms.IFormColors; import org.eclipse.ui.forms.events.HyperlinkAdapter; import org.eclipse.ui.forms.events.HyperlinkEvent; import org.eclipse.ui.forms.widgets.Form; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Hyperlink; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.forms.widgets.Section; import org.eclipse.ui.part.ViewPart; import com.google.inject.Inject; import de.gebit.integrity.eclipse.Activator; import de.gebit.integrity.eclipse.actions.BreakpointAction; import de.gebit.integrity.eclipse.actions.JumpToLinkAction; import de.gebit.integrity.eclipse.controls.ProgressBar; import de.gebit.integrity.eclipse.running.TestActionConfigurationDialog; import de.gebit.integrity.eclipse.search.SetListSearch; import de.gebit.integrity.remoting.IntegrityRemotingConstants; import de.gebit.integrity.remoting.client.IntegrityRemotingClient; import de.gebit.integrity.remoting.client.IntegrityRemotingClientListener; import de.gebit.integrity.remoting.entities.setlist.SetList; import de.gebit.integrity.remoting.entities.setlist.SetListEntry; import de.gebit.integrity.remoting.entities.setlist.SetListEntryAttributeKeys; import de.gebit.integrity.remoting.entities.setlist.SetListEntryResultStates; import de.gebit.integrity.remoting.entities.setlist.SetListEntryTypes; import de.gebit.integrity.remoting.transport.Endpoint; import de.gebit.integrity.remoting.transport.enums.ExecutionCommands; import de.gebit.integrity.remoting.transport.enums.ExecutionStates; import de.gebit.integrity.remoting.transport.enums.TestRunnerCallbackMethods; import de.gebit.integrity.remoting.transport.messages.ExecutionStateMessage; import de.gebit.integrity.remoting.transport.messages.IntegrityRemotingVersionMessage; import de.gebit.integrity.remoting.transport.messages.SetListBaselineMessage; import de.gebit.integrity.ui.linking.IntegrityURLResolver; import de.gebit.integrity.utils.DateUtil; /** * The Integrity Test Runner Eclipse Plugin main view. * * @author Rene Schneider - initial API and implementation */ public class IntegrityTestRunnerView extends ViewPart { /** * The ID of the view as specified by the extension. */ public static final String ID = "de.gebit.integrity.eclipse.views.IntegrityTestRunnerView"; /** * The prefix for Integrity URLs. Required to add to links provided by {@link SetListEntry} instances, which don't * include the prefix to save some space. */ protected static final String INTEGRITY_URL_PREFIX = "integrity://"; /** * Height of the result text fields. */ private static final int RESULT_TEXTFIELD_HEIGHT = 60; /** * Height of larger tables in the result (variables, tabletests). */ private static final int RESULT_TABLE_HEIGHT = 230; /** * Height of each text field for extended results in text form. */ private static final int EXTENDED_RESULT_TEXTFIELD_HEIGHT = 60; /** * Space around images in extended result fields. */ private static final int EXTENDED_RESULT_IMAGE_SPACING = 6; /** * Space between each extended result field. */ private static final int EXTENDED_RESULT_SPACING = 5; /** * The "magic search term" for failed test/calls. */ private static final String MAGIC_SEARCH_TERM_FAILURES = "Tests/Calls with failures or exceptions"; /** * The Integrity URL resolver. */ @Inject private IntegrityURLResolver urlResolver; /** * The sash form used to split the screen in one half for the tree, and another for the details view. */ private SashForm sashForm; /** * The container for the tree. */ private Form treeContainer; /** * This container is placed below the tree and contains the UI elements of the tree search function. */ private Composite searchContainer; /** * The text input field for the tree search. */ private Text searchTextField; /** * A flag used to determine whether the text field just gained the focus. */ private boolean searchTextFieldJustGainedFocus; /** * The "search for error/exception" button for the tree search. */ private Button searchErrorButton; /** * The image for the {@link #searchErrorButton}. */ private Image searchErrorButtonEnabledImage; /** * The "previous result" button for the tree search. */ private Button searchLeftButton; /** * The image for the {@link #searchLeftButton}. */ private Image searchLeftButtonEnabledImage; /** * The "next result" button for the tree search. */ private Button searchRightButton; /** * The image for the {@link #searchRightButton}. */ private Image searchRightButtonEnabledImage; /** * The label denoting the current position and number of results during searching in the tree. */ private Label searchPositionLabel; /** * The test execution tree viewer. */ private TreeViewer treeViewer; /** * Status flag which is used to signal whether the tree viewer is currently scrolled by the user (using the vertical * scrollbar). */ private boolean treeViewerIsScrolledManually; /** * The drawer to colorize the test execution tree. */ private TestTreeContentDrawer viewerContentDrawer; /** * The container for the detail information. */ private Composite detailsContainer; /** * The scrolling form for the details. */ private ScrolledForm details; /** * The hyperlink group for the fixture link. */ private HyperlinkGroup fixtureLinkGroup; /** * The link that allows to jump to a specific fixture method. */ private Hyperlink fixtureLink; /** * The label displaying whether a command is executed on a fork. */ private Label forkLabel; /** * The container for the detail information groups. */ private Composite detailGroups; /** * The variable section. */ private Section variableSection; /** * The composite for the variable table. */ private Composite variableComposite; /** * The table of defined variables. */ private TableViewer variableTable; /** * The section for parameters. */ private Section parameterSection; /** * The composite for the parameter table. */ private Composite parameterComposite; /** * The table with all defined parameters. */ private TableViewer parameterTable; /** * The section that gets the result info. */ private Section resultSection; /** * The composite containing result UI elements. */ private Composite resultComposite; /** * The label for the first (actual) result. */ private Label resultLine1Name; /** * The text field for the first (actual) result. */ private Text resultLine1Text; /** * The container for the first (actual) result text field, which adds a color border around it. */ private Composite resultLine1Border; /** * The label for the second (expected) result. */ private Label resultLine2Name; /** * The text field for the second (expected) result. */ private Text resultLine2Text; /** * The container for the second (expected) result text field, which adds a color border around it. */ private Composite resultLine2Border; /** * The label for the third (extended result) result value. */ private Label resultLine3Name; /** * The container for the third (extended result) result value field. This one will be dynamically filled with text * fields or whatever else for displaying the varying number of extended result data objects. */ private Composite resultLine3Border; /** * The container for the result table. */ private Composite resultTableComposite; /** * The result table (for multi-result tests). */ private TableViewer resultTable; /** * The container for the variable update table. */ private Composite varUpdateTableComposite; /** * The variable update table (for calls with multi-variable updates). */ private TableViewer varUpdateTable; /** * The color for results of successful tests. */ private Color resultSuccessColor; /** * The color for results of failed tests. */ private Color resultFailureColor; /** * The neutral color for results. */ private Color resultNeutralColor; /** * The color of exception results. */ private Color resultExceptionColor; /** * The background color of the search container. */ private Color searchContainerColor; /** * The image used to display successful test results. */ private Image resultSuccessIconImage; /** * The image used to display failed test results. */ private Image resultFailureIconImage; /** * The image used to display exception test results. */ private Image resultExceptionIconImage; /** * The container to display the success icon. */ private Label resultSuccessIcon; /** * The container to display the failure icon. */ private Label resultFailureIcon; /** * The container to display the exception icon. */ private Label resultExceptionIcon; /** * The success count. */ private Label resultSuccessCountLabel; /** * The failure count. */ private Label resultFailureCountLabel; /** * The exception count. */ private Label resultExceptionCountLabel; /** * The progress bar displaying the test execution progress. */ private ProgressBar executionProgress; /** * The background color for table test results (successful tests). */ private Color resultTableSuccessColor; /** * The background color for failed table test results (failed tests). */ private Color resultTableFailureColor; /** * The action that connects to a test runner. */ private Action connectToTestRunnerAction; /** * The action that allows test continuation. */ private Action playAction; /** * The action that allows to pause a running test execution. */ private Action pauseAction; /** * The action for single-stepping test execution steps. */ private Action stepIntoAction; /** * The action for stepping over suite calls. */ private Action stepOverAction; /** * The action for deleting all existing breakpoints. */ private Action clearBreakpointsAction; /** * The action that runs a predefined launch config and connects to the test runner automatically. */ private Action executeTestAction; /** * The action that runs a predefined launch config in debug mode and connects to the test runner automatically. */ private Action executeDebugTestAction; /** * The action allowing to shut down a running test execution. */ private Action shutdownAction; /** * The action allowing to configure what is executed with {@link #executeTestAction}. */ private Action configureTestAction; /** * The action which expands all nodes one level further. */ private Action expandAllAction; /** * The action which collapses all nodes. */ private Action collapseAllAction; /** * The action which toggles the scroll lock function. */ private Action scrollLockAction; /** * Whether scroll lock is active. */ private boolean scrollLockActive; /** * The last level of node expansion. */ private int lastExpansionLevel; /** * The search engine instance used to search the setlist tree. */ private SetListSearch setListSearch; /** * The currently valid setlist tree search result. May be null if no search result is available. */ private List<SetListEntry> currentSearchResult; /** * The current position in the setlist tree search result. May be null if no current position is available. */ private Integer currentSearchResultPosition; /** * The remoting client instance. */ private IntegrityRemotingClient client; /** * The currently used set list instance. */ private SetList setList; /** * The set of breakpoints currently in use. */ private Set<Integer> breakpointSet = Collections.synchronizedSet(new HashSet<Integer>()); /** * These breakpoints are to be recreated after the next connect to a test runner. */ private Set<String> breakpointsToRecreate = Collections.synchronizedSet(new HashSet<String>()); /** * The launch configuration to run when the start button in the view is pressed. */ private ILaunchConfiguration launchConfiguration; /** * The constructor. */ public IntegrityTestRunnerView() { } /** * This is a callback that will allow us to create the viewer and initialize it. */ // SUPPRESS CHECKSTYLE MethodLength @Override public void createPartControl(final Composite aParent) { aParent.setLayout(new FillLayout()); final FormToolkit tempToolkit = new FormToolkit(aParent.getDisplay()); resultSuccessColor = new Color(Display.getCurrent(), 0, 94, 13); resultFailureColor = new Color(Display.getCurrent(), 190, 0, 0); resultNeutralColor = new Color(Display.getCurrent(), 0, 0, 0); resultExceptionColor = new Color(Display.getCurrent(), 204, 163, 0); resultTableSuccessColor = new Color(Display.getCurrent(), 205, 255, 222); resultTableFailureColor = new Color(Display.getCurrent(), 255, 130, 130); searchContainerColor = new Color(Display.getCurrent(), 220, 220, 220); resultSuccessIconImage = Activator.getImageDescriptor("icons/suite_success_big.png").createImage(); resultFailureIconImage = Activator.getImageDescriptor("icons/suite_failure_big.png").createImage(); resultExceptionIconImage = Activator.getImageDescriptor("icons/suite_exception_big.png").createImage(); sashForm = new SashForm(aParent, SWT.HORIZONTAL | SWT.SMOOTH); treeContainer = new Form(sashForm, SWT.NONE); treeContainer.setText("Not connected"); treeContainer.getBody().setLayout(new FormLayout()); treeContainer.setBackground(tempToolkit.getColors().getBackground()); treeContainer.setForeground(tempToolkit.getColors().getColor(IFormColors.TITLE)); treeContainer.setFont(JFaceResources.getHeaderFont()); tempToolkit.decorateFormHeading(treeContainer); executionProgress = new ProgressBar(treeContainer.getBody(), SWT.NONE); FormData tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 0); tempFormData.right = new FormAttachment(100, 0); tempFormData.top = new FormAttachment(0, 0); tempFormData.bottom = new FormAttachment(0, 16); executionProgress.setLayoutData(tempFormData); treeViewer = new TreeViewer(treeContainer.getBody(), SWT.VIRTUAL | SWT.H_SCROLL | SWT.V_SCROLL); treeViewer.setUseHashlookup(true); treeViewer.setContentProvider(new TestTreeContentProvider(treeViewer)); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 0); tempFormData.right = new FormAttachment(100, 0); tempFormData.top = new FormAttachment(executionProgress, 0); tempFormData.bottom = new FormAttachment(100, -18); treeViewer.getTree().setLayoutData(tempFormData); treeViewer.getTree().getVerticalBar().addSelectionListener(new SelectionListener() { @Override public void widgetDefaultSelected(SelectionEvent anEvent) { // nothing to do } @Override public void widgetSelected(SelectionEvent anEvent) { if (anEvent.detail == SWT.NONE) { treeViewerIsScrolledManually = false; } else if (anEvent.detail == SWT.DRAG) { treeViewerIsScrolledManually = true; } } }); searchContainer = new Composite(treeContainer.getBody(), SWT.NONE); searchContainer.setLayout(new FormLayout()); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 0); tempFormData.right = new FormAttachment(100, 0); tempFormData.top = new FormAttachment(treeViewer.getControl(), 0); tempFormData.height = 18; searchContainer.setLayoutData(tempFormData); searchContainer.setBackground(searchContainerColor); searchErrorButtonEnabledImage = Activator.getImageDescriptor("icons/search_failed_enabled.gif").createImage(); searchErrorButton = new Button(searchContainer, SWT.FLAT); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 0); tempFormData.width = 16; tempFormData.top = new FormAttachment(0, 2); tempFormData.height = 16; searchErrorButton.setImage(searchErrorButtonEnabledImage); searchErrorButton.setLayoutData(tempFormData); searchErrorButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event anEvent) { // repeated clicks shall just jump to the next result if (!performTreeSearchForFailures()) { jumpToNextSearchResult(); } } }); searchTextField = new Text(searchContainer, SWT.SINGLE); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 16); tempFormData.right = new FormAttachment(100, -100); tempFormData.top = new FormAttachment(0, 2); tempFormData.height = 16; searchTextField.setText(""); searchTextField.setLayoutData(tempFormData); searchTextField.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent anEvent) { performTreeSearch(); } }); searchTextField.addFocusListener(new FocusListener() { @Override public void focusLost(FocusEvent anEvent) { searchTextFieldJustGainedFocus = false; } @Override public void focusGained(FocusEvent anEvent) { searchTextFieldJustGainedFocus = true; } }); searchTextField.addMouseListener(new MouseListener() { @Override public void mouseUp(MouseEvent anEvent) { // Perform a full selection of all entered text if there is text AND the text field just gained the // focus. if (searchTextFieldJustGainedFocus && searchTextField.getText().length() > 0) { searchTextField.selectAll(); } searchTextFieldJustGainedFocus = false; } @Override public void mouseDown(MouseEvent anEvent) { // ignored } @Override public void mouseDoubleClick(MouseEvent anEvent) { // ignored } }); searchLeftButtonEnabledImage = Activator.getImageDescriptor("icons/search_prev_enabled.gif").createImage(); searchLeftButton = new Button(searchContainer, SWT.FLAT); tempFormData = new FormData(); tempFormData.left = new FormAttachment(searchTextField, 0); tempFormData.width = 16; tempFormData.top = new FormAttachment(0, 2); tempFormData.height = 16; searchLeftButton.setImage(searchLeftButtonEnabledImage); searchLeftButton.setLayoutData(tempFormData); searchLeftButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event anEvent) { jumpToPreviousSearchResult(); } }); searchRightButtonEnabledImage = Activator.getImageDescriptor("icons/search_next_enabled.gif").createImage(); searchRightButton = new Button(searchContainer, SWT.FLAT); tempFormData = new FormData(); tempFormData.left = new FormAttachment(searchLeftButton, 0); tempFormData.width = 16; tempFormData.top = new FormAttachment(0, 2); tempFormData.height = 16; searchRightButton.setImage(searchRightButtonEnabledImage); searchRightButton.setLayoutData(tempFormData); searchRightButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event anEvent) { jumpToNextSearchResult(); } }); searchPositionLabel = new Label(searchContainer, SWT.NONE); tempFormData = new FormData(); tempFormData.left = new FormAttachment(searchRightButton, 0); tempFormData.right = new FormAttachment(100, 0); tempFormData.top = new FormAttachment(0, 2); tempFormData.height = 16; searchPositionLabel.setBackground(searchContainerColor); searchPositionLabel.setLayoutData(tempFormData); searchPositionLabel.setText(""); searchPositionLabel.setAlignment(SWT.CENTER); detailsContainer = new Composite(sashForm, SWT.NONE); detailsContainer.setLayout(new FillLayout()); details = new ScrolledForm(detailsContainer, SWT.V_SCROLL | SWT.H_SCROLL); details.setExpandHorizontal(true); details.setExpandVertical(true); details.setBackground(tempToolkit.getColors().getBackground()); details.setForeground(tempToolkit.getColors().getColor(IFormColors.TITLE)); details.setFont(JFaceResources.getHeaderFont()); details.getBody().setLayout(new FormLayout()); tempToolkit.decorateFormHeading(details.getForm()); fixtureLinkGroup = new HyperlinkGroup(aParent.getDisplay()); fixtureLink = new Hyperlink(details.getBody(), SWT.NONE); fixtureLink.setBackground(details.getBackground()); fixtureLink.setText(""); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 5); tempFormData.right = new FormAttachment(100, -5); tempFormData.top = new FormAttachment(0, 3); tempFormData.height = 10; fixtureLink.setLayoutData(tempFormData); fixtureLink.addHyperlinkListener(new HyperlinkAdapter() { @Override public void linkActivated(HyperlinkEvent anEvent) { jumpToJavaMethod(anEvent.getLabel()); } }); fixtureLinkGroup.add(fixtureLink); forkLabel = new Label(details.getBody(), SWT.NONE); forkLabel.setText(""); forkLabel.setBackground(tempToolkit.getColors().getBackground()); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 5); tempFormData.right = new FormAttachment(100, -5); tempFormData.top = new FormAttachment(fixtureLink, 3); tempFormData.height = 14; forkLabel.setLayoutData(tempFormData); detailGroups = new Composite(details.getBody(), SWT.NONE); detailGroups.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); GridLayout tempGridLayout = new GridLayout(1, true); tempGridLayout.verticalSpacing = 10; detailGroups.setLayout(tempGridLayout); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 5); tempFormData.right = new FormAttachment(100, -5); tempFormData.top = new FormAttachment(forkLabel, 3); tempFormData.bottom = new FormAttachment(100, 0); detailGroups.setLayoutData(tempFormData); resultSection = tempToolkit.createSection(detailGroups, Section.TITLE_BAR | Section.EXPANDED); resultSection.setText("Result"); GridData tempGridData = new GridData(); tempGridData.minimumHeight = 10; tempGridData.horizontalIndent = 5; tempGridData.grabExcessHorizontalSpace = true; tempGridData.horizontalAlignment = GridData.FILL; resultSection.setLayoutData(tempGridData); resultSection.setLayout(new FillLayout()); resultComposite = tempToolkit.createComposite(resultSection); tempToolkit.paintBordersFor(resultComposite); resultSection.setClient(resultComposite); resultComposite.setLayout(new FormLayout()); parameterSection = tempToolkit.createSection(detailGroups, Section.TITLE_BAR | Section.EXPANDED); parameterSection.setText("Parameters"); tempGridData = new GridData(); tempGridData.minimumHeight = SWT.DEFAULT; tempGridData.heightHint = 130; tempGridData.horizontalIndent = 5; tempGridData.grabExcessHorizontalSpace = true; tempGridData.horizontalAlignment = GridData.FILL; parameterSection.setLayoutData(tempGridData); parameterSection.setLayout(new FillLayout()); parameterComposite = tempToolkit.createComposite(parameterSection); tempToolkit.paintBordersFor(parameterComposite); parameterSection.setClient(parameterComposite); parameterComposite.setLayout(new FillLayout()); parameterTable = new TableViewer(parameterComposite, SWT.FULL_SELECTION); parameterTable.setContentProvider(new ArrayContentProvider()); configureTable(parameterTable); variableSection = tempToolkit.createSection(detailGroups, Section.TITLE_BAR | Section.EXPANDED); variableSection.setText("Variable definitions"); tempGridData = new GridData(); tempGridData.minimumHeight = SWT.DEFAULT; tempGridData.heightHint = 150; tempGridData.horizontalIndent = 5; tempGridData.grabExcessHorizontalSpace = true; tempGridData.horizontalAlignment = GridData.FILL; variableSection.setLayoutData(tempGridData); variableSection.setLayout(new FillLayout()); variableComposite = tempToolkit.createComposite(variableSection); tempToolkit.paintBordersFor(variableComposite); variableSection.setClient(variableComposite); variableComposite.setLayout(new FillLayout()); variableTable = new TableViewer(variableComposite, SWT.FULL_SELECTION); variableTable.setContentProvider(new ArrayContentProvider()); configureTable(variableTable); resultComposite = tempToolkit.createComposite(resultSection); tempToolkit.paintBordersFor(resultComposite); resultSection.setClient(resultComposite); resultComposite.setLayout(new FormLayout()); resultTableComposite = tempToolkit.createComposite(resultComposite); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 5); tempFormData.right = new FormAttachment(100, -5); tempFormData.top = new FormAttachment(resultComposite, 10); tempFormData.bottom = new FormAttachment(resultTableComposite, RESULT_TABLE_HEIGHT, SWT.TOP); resultTableComposite.setLayoutData(tempFormData); resultTableComposite.setLayout(new FillLayout()); resultTable = new TableViewer(resultTableComposite, SWT.FULL_SELECTION); resultTable.setContentProvider(new ArrayContentProvider()); configureResultTable(resultTable); varUpdateTableComposite = tempToolkit.createComposite(resultComposite); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 5); tempFormData.right = new FormAttachment(100, -5); tempFormData.top = new FormAttachment(resultComposite, 10); tempFormData.bottom = new FormAttachment(varUpdateTableComposite, RESULT_TABLE_HEIGHT, SWT.TOP); varUpdateTableComposite.setLayoutData(tempFormData); varUpdateTableComposite.setLayout(new FillLayout()); varUpdateTable = new TableViewer(varUpdateTableComposite, SWT.FULL_SELECTION); varUpdateTable.setContentProvider(new ArrayContentProvider()); configureVarUpdateTable(varUpdateTable); resultLine1Name = new Label(resultComposite, SWT.WRAP); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 5); tempFormData.right = new FormAttachment(100, -5); tempFormData.top = new FormAttachment(0, 4); resultLine1Name.setLayoutData(tempFormData); resultLine1Border = new Composite(resultComposite, SWT.NONE); resultLine1Border.setForeground(resultNeutralColor); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 5); tempFormData.right = new FormAttachment(100, -5); tempFormData.top = new FormAttachment(resultLine1Name, 2, SWT.BOTTOM); tempFormData.bottom = new FormAttachment(resultLine1Border, RESULT_TEXTFIELD_HEIGHT, SWT.TOP); resultLine1Border.setLayoutData(tempFormData); FillLayout tempFill = new FillLayout(); tempFill.marginHeight = 1; tempFill.marginWidth = 1; resultLine1Border.setLayout(tempFill); configureTextFieldBorder(resultLine1Border); resultLine1Text = new Text(resultLine1Border, SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL); resultLine1Text.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); resultLine2Name = new Label(resultComposite, SWT.WRAP); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 5); tempFormData.right = new FormAttachment(100, -5); tempFormData.top = new FormAttachment(resultLine1Border, 6); resultLine2Name.setLayoutData(tempFormData); resultLine2Border = new Composite(resultComposite, SWT.NONE); resultLine2Border.setForeground(resultNeutralColor); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 5); tempFormData.right = new FormAttachment(100, -5); tempFormData.top = new FormAttachment(resultLine2Name, 2, SWT.BOTTOM); tempFormData.bottom = new FormAttachment(resultLine2Border, RESULT_TEXTFIELD_HEIGHT, SWT.TOP); resultLine2Border.setLayoutData(tempFormData); tempFill = new FillLayout(); tempFill.marginHeight = 1; tempFill.marginWidth = 1; resultLine2Border.setLayout(tempFill); configureTextFieldBorder(resultLine2Border); resultLine2Text = new Text(resultLine2Border, SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL); resultLine2Text.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); resultLine3Name = new Label(resultComposite, SWT.WRAP); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 5); tempFormData.right = new FormAttachment(100, -5); tempFormData.top = new FormAttachment(resultLine2Border, 6); resultLine3Name.setLayoutData(tempFormData); resultLine3Name.setText("Extended Result Data"); resultLine3Border = new Composite(resultComposite, SWT.NONE); resultLine3Border.setForeground(resultNeutralColor); tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 5); tempFormData.right = new FormAttachment(100, -5); tempFormData.top = new FormAttachment(resultLine3Name, 2, SWT.BOTTOM); tempFormData.bottom = new FormAttachment(resultLine3Border, 0, SWT.TOP); resultLine3Border.setLayoutData(tempFormData); resultLine3Border.setLayout(new FormLayout()); configureTextFieldBorder(resultLine3Border); resultFailureIcon = new Label(resultComposite, SWT.NONE); resultFailureIcon.setImage(resultFailureIconImage); tempFormData = new FormData(); tempFormData.left = new FormAttachment(50, -24); tempFormData.top = new FormAttachment(0, 10); tempFormData.width = 48; tempFormData.height = 48; resultFailureIcon.setLayoutData(tempFormData); resultSuccessIcon = new Label(resultComposite, SWT.NONE); resultSuccessIcon.setImage(resultSuccessIconImage); tempFormData = new FormData(); tempFormData.right = new FormAttachment(resultFailureIcon, -16); tempFormData.top = new FormAttachment(0, 10); tempFormData.width = 48; tempFormData.height = 48; resultSuccessIcon.setLayoutData(tempFormData); resultExceptionIcon = new Label(resultComposite, SWT.NONE); resultExceptionIcon.setImage(resultExceptionIconImage); tempFormData = new FormData(); tempFormData.left = new FormAttachment(resultFailureIcon, 16); tempFormData.top = new FormAttachment(0, 10); tempFormData.width = 48; tempFormData.height = 48; resultExceptionIcon.setLayoutData(tempFormData); resultSuccessCountLabel = new Label(resultComposite, SWT.CENTER); resultSuccessCountLabel.setText("123"); resultSuccessCountLabel.setForeground(resultSuccessColor); FontData[] tempFontData = resultSuccessCountLabel.getFont().getFontData(); tempFontData[0].setHeight(16); tempFontData[0].setStyle(SWT.BOLD); resultSuccessCountLabel.setFont(new Font(Display.getCurrent(), tempFontData[0])); tempFormData = new FormData(); tempFormData.left = new FormAttachment(resultSuccessIcon, -32, SWT.CENTER); tempFormData.top = new FormAttachment(resultSuccessIcon, 4); tempFormData.width = 64; tempFormData.height = 24; resultSuccessCountLabel.setLayoutData(tempFormData); resultFailureCountLabel = new Label(resultComposite, SWT.CENTER); resultFailureCountLabel.setText("123"); resultFailureCountLabel.setForeground(resultFailureColor); tempFontData = resultFailureCountLabel.getFont().getFontData(); tempFontData[0].setHeight(16); tempFontData[0].setStyle(SWT.BOLD); resultFailureCountLabel.setFont(new Font(Display.getCurrent(), tempFontData[0])); tempFormData = new FormData(); tempFormData.left = new FormAttachment(resultFailureIcon, -32, SWT.CENTER); tempFormData.top = new FormAttachment(resultFailureIcon, 4); tempFormData.width = 64; tempFormData.height = 24; resultFailureCountLabel.setLayoutData(tempFormData); resultExceptionCountLabel = new Label(resultComposite, SWT.CENTER); resultExceptionCountLabel.setText("123"); resultExceptionCountLabel.setForeground(resultExceptionColor); tempFontData = resultExceptionCountLabel.getFont().getFontData(); tempFontData[0].setHeight(16); tempFontData[0].setStyle(SWT.BOLD); resultExceptionCountLabel.setFont(new Font(Display.getCurrent(), tempFontData[0])); tempFormData = new FormData(); tempFormData.left = new FormAttachment(resultExceptionIcon, -32, SWT.CENTER); tempFormData.top = new FormAttachment(resultExceptionIcon, 4); tempFormData.width = 64; tempFormData.height = 24; resultExceptionCountLabel.setLayoutData(tempFormData); PlatformUI.getWorkbench().getHelpSystem().setHelp(treeViewer.getControl(), "de.gebit.integrity.eclipse.viewer"); attachTreeInteractionListeners(); makeActions(); hookContextMenu(); contributeToActionBars(); updateDetailPanel(null, null); } private void configureTable(final TableViewer aTable) { aTable.getTable().setHeaderVisible(true); aTable.getTable().setLinesVisible(true); TableViewerColumn tempColumn = new TableViewerColumn(aTable, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION); tempColumn.getColumn().setText("Name"); tempColumn.getColumn().setWidth(150); tempColumn.getColumn().setResizable(true); tempColumn.getColumn().setMoveable(false); tempColumn.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object anElement) { SetListEntry tempEntry = (SetListEntry) anElement; return (String) tempEntry.getAttribute(SetListEntryAttributeKeys.NAME); } }); tempColumn = new TableViewerColumn(aTable, SWT.NONE); tempColumn.getColumn().setText("Value"); tempColumn.getColumn().setWidth(150); tempColumn.getColumn().setResizable(true); tempColumn.getColumn().setMoveable(false); tempColumn.setLabelProvider(new ColumnLabelProvider() { @Override public void update(ViewerCell aCell) { SetListEntry tempEntry = (SetListEntry) aCell.getElement(); aCell.setText((String) tempEntry.getAttribute(SetListEntryAttributeKeys.VALUE)); } }); // Make the value column editable, mostly to be able to copy out results. See issue #77 tempColumn.setEditingSupport(new EditingSupport(aTable) { @Override protected void setValue(Object anElement, Object aValue) { // not supported, we don't really want to support editing of result values } @Override protected Object getValue(Object anElement) { SetListEntry tempEntry = (SetListEntry) anElement; return (String) tempEntry.getAttribute(SetListEntryAttributeKeys.VALUE); } @Override protected CellEditor getCellEditor(Object anElement) { return new TextCellEditor(aTable.getTable()); } @Override protected boolean canEdit(Object anElement) { return true; } }); } private void configureResultTable(final TableViewer aTable) { aTable.getTable().setHeaderVisible(true); aTable.getTable().setLinesVisible(true); TableViewerColumn tempColumn = new TableViewerColumn(aTable, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION); tempColumn.getColumn().setText("Name"); tempColumn.getColumn().setWidth(150); tempColumn.getColumn().setResizable(true); tempColumn.getColumn().setMoveable(false); tempColumn.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object anElement) { SetListEntry tempEntry = (SetListEntry) anElement; return (String) tempEntry.getAttribute(SetListEntryAttributeKeys.NAME); } @Override public Color getBackground(Object anElement) { SetListEntry tempEntry = (SetListEntry) anElement; Boolean tempSuccess = (Boolean) tempEntry.getAttribute(SetListEntryAttributeKeys.RESULT_SUCCESS_FLAG); if (tempSuccess == null) { return super.getBackground(anElement); } else if (tempSuccess) { return resultTableSuccessColor; } else { return resultTableFailureColor; } } }); tempColumn = new TableViewerColumn(aTable, SWT.NONE); tempColumn.getColumn().setText("Result"); tempColumn.getColumn().setWidth(150); tempColumn.getColumn().setResizable(true); tempColumn.getColumn().setMoveable(false); tempColumn.setLabelProvider(new ColumnLabelProvider() { @Override public void update(ViewerCell aCell) { SetListEntry tempEntry = (SetListEntry) aCell.getElement(); aCell.setText((String) tempEntry.getAttribute(SetListEntryAttributeKeys.VALUE)); } @Override public Color getBackground(Object anElement) { SetListEntry tempEntry = (SetListEntry) anElement; Boolean tempSuccess = (Boolean) tempEntry.getAttribute(SetListEntryAttributeKeys.RESULT_SUCCESS_FLAG); if (tempSuccess == null) { return super.getBackground(anElement); } else if (tempSuccess) { return resultTableSuccessColor; } else { return resultTableFailureColor; } } }); // Make the value column editable, mostly to be able to copy out results. See issue #77 tempColumn.setEditingSupport(new EditingSupport(aTable) { @Override protected void setValue(Object anElement, Object aValue) { // not supported, we don't really want to support editing of result values } @Override protected Object getValue(Object anElement) { SetListEntry tempEntry = (SetListEntry) anElement; return (String) tempEntry.getAttribute(SetListEntryAttributeKeys.VALUE); } @Override protected CellEditor getCellEditor(Object anElement) { return new TextCellEditor(aTable.getTable()); } @Override protected boolean canEdit(Object anElement) { return true; } }); tempColumn = new TableViewerColumn(aTable, SWT.NONE); tempColumn.getColumn().setText("Expected"); tempColumn.getColumn().setWidth(150); tempColumn.getColumn().setResizable(true); tempColumn.getColumn().setMoveable(false); tempColumn.setLabelProvider(new ColumnLabelProvider() { @Override public void update(ViewerCell aCell) { SetListEntry tempEntry = (SetListEntry) aCell.getElement(); aCell.setText((String) tempEntry.getAttribute(SetListEntryAttributeKeys.EXPECTED_RESULT)); } @Override public Color getBackground(Object anElement) { SetListEntry tempEntry = (SetListEntry) anElement; Boolean tempSuccess = (Boolean) tempEntry.getAttribute(SetListEntryAttributeKeys.RESULT_SUCCESS_FLAG); if (tempSuccess == null) { return super.getBackground(anElement); } else if (tempSuccess) { return resultTableSuccessColor; } else { return resultTableFailureColor; } } }); // Make the value column editable, mostly to be able to copy out results. See issue #77 tempColumn.setEditingSupport(new EditingSupport(aTable) { @Override protected void setValue(Object anElement, Object aValue) { // not supported, we don't really want to support editing of result values } @Override protected Object getValue(Object anElement) { SetListEntry tempEntry = (SetListEntry) anElement; return (String) tempEntry.getAttribute(SetListEntryAttributeKeys.EXPECTED_RESULT); } @Override protected CellEditor getCellEditor(Object anElement) { return new TextCellEditor(aTable.getTable()); } @Override protected boolean canEdit(Object anElement) { return true; } }); } private void configureVarUpdateTable(final TableViewer aTable) { aTable.getTable().setHeaderVisible(true); aTable.getTable().setLinesVisible(true); TableViewerColumn tempColumn = new TableViewerColumn(aTable, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION); tempColumn.getColumn().setText("Result"); tempColumn.getColumn().setWidth(150); tempColumn.getColumn().setResizable(true); tempColumn.getColumn().setMoveable(false); tempColumn.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object anElement) { SetListEntry tempEntry = (SetListEntry) anElement; return (String) tempEntry.getAttribute(SetListEntryAttributeKeys.PARAMETER_NAME); } }); tempColumn = new TableViewerColumn(aTable, SWT.NONE); tempColumn.getColumn().setText("Variable"); tempColumn.getColumn().setWidth(150); tempColumn.getColumn().setResizable(true); tempColumn.getColumn().setMoveable(false); tempColumn.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object anElement) { SetListEntry tempEntry = (SetListEntry) anElement; return (String) tempEntry.getAttribute(SetListEntryAttributeKeys.VARIABLE_NAME); } }); tempColumn = new TableViewerColumn(aTable, SWT.NONE); tempColumn.getColumn().setText("Value"); tempColumn.getColumn().setWidth(150); tempColumn.getColumn().setResizable(true); tempColumn.getColumn().setMoveable(false); tempColumn.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object anElement) { SetListEntry tempEntry = (SetListEntry) anElement; return (String) tempEntry.getAttribute(SetListEntryAttributeKeys.VALUE); } }); } private void configureTextFieldBorder(final Composite aBorder) { aBorder.addPaintListener(new PaintListener() { @Override public void paintControl(PaintEvent anEvent) { GC tempGC = anEvent.gc; tempGC.setForeground(aBorder.getForeground()); Rectangle tempRect = aBorder.getBounds(); tempGC.drawRectangle(0, 0, tempRect.width - 1, tempRect.height - 1); } }); } private void attachTreeInteractionListeners() { treeViewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent anEvent) { if (anEvent.getSelection().isEmpty()) { updateDetailPanel(null, null); } else { if (anEvent.getSelection() instanceof TreeSelection) { TreeSelection tempSelection = (TreeSelection) anEvent.getSelection(); if (tempSelection.getFirstElement() instanceof SetListEntry) { SetListEntry tempEntry = (SetListEntry) tempSelection.getFirstElement(); if (tempEntry.getType() == SetListEntryTypes.COMMENT) { updateDetailPanel(null, null); } else { updateDetailPanel(tempEntry, (ILabelProvider) ((TreeViewer) anEvent.getSource()).getLabelProvider()); } } } } } }); treeViewer.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(DoubleClickEvent anEvent) { if (anEvent.getSelection() instanceof TreeSelection) { TreeSelection tempSelection = (TreeSelection) anEvent.getSelection(); if (tempSelection.getFirstElement() instanceof SetListEntry) { SetListEntry tempEntry = (SetListEntry) tempSelection.getFirstElement(); String tempLink = (String) tempEntry.getAttribute(SetListEntryAttributeKeys.LINK); if (tempLink != null) { urlResolver.parseURL(INTEGRITY_URL_PREFIX + tempLink); } } } } }); } private void hookContextMenu() { MenuManager tempMenuMgr = new MenuManager("#PopupMenu"); tempMenuMgr.setRemoveAllWhenShown(true); tempMenuMgr.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager aManager) { IntegrityTestRunnerView.this.fillContextMenu(aManager); } }); Menu tempMenu = tempMenuMgr.createContextMenu(treeViewer.getControl()); treeViewer.getControl().setMenu(tempMenu); getSite().registerContextMenu(tempMenuMgr, treeViewer); } private void contributeToActionBars() { IActionBars tempBars = getViewSite().getActionBars(); fillLocalPullDown(tempBars.getMenuManager()); fillLocalToolBar(tempBars.getToolBarManager()); } private void fillLocalPullDown(IMenuManager aManager) { aManager.add(executeTestAction); aManager.add(executeDebugTestAction); aManager.add(shutdownAction); aManager.add(configureTestAction); aManager.add(new Separator()); aManager.add(playAction); aManager.add(pauseAction); aManager.add(stepIntoAction); aManager.add(new Separator()); aManager.add(connectToTestRunnerAction); } private void fillContextMenu(IMenuManager aManager) { if (treeViewer.getSelection().isEmpty()) { return; } if (treeViewer.getSelection() instanceof IStructuredSelection) { IStructuredSelection tempSelection = (IStructuredSelection) treeViewer.getSelection(); if (tempSelection.getFirstElement() instanceof SetListEntry) { final SetListEntry tempEntry = (SetListEntry) tempSelection.getFirstElement(); if (tempEntry.getType() == SetListEntryTypes.TEST || tempEntry.getType() == SetListEntryTypes.CALL) { if (breakpointSet.contains(tempEntry.getId())) { aManager.add(new BreakpointAction(tempEntry.getId(), "Remove Breakpoint", "Removes the breakpoint from the selected step.") { @Override public void run() { if (client == null || !client.isActive()) { // If not connected, add/remove breakpoint only from the recreation set String tempFullyQualifiedName = setList.getFullyQualifiedName(tempEntry); if (tempFullyQualifiedName != null) { breakpointsToRecreate.remove(tempFullyQualifiedName); breakpointSet.remove(tempEntry.getId()); } Display.getDefault().syncExec(new Runnable() { @Override public void run() { treeViewer.update(tempEntry, null); } }); } else { client.deleteBreakpoint(tempEntry.getId()); } } }); } else { aManager.add(new BreakpointAction(tempEntry.getId(), "Add Breakpoint", "Adds a breakpoint to the selected step.") { @Override public void run() { if (client == null || !client.isActive()) { // If not connected, add/remove breakpoint only from the recreation set String tempFullyQualifiedName = setList.getFullyQualifiedName(tempEntry); if (tempFullyQualifiedName != null) { breakpointsToRecreate.add(tempFullyQualifiedName); // However, we also need to insert it into this set in order to display it breakpointSet.add(tempEntry.getId()); } Display.getDefault().syncExec(new Runnable() { @Override public void run() { treeViewer.update(tempEntry, null); } }); } else { client.createBreakpoint(tempEntry.getId()); } } }); } } String tempLink = (String) tempEntry.getAttribute(SetListEntryAttributeKeys.LINK); if (tempLink != null) { aManager.add(new JumpToLinkAction(INTEGRITY_URL_PREFIX + tempLink, "Jump to Script", "Jumps to the position of this element in the test scripts.") { @Override public void run() { urlResolver.parseURL(getURL()); } }); } } } } private void fillLocalToolBar(IToolBarManager aManager) { // These are still in development... aManager.add(executeTestAction); aManager.add(executeDebugTestAction); aManager.add(shutdownAction); aManager.add(configureTestAction); aManager.add(new Separator()); aManager.add(expandAllAction); aManager.add(collapseAllAction); aManager.add(scrollLockAction); aManager.add(new Separator()); aManager.add(playAction); aManager.add(pauseAction); aManager.add(stepIntoAction); aManager.add(stepOverAction); aManager.add(clearBreakpointsAction); aManager.add(new Separator()); aManager.add(connectToTestRunnerAction); } private void makeActions() { connectToTestRunnerAction = new Action() { private String lastHostname = "localhost"; @Override public void run() { if (client == null || !client.isActive()) { InputDialog tempDialog = new InputDialog(getSite().getShell(), "Connect to test runner", "Please enter the hostname or IP address to connect to", lastHostname, null); if (tempDialog.open() == IStatus.OK && tempDialog.getValue() != null && tempDialog.getValue().length() > 0) { lastHostname = tempDialog.getValue(); String tempHost = lastHostname; int tempPort = IntegrityRemotingConstants.DEFAULT_PORT; if (tempHost.contains(":")) { try { tempPort = Integer.parseInt(tempHost.substring(tempHost.indexOf(':') + 1)); } catch (NumberFormatException exc) { showMessage("The port number given is illegal."); return; } catch (IndexOutOfBoundsException exc) { showMessage("No port number given."); return; } tempHost = tempHost.substring(0, tempHost.indexOf(':')); } connectToTestRunnerAsync(tempHost, tempPort); } } else { disconnectFromTestRunner(); } } }; playAction = new Action() { @Override public void run() { client.controlExecution(ExecutionCommands.RUN); updateStatus("Continuing test execution..."); } }; playAction.setText("Start or continue test execution"); playAction.setToolTipText("Continues test execution if currently paused."); playAction.setImageDescriptor(Activator.getImageDescriptor("icons/play_enabled.gif")); playAction.setDisabledImageDescriptor(Activator.getImageDescriptor("icons/play_disabled.gif")); pauseAction = new Action() { @Override public void run() { client.controlExecution(ExecutionCommands.PAUSE); updateStatus("Pausing test execution..."); } }; pauseAction.setText("Pause test execution"); pauseAction.setToolTipText("Interrupts test execution; the currently running test will be finished though."); pauseAction.setImageDescriptor(Activator.getImageDescriptor("icons/pause_enabled.gif")); pauseAction.setDisabledImageDescriptor(Activator.getImageDescriptor("icons/pause_disabled.gif")); stepIntoAction = new Action() { @Override public void run() { client.controlExecution(ExecutionCommands.STEP_INTO); updateStatus("Executing single step..."); } }; stepIntoAction.setText("Single step / step into"); stepIntoAction.setToolTipText("Executes a single test or call."); stepIntoAction.setImageDescriptor(Activator.getImageDescriptor("icons/stepinto_enabled.gif")); stepIntoAction.setDisabledImageDescriptor(Activator.getImageDescriptor("icons/stepinto_disabled.gif")); stepOverAction = new Action() { @Override @SuppressWarnings("unchecked") public void run() { SetListEntry tempTarget = null; SetListEntry tempCurrentSuite = setList.getParent(setList.getEntryInExecution()); if (tempCurrentSuite != null) { SetListEntry tempOuterSuite = setList.getParent(tempCurrentSuite); while (tempOuterSuite != null && tempTarget == null) { List<Integer> tempSetupStatements = (List<Integer>) tempOuterSuite .getAttribute(SetListEntryAttributeKeys.SETUP); List<Integer> tempSuiteStatements = (List<Integer>) tempOuterSuite .getAttribute(SetListEntryAttributeKeys.STATEMENTS); List<Integer> tempTeardownStatements = (List<Integer>) tempOuterSuite .getAttribute(SetListEntryAttributeKeys.TEARDOWN); List<Integer> tempAllStatements = new LinkedList<Integer>(); if (tempSetupStatements != null) { tempAllStatements.addAll(tempSetupStatements); } if (tempSuiteStatements != null) { tempAllStatements.addAll(tempSuiteStatements); } if (tempTeardownStatements != null) { tempAllStatements.addAll(tempTeardownStatements); } int tempPos = tempAllStatements.indexOf(tempCurrentSuite.getId()) + 1; if (tempPos == 0 || tempPos >= tempAllStatements.size()) { tempOuterSuite = setList.getParent(tempOuterSuite); } else { tempTarget = setList.resolveReference(tempAllStatements.get(tempPos)); } } } if (tempTarget != null) { while (tempTarget != null && tempTarget.getType() != SetListEntryTypes.CALL && tempTarget.getType() != SetListEntryTypes.TEST) { tempTarget = setList.resolveReference(tempTarget.getId() + 1); } } if (tempTarget != null) { client.createBreakpoint(tempTarget.getId()); client.controlExecution(ExecutionCommands.RUN); updateStatus("Executing until end of current suite..."); } else { client.controlExecution(ExecutionCommands.RUN); updateStatus("Continuing test execution..."); } } }; stepOverAction.setText("Single step / step into"); stepOverAction.setToolTipText("Places a breakpoint after the current suite call and continues execution."); stepOverAction.setImageDescriptor(Activator.getImageDescriptor("icons/stepover_enabled.gif")); stepOverAction.setDisabledImageDescriptor(Activator.getImageDescriptor("icons/stepover_disabled.gif")); clearBreakpointsAction = new Action() { @Override public void run() { breakpointsToRecreate.clear(); if (client != null && client.isActive()) { synchronized (breakpointSet) { for (Integer tempBreakpoint : breakpointSet) { client.deleteBreakpoint(tempBreakpoint); } } } else { // If offline, we "fake" removal of breakpoints so we can update the display Iterator<Integer> tempIterator = breakpointSet.iterator(); while (tempIterator.hasNext()) { final Integer tempReference = tempIterator.next(); tempIterator.remove(); Display.getDefault().asyncExec(new Runnable() { @Override public void run() { treeViewer.update(setList.resolveReference(tempReference), null); } }); } } } }; clearBreakpointsAction.setText("Clear breakpoints"); clearBreakpointsAction.setToolTipText("Clears all existing and/or saved breakpoints."); clearBreakpointsAction.setImageDescriptor(Activator.getImageDescriptor("icons/removeall_enabled.gif")); clearBreakpointsAction.setDisabledImageDescriptor(Activator.getImageDescriptor("icons/removeall_disabled.gif")); executeTestAction = new Action() { @Override public void run() { if (launchConfiguration != null) { try { executeTestAction.setEnabled(false); executeDebugTestAction.setEnabled(false); final ILaunch tempLaunch = launchConfiguration.launch(ILaunchManager.RUN_MODE, null); new AutoConnectThread(tempLaunch).start(); } catch (CoreException exc) { showException(exc); } } } }; executeTestAction.setText("Launch test application"); executeTestAction.setImageDescriptor(Activator.getImageDescriptor("icons/exec_enabled.gif")); executeDebugTestAction = new Action() { @Override public void run() { if (launchConfiguration != null) { try { executeTestAction.setEnabled(false); executeDebugTestAction.setEnabled(false); final ILaunch tempLaunch = launchConfiguration.launch(ILaunchManager.DEBUG_MODE, null); new AutoConnectThread(tempLaunch).start(); } catch (CoreException exc) { showException(exc); } } } }; executeDebugTestAction.setText("Launch test application (debug mode)"); executeDebugTestAction.setImageDescriptor(Activator.getImageDescriptor("icons/exec_debug_enabled.gif")); updateLaunchButtonState(); shutdownAction = new Action() { @Override public void run() { client.requestShutdown(); updateStatus("Requested immediate shutdown..."); }; }; shutdownAction.setText("Shutdown running test application"); shutdownAction.setToolTipText("Requests the test application to shut down immediately."); shutdownAction.setImageDescriptor(Activator.getImageDescriptor("icons/shutdown.gif")); shutdownAction.setEnabled(false); configureTestAction = new Action() { @Override public void run() { TestActionConfigurationDialog tempDialog = new TestActionConfigurationDialog(getSite().getShell(), launchConfiguration); if (tempDialog.open() == Dialog.OK) { launchConfiguration = tempDialog.getSelectedConfiguration(); updateLaunchButtonState(); } } }; configureTestAction.setText("Configure test application"); configureTestAction.setToolTipText("Configures the test run configuration(s) to launch."); configureTestAction.setImageDescriptor(Activator.getImageDescriptor("icons/exec_config_enabled.gif")); expandAllAction = new Action() { @Override public void run() { lastExpansionLevel++; ((TestTreeContentProvider) treeViewer.getContentProvider()).expandToLevel(lastExpansionLevel + 1); } }; expandAllAction.setText("Expand all (one level)"); expandAllAction.setToolTipText("Expands all nodes one level deeper (except table tests)."); expandAllAction.setImageDescriptor(Activator.getImageDescriptor("icons/expandall.gif")); collapseAllAction = new Action() { @Override public void run() { lastExpansionLevel = 0; treeViewer.collapseAll(); } }; collapseAllAction.setText("Collapse all"); collapseAllAction.setToolTipText("Collapses all nodes."); collapseAllAction.setImageDescriptor(Activator.getImageDescriptor("icons/collapseall.gif")); scrollLockAction = new Action("Toggle scroll lock", IAction.AS_CHECK_BOX) { @Override public void run() { scrollLockActive = isChecked(); }; }; scrollLockAction.setToolTipText("Toggles the scroll lock setting."); scrollLockAction.setImageDescriptor(Activator.getImageDescriptor("icons/scrolllock.gif")); updateActionStatus(null); } private void updateLaunchButtonState() { String tempText; boolean tempEnabled; if (launchConfiguration != null) { tempText = "Launches the test run configuration '" + launchConfiguration.getName() + "'"; tempEnabled = true; } else { tempText = "Launches the test run configuration"; tempEnabled = false; } executeTestAction.setEnabled(tempEnabled); executeTestAction.setToolTipText(tempText); executeDebugTestAction.setEnabled(tempEnabled); executeDebugTestAction.setToolTipText(tempText + " (debug mode)"); } private boolean isConnected() { return (client != null && client.isActive()); } private void updateActionStatus(final ExecutionStates anExecutionState) { Runnable tempRunnable = updateActionStatusRunnable(anExecutionState); if (Display.getCurrent() != null) { Display.getCurrent().syncExec(tempRunnable); } else { Display.getDefault().asyncExec(tempRunnable); } } private Runnable updateActionStatusRunnable(final ExecutionStates anExecutionState) { return new Runnable() { @Override public void run() { if (!isConnected()) { connectToTestRunnerAction.setText("Connect to test runner"); connectToTestRunnerAction.setToolTipText("Connects to a local or remote test runner"); connectToTestRunnerAction.setImageDescriptor(Activator.getImageDescriptor("icons/connect.gif")); playAction.setEnabled(false); pauseAction.setEnabled(false); stepIntoAction.setEnabled(false); stepOverAction.setEnabled(false); shutdownAction.setEnabled(false); } else { connectToTestRunnerAction.setText("Disconnect from test runner"); connectToTestRunnerAction .setToolTipText("Disconnects the client from the currently connected test runner"); connectToTestRunnerAction.setImageDescriptor(Activator.getImageDescriptor("icons/disconnect.gif")); if (anExecutionState == null) { playAction.setEnabled(false); pauseAction.setEnabled(false); stepIntoAction.setEnabled(false); stepOverAction.setEnabled(false); shutdownAction.setEnabled(false); } else { shutdownAction.setEnabled(true); switch (anExecutionState) { case BLOCKED: playAction.setEnabled(true); pauseAction.setEnabled(false); stepIntoAction.setEnabled(true); stepOverAction.setEnabled(true); updateStatusRunnable("Waiting for execution start").run(); break; case PAUSED: playAction.setEnabled(true); pauseAction.setEnabled(false); stepIntoAction.setEnabled(true); stepOverAction.setEnabled(true); updateStatusRunnable( determineIntermediateTestResultStatusString("Paused test execution (", ")")).run(); break; case RUNNING: playAction.setEnabled(false); pauseAction.setEnabled(true); stepIntoAction.setEnabled(false); stepOverAction.setEnabled(false); updateStatusRunnable(determineIntermediateTestResultStatusString("Running tests: ", "")) .run(); break; case FINALIZING: playAction.setEnabled(false); pauseAction.setEnabled(false); stepIntoAction.setEnabled(false); stepOverAction.setEnabled(false); updateStatusRunnable( determineIntermediateTestResultStatusString("Finalizing test results (", ")")) .run(); break; case ENDED: playAction.setEnabled(false); pauseAction.setEnabled(false); stepIntoAction.setEnabled(false); stepOverAction.setEnabled(false); updateStatusRunnable( determineIntermediateTestResultStatusString("Test execution finished (", ")")) .run(); break; default: break; } } } } }; } private String determineIntermediateTestResultStatusString(String aPrefix, String aSuffix) { StringBuilder tempBuilder = new StringBuilder(aPrefix); if (setList != null) { tempBuilder.append(setList.getNumberOfEntriesInResultState(SetListEntryResultStates.SUCCESSFUL)); tempBuilder.append(" successful, "); tempBuilder.append(setList.getNumberOfEntriesInResultState(SetListEntryResultStates.FAILED)); tempBuilder.append(" failures, "); tempBuilder.append(setList.getNumberOfEntriesInResultState(SetListEntryResultStates.EXCEPTION)); tempBuilder.append(" exceptions"); } tempBuilder.append(aSuffix); return tempBuilder.toString(); } private void hideResultComposite(Composite aComposite) { aComposite.setVisible(false); ((FormData) aComposite.getLayoutData()).bottom.offset = 0; } private void showResultComposite(Composite aComposite, int aHeight) { aComposite.setVisible(true); ((FormData) aComposite.getLayoutData()).bottom.offset = aHeight; } // SUPPRESS CHECKSTYLE MethodLength private void updateDetailPanel(SetListEntry anEntry, ILabelProvider aProvider) { fixtureLink.setVisible(false); forkLabel.setVisible(false); hideResultComposite(resultTableComposite); hideResultComposite(varUpdateTableComposite); resultLine1Name.setVisible(false); hideResultComposite(resultLine1Border); resultLine1Text.setText(""); resultLine2Name.setVisible(false); hideResultComposite(resultLine2Border); resultLine3Name.setVisible(false); resultLine3Border.setVisible(false); for (Control tempChild : resultLine3Border.getChildren()) { tempChild.dispose(); } resultSuccessIcon.setVisible(false); resultFailureIcon.setVisible(false); resultExceptionIcon.setVisible(false); resultSuccessCountLabel.setVisible(false); resultFailureCountLabel.setVisible(false); resultExceptionCountLabel.setVisible(false); if (anEntry == null) { details.setText("Details"); details.setImage(null); } else { details.setImage(aProvider.getImage(anEntry)); if (anEntry.getType() == SetListEntryTypes.SUITE) { details.setText((String) anEntry.getAttribute(SetListEntryAttributeKeys.NAME)); } else { details.setText((String) anEntry.getAttribute(SetListEntryAttributeKeys.DESCRIPTION)); if (anEntry.getType() == SetListEntryTypes.RESULT) { fixtureLink.setText( (String) setList.getParent(anEntry).getAttribute(SetListEntryAttributeKeys.FIXTURE)); } else { fixtureLink.setText((String) anEntry.getAttribute(SetListEntryAttributeKeys.FIXTURE)); } fixtureLink.setVisible(true); } String[] tempForkName = setList.getForkExecutingEntry(anEntry); if (tempForkName != null) { String tempLabelText = "executed on fork '" + tempForkName[0] + "'"; if (tempForkName[1] != null) { tempLabelText += " (" + tempForkName[1] + ")"; } forkLabel.setText(tempLabelText); forkLabel.setVisible(true); } List<SetListEntry> tempVariables = setList.resolveReferences(anEntry, SetListEntryAttributeKeys.VARIABLE_DEFINITIONS); if (tempVariables.size() > 0) { variableTable.setInput(tempVariables); } else { variableTable.setInput(null); } List<SetListEntry> tempParameters = setList.resolveReferences(anEntry, SetListEntryAttributeKeys.PARAMETERS); if (tempParameters.size() > 0) { parameterTable.setInput(tempParameters); } else { parameterTable.setInput(null); } SetListEntry tempResultEntry = null; if (anEntry.getType() == SetListEntryTypes.TABLETEST) { // High-level table test summary information is stored in the // tabletest entry itself tempResultEntry = anEntry; } else if (anEntry.getType() == SetListEntryTypes.RESULT) { // result entries are results by themselves ;-) tempResultEntry = anEntry; } else { tempResultEntry = setList.resolveReferences(anEntry, SetListEntryAttributeKeys.RESULT).get(0); } if (tempResultEntry != null) { switch (anEntry.getType()) { case SUITE: case TABLETEST: if (tempResultEntry.getAttribute(SetListEntryAttributeKeys.SUCCESS_COUNT) != null) { int tempSuccessCount = (Integer) tempResultEntry .getAttribute(SetListEntryAttributeKeys.SUCCESS_COUNT); int tempFailureCount = (Integer) tempResultEntry .getAttribute(SetListEntryAttributeKeys.FAILURE_COUNT); int tempExceptionCount = (Integer) tempResultEntry .getAttribute(SetListEntryAttributeKeys.TEST_EXCEPTION_COUNT) + (Integer) tempResultEntry .getAttribute(SetListEntryAttributeKeys.CALL_EXCEPTION_COUNT); resultSuccessCountLabel.setText(Integer.toString(tempSuccessCount)); resultFailureCountLabel.setText(Integer.toString(tempFailureCount)); resultExceptionCountLabel.setText(Integer.toString(tempExceptionCount)); resultSuccessIcon.setVisible(true); resultFailureIcon.setVisible(true); resultExceptionIcon.setVisible(true); resultSuccessCountLabel.setVisible(true); resultFailureCountLabel.setVisible(true); resultExceptionCountLabel.setVisible(true); } else { resultLine1Name.setText("No results available - please run the tests first."); resultLine1Name.setVisible(true); } break; case TEST: case RESULT: @SuppressWarnings("unchecked") List<SetListEntry> tempComparisonEntries = setList.resolveReferences( ((List<Integer>) tempResultEntry.getAttribute(SetListEntryAttributeKeys.COMPARISONS))); if (tempComparisonEntries.size() > 1) { resultTable.setInput(tempComparisonEntries); showResultComposite(resultTableComposite, RESULT_TABLE_HEIGHT); } else { SetListEntry tempComparisonEntry = tempComparisonEntries.get(0); resultLine2Name.setText("Expected value: "); resultLine2Text.setText( (String) tempComparisonEntry.getAttribute(SetListEntryAttributeKeys.EXPECTED_RESULT)); resultLine2Border.setForeground(resultNeutralColor); resultLine2Name.setVisible(true); showResultComposite(resultLine2Border, RESULT_TEXTFIELD_HEIGHT); if (tempResultEntry.getAttribute(SetListEntryAttributeKeys.EXCEPTION) != null) { resultLine1Name.setText("Exception occurred while running the test fixture:"); resultLine1Text.setText( (String) tempResultEntry.getAttribute(SetListEntryAttributeKeys.EXCEPTION)); resultLine1Border.setForeground(resultExceptionColor); resultLine1Name.setVisible(true); showResultComposite(resultLine1Border, RESULT_TEXTFIELD_HEIGHT); } else { if (tempComparisonEntry .getAttribute(SetListEntryAttributeKeys.RESULT_SUCCESS_FLAG) != null) { resultLine1Name.setText("Result returned by the test fixture: "); String tempResult = (String) tempComparisonEntry .getAttribute(SetListEntryAttributeKeys.VALUE); resultLine1Text.setText(tempResult == null ? "null" : tempResult); if (tempComparisonEntry .getAttribute(SetListEntryAttributeKeys.RESULT_SUCCESS_FLAG) != null) { if (Boolean.TRUE.equals(tempComparisonEntry .getAttribute(SetListEntryAttributeKeys.RESULT_SUCCESS_FLAG))) { resultLine1Border.setForeground(resultSuccessColor); } else { resultLine1Border.setForeground(resultFailureColor); } } showResultComposite(resultLine1Border, RESULT_TEXTFIELD_HEIGHT); } else { resultLine1Name.setText("No result available - please run the tests first."); } resultLine1Name.setVisible(true); } } break; case CALL: if (tempResultEntry.getAttribute(SetListEntryAttributeKeys.RESULT_SUCCESS_FLAG) != null) { if (tempResultEntry.getAttribute(SetListEntryAttributeKeys.EXCEPTION) != null) { resultLine1Name.setText("Exception occurred while running the test fixture:"); resultLine1Text.setText( (String) tempResultEntry.getAttribute(SetListEntryAttributeKeys.EXCEPTION)); resultLine1Border.setForeground(resultExceptionColor); showResultComposite(resultLine1Border, RESULT_TEXTFIELD_HEIGHT); } else { List<SetListEntry> tempVarUpdates = setList.resolveReferences(tempResultEntry, SetListEntryAttributeKeys.VARIABLE_UPDATES); if (tempVarUpdates.size() == 1) { String tempResultValue = (String) tempVarUpdates.get(0) .getAttribute(SetListEntryAttributeKeys.VALUE); String tempTargetVariable = (String) tempVarUpdates.get(0) .getAttribute(SetListEntryAttributeKeys.VARIABLE_NAME); if (tempTargetVariable != null) { tempResultValue += " ➔ " + tempTargetVariable; } resultLine1Name.setText("Result returned by the fixture:"); resultLine1Text.setText(tempResultValue); resultLine1Border.setForeground(resultNeutralColor); showResultComposite(resultLine1Border, RESULT_TEXTFIELD_HEIGHT); } else if (tempVarUpdates.size() > 1) { varUpdateTable.setInput(tempVarUpdates); showResultComposite(varUpdateTableComposite, RESULT_TABLE_HEIGHT); } else { resultLine1Name.setText("No result returned by the fixture."); } } } else { resultLine1Name.setText("No result available - please run the tests first."); } resultLine1Name.setVisible(true); break; case VARIABLE_ASSIGNMENT: List<SetListEntry> tempVarUpdates = setList.resolveReferences(tempResultEntry, SetListEntryAttributeKeys.VARIABLE_UPDATES); if (tempVarUpdates.size() == 1) { String tempResultValue = (String) tempVarUpdates.get(0) .getAttribute(SetListEntryAttributeKeys.VALUE); String tempTargetVariable = (String) tempVarUpdates.get(0) .getAttribute(SetListEntryAttributeKeys.VARIABLE_NAME); if (tempTargetVariable != null) { tempResultValue += " ➔ " + tempTargetVariable; } resultLine1Name.setText("Assigned variable value:"); resultLine1Text.setText(tempResultValue); resultLine1Border.setForeground(resultNeutralColor); showResultComposite(resultLine1Border, RESULT_TEXTFIELD_HEIGHT); } else if (tempVarUpdates.size() > 1) { varUpdateTable.setInput(tempVarUpdates); showResultComposite(varUpdateTableComposite, RESULT_TABLE_HEIGHT); } else { resultLine1Name.setText("No variables assigned."); } resultLine1Name.setVisible(true); break; default: break; } } Object[] tempExtendedResults = (Object[]) anEntry .getAttribute(SetListEntryAttributeKeys.EXTENDED_RESULT_DATA); if (tempExtendedResults != null && tempExtendedResults.length > 0) { int tempSize = 0; for (Object tempExtendedResultArray : tempExtendedResults) { if (tempSize > 0) { tempSize += EXTENDED_RESULT_SPACING; } tempSize += createExtendedResultContainer(resultLine3Border, tempSize + 1, (Object[]) tempExtendedResultArray); } resultLine3Name.setVisible(true); resultLine3Border.setVisible(true); showResultComposite(resultLine3Border, tempSize + 2); resultComposite.layout(true, true); } else { hideResultComposite(resultLine3Border); } } details.layout(true, true); details.reflow(false); details.redraw(); } private int createExtendedResultContainer(Composite aTargetComposite, int aStartingPosition, Object[] someExtendedResultData) { String tempTitle = (String) someExtendedResultData[0]; Object tempData = someExtendedResultData[1]; int tempTitleSize = 0; int tempContentSize = 0; Control tempContentContainer = null; // First, create the title. if (tempTitle != null) { tempTitleSize = 18; Composite tempResultTitleContainer = new Composite(aTargetComposite, SWT.NONE); tempResultTitleContainer.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK)); FormData tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 1); tempFormData.right = new FormAttachment(100, 1); tempFormData.top = new FormAttachment(aTargetComposite, aStartingPosition); tempFormData.bottom = new FormAttachment(aTargetComposite, aStartingPosition + tempTitleSize, SWT.BOTTOM); tempResultTitleContainer.setLayoutData(tempFormData); FillLayout tempFillLayout = new FillLayout(); tempFillLayout.marginWidth = 2; tempFillLayout.marginHeight = 2; tempResultTitleContainer.setLayout(tempFillLayout); tempResultTitleContainer.setVisible(true); Label tempResultTitleField = new Label(tempResultTitleContainer, SWT.BOLD); tempResultTitleField.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); tempResultTitleField.setText(tempTitle); tempResultTitleField.setVisible(true); } // Now, see what we have to display, create the appropriate control and set everything up if (tempData instanceof String) { // This covers strings and hypertext strings Text tempResultTextField = new Text(aTargetComposite, SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL); tempResultTextField.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); tempResultTextField.setText((String) tempData); tempContentSize = EXTENDED_RESULT_TEXTFIELD_HEIGHT; tempContentContainer = tempResultTextField; } else if (tempData instanceof byte[]) { // Covers images Image tempImage = new Image(Display.getCurrent(), new ByteArrayInputStream((byte[]) tempData)); Label tempImageLabel = new Label(aTargetComposite, SWT.NONE); tempImageLabel.setImage(tempImage); tempImageLabel.setAlignment(SWT.CENTER); tempContentSize = tempImage.getBounds().height + EXTENDED_RESULT_IMAGE_SPACING; tempContentContainer = tempImageLabel; } // Finally, place the control onto its parent if (tempContentContainer != null) { FormData tempFormData = new FormData(); tempFormData.left = new FormAttachment(0, 1); tempFormData.right = new FormAttachment(100, -1); tempFormData.top = new FormAttachment(aTargetComposite, aStartingPosition + tempTitleSize); tempFormData.bottom = new FormAttachment(aTargetComposite, aStartingPosition + tempTitleSize + tempContentSize, SWT.BOTTOM); tempContentContainer.setLayoutData(tempFormData); tempContentContainer.setVisible(true); } return tempTitleSize + tempContentSize; } private void showMessage(final String aMessage) { Runnable tempRunnable = new Runnable() { @Override public void run() { MessageDialog.openInformation(treeViewer.getControl().getShell(), "Integrity Test Control", aMessage); } }; Display.getDefault().asyncExec(tempRunnable); } private void showException(final Exception anException) { Runnable tempRunnable = new Runnable() { @Override public void run() { MessageDialog.openError(treeViewer.getControl().getShell(), "Integrity Test Runner", anException.getLocalizedMessage()); } }; Display.getDefault().asyncExec(tempRunnable); } private void updateStatus(final String aStatus) { Display.getDefault().asyncExec(updateStatusRunnable(aStatus)); } private Runnable updateStatusRunnable(final String aStatus) { return new Runnable() { @Override public void run() { treeContainer.setText(aStatus); } }; } /** * Passing the focus request to the viewer's control. */ @Override public void setFocus() { treeViewer.getControl().setFocus(); } private void connectToTestRunnerAsync(final String aHost, final int aPort) { new Thread("Test Runner Connect Thread") { @Override public void run() { try { connectToTestRunner(aHost, aPort); return; } catch (UnknownHostException exc) { showMessage("Target host name '" + aHost + "' could not be resolved."); } catch (IOException exc) { showMessage("Error while connecting to '" + aHost + "': " + exc.getMessage()); } } }.start(); } private void connectToTestRunner(final String aHost, final int aPort) throws UnknownHostException, IOException { updateStatus("Connecting..."); boolean tempSuccessful = false; try { client = new IntegrityRemotingClient(aHost, aPort, new RemotingListener(), null); tempSuccessful = true; updateStatus("Connected, downloading test data..."); } finally { if (!tempSuccessful) { updateStatus("Not connected"); } } } private void disconnectFromTestRunner() { client.close(); client = null; updateActionStatus(null); updateStatus("Not connected"); } private void jumpToJavaMethod(String aJavaClassAndMethod) { Matcher tempMatcher = Pattern.compile("([^#]*)\\.([^#]*)#(.*)").matcher(aJavaClassAndMethod); if (tempMatcher.matches()) { final String tempPackageName = tempMatcher.group(1); String tempClassName = tempMatcher.group(2); final String tempMethodName = tempMatcher.group(3); SearchPattern tempPattern = SearchPattern.createPattern(tempClassName, IJavaSearchConstants.TYPE, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE); IJavaSearchScope tempScope = SearchEngine.createWorkspaceScope(); SearchRequestor tempRequestor = new SearchRequestor() { @Override public void acceptSearchMatch(SearchMatch aMatch) throws CoreException { IType tempType = (IType) aMatch.getElement(); if (tempPackageName.equals(tempType.getPackageFragment().getElementName())) { for (IMethod tempMethod : tempType.getMethods()) { if (tempMethodName.equals(tempMethod.getElementName())) { JavaUI.openInEditor(tempMethod); return; } } } } }; SearchEngine tempSearchEngine = new SearchEngine(); try { tempSearchEngine.search(tempPattern, new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() }, tempScope, tempRequestor, null); } catch (CoreException exc) { exc.printStackTrace(); } } } private void performTreeSearch() { String tempSearchQuery = searchTextField.getText(); if (tempSearchQuery.length() < 3) { clearTreeSearchResult(); } else { prepareTreeSearch(); currentSearchResultPosition = null; if (MAGIC_SEARCH_TERM_FAILURES.equals(tempSearchQuery)) { currentSearchResult = setListSearch.findUnsuccessfulEntries(false); } else { currentSearchResult = setListSearch.findEntries(tempSearchQuery); } if (currentSearchResult.size() > 0) { currentSearchResultPosition = 0; jumpToCurrentSearchResult(); } updateTreeSearchLabel(); } } private boolean performTreeSearchForFailures() { if (MAGIC_SEARCH_TERM_FAILURES.equals(searchTextField.getText())) { return false; } searchTextField.setText(MAGIC_SEARCH_TERM_FAILURES); performTreeSearch(); return true; } private void prepareTreeSearch() { if (setListSearch == null) { setListSearch = new SetListSearch(setList); } } private void clearTreeSearchResult() { currentSearchResultPosition = null; currentSearchResult = null; searchPositionLabel.setText(""); } private void updateTreeSearchLabel() { if (currentSearchResult == null) { searchPositionLabel.setText(""); } else { if (currentSearchResult.size() == 0) { searchPositionLabel.setText("no matches"); } else { String tempCurrentPosition = (currentSearchResultPosition == null ? "?" : Integer.toString(currentSearchResultPosition + 1)); searchPositionLabel.setText(tempCurrentPosition + " / " + currentSearchResult.size()); } } } private void jumpToPreviousSearchResult() { if (currentSearchResult != null && currentSearchResultPosition != null) { currentSearchResultPosition--; if (currentSearchResultPosition <= 0) { currentSearchResultPosition = 0; } jumpToCurrentSearchResult(); } } private void jumpToNextSearchResult() { if (currentSearchResult != null && currentSearchResultPosition != null) { currentSearchResultPosition++; if (currentSearchResultPosition >= currentSearchResult.size()) { currentSearchResultPosition = 0; } jumpToCurrentSearchResult(); } } private void jumpToCurrentSearchResult() { if (currentSearchResultPosition != null && currentSearchResult != null && currentSearchResultPosition >= 0 && currentSearchResultPosition < currentSearchResult.size()) { SetListEntry tempEntry = currentSearchResult.get(currentSearchResultPosition); treeViewer.setSelection(new StructuredSelection(tempEntry)); updateTreeSearchLabel(); } } private void updateSetList(SetList aNewSetList) { setList = aNewSetList; breakpointSet.clear(); setListSearch = null; Display.getDefault().asyncExec(new Runnable() { @Override public void run() { searchTextField.setText(""); treeViewer.setSelection(null); treeViewer.setInput(null); executionProgress.setSetList(setList); executionProgress.redraw(); // the following will automatically dispose the old provider! treeViewer.setLabelProvider( new TestTreeLabelProvider(setList, breakpointSet, Display.getCurrent(), treeViewer)); // the drawer must be manually disposed if (viewerContentDrawer != null) { viewerContentDrawer.dispose(treeViewer.getTree()); } viewerContentDrawer = new TestTreeContentDrawer(setList, breakpointSet, Display.getCurrent()); viewerContentDrawer.attachToTree(treeViewer.getTree()); treeViewer.setInput(setList); ((TestTreeContentProvider) treeViewer.getContentProvider()).expandToLevel(lastExpansionLevel + 1); updateStatus("Connected and ready"); } }); } private abstract class StatusUpdateRunnable implements Runnable { /** * Whether this update may be skipped to improve performance. */ private boolean skippable; StatusUpdateRunnable(boolean aSkippable) { skippable = aSkippable; } public boolean isSkippable() { return skippable; } } private class RemotingListener implements IntegrityRemotingClientListener { /** * Used to measure the connected time. */ private long connectionTimestamp; @Override public void onConnectionSuccessful(IntegrityRemotingVersionMessage aRemoteVersion, Endpoint anEndpoint) { // request set list baseline and execution state anEndpoint.sendMessage(new SetListBaselineMessage(null)); anEndpoint.sendMessage(new ExecutionStateMessage(null)); updateActionStatus(client.getExecutionState()); connectionTimestamp = System.nanoTime(); // Initiate the status update timer. See issue #80 and timer javadoc documentation. statusUpdateTimer = new Timer("Integrity Test Runner Status Update Timer"); statusUpdateTimerTask = new TimerTask() { private Timer associatedTimer = statusUpdateTimer; @Override public void run() { StatusUpdateRunnable tempRunnable = statusUpdateQueue.poll(); if (tempRunnable == null) { if (statusUpdateTimerTask != this) { associatedTimer.cancel(); } return; } StatusUpdateRunnable tempLastRunnable; do { tempLastRunnable = tempRunnable; if (!tempLastRunnable.isSkippable()) { break; } tempRunnable = statusUpdateQueue.poll(); } while (tempRunnable != null); Display.getDefault().syncExec(tempLastRunnable); } }; statusUpdateTimer.scheduleAtFixedRate(statusUpdateTimerTask, 0, STATUS_UPDATE_INTERVAL); } @Override public void onVersionMismatch(IntegrityRemotingVersionMessage aRemoteVersion, Endpoint anEndpoint) { // TODO Auto-generated method stub } @Override public void onBaselineReceived(SetList aSetList, Endpoint anEndpoint) { updateSetList(aSetList); // Recreate breakpoints, if possible synchronized (breakpointsToRecreate) { for (String tempBreakpointName : breakpointsToRecreate) { SetListEntry tempEntry = aSetList.findEntryByFullyQualifiedName(tempBreakpointName); if (tempEntry != null) { client.createBreakpoint(tempEntry.getId()); } } } } @Override public void onExecutionStateUpdate(final ExecutionStates aState, Endpoint anEndpoint) { statusUpdateQueue.add(new StatusUpdateRunnable(false) { @Override public void run() { updateActionStatusRunnable(aState).run(); } }); } @Override public void onConnectionLost(Endpoint anEndpoint) { client = null; statusUpdateQueue.add(new StatusUpdateRunnable(false) { @Override public void run() { executionProgress.redraw(); updateActionStatusRunnable(null).run(); updateStatusRunnable(determineIntermediateTestResultStatusString("Test Runner disconnected (", ") after " + DateUtil.convertNanosecondTimespanToHumanReadableFormat( System.nanoTime() - connectionTimestamp, true, false))).run(); } }); statusUpdateTimer = null; statusUpdateTimerTask = null; } /** * This queue is used to queue asynchronous status display update requests (status text and execution progress * bar). Certain updates can be skipped for better performance. See issue #80. */ private LinkedBlockingQueue<StatusUpdateRunnable> statusUpdateQueue = new LinkedBlockingQueue<StatusUpdateRunnable>(); /** * The timer used to process status update queue entries. Gets started and stopped with Integrity test * executions. */ private Timer statusUpdateTimer; /** * The task used by the {@link #statusUpdateTimer}. */ private TimerTask statusUpdateTimerTask; /** * The interval in milliseconds with which the status shall be updated. Maximum number of updates per second can * directly be calculated from this. */ private static final int STATUS_UPDATE_INTERVAL = 200; @Override public void onSetListUpdate(final SetListEntry[] someUpdatedEntries, final Integer anEntryInExecutionReference, Endpoint anEndpoint) { setList.integrateUpdates(someUpdatedEntries); if (anEntryInExecutionReference != null) { setList.setEntryInExecutionReference(anEntryInExecutionReference); } Display.getDefault().syncExec(new Runnable() { @Override public void run() { for (SetListEntry tempEntry : someUpdatedEntries) { switch (tempEntry.getType()) { case RESULT: treeViewer.update(setList.getParent(tempEntry), null); treeViewer.update(tempEntry, null); break; default: treeViewer.update(tempEntry, null); } } if (anEntryInExecutionReference != null) { List<SetListEntry> tempExecutionPath = setList.getEntriesInExecution(); for (SetListEntry tempEntry : tempExecutionPath) { treeViewer.update(tempEntry, null); } if (!scrollLockActive && !treeViewerIsScrolledManually && tempExecutionPath.size() > 0) { treeViewer.reveal(tempExecutionPath.get(0)); } } } }); final String tempStatusUpdate = determineIntermediateTestResultStatusString("Running tests: ", ""); statusUpdateQueue.add(new StatusUpdateRunnable(true) { @Override public void run() { executionProgress.redraw(); updateStatusRunnable(tempStatusUpdate).run(); } }); } @Override public void onConfirmCreateBreakpoint(final Integer anEntryReference, Endpoint anEndpoint) { if (anEntryReference == null) { // We are only interested in real breakpoints, not pause-at-next-instructions. return; } breakpointSet.add(anEntryReference); String tempFullyQualifiedName = setList.getFullyQualifiedName(anEntryReference); if (tempFullyQualifiedName != null) { breakpointsToRecreate.add(tempFullyQualifiedName); } Display.getDefault().asyncExec(new Runnable() { @Override public void run() { treeViewer.update(setList.resolveReference(anEntryReference), null); } }); } @Override public void onConfirmRemoveBreakpoint(final Integer anEntryReference, Endpoint anEndpoint) { if (anEntryReference == null) { // We are only interested in real breakpoints, not pause-at-next-instructions. return; } breakpointSet.remove(anEntryReference); String tempFullyQualifiedName = setList.getFullyQualifiedName(anEntryReference); if (tempFullyQualifiedName != null) { breakpointsToRecreate.remove(tempFullyQualifiedName); } Display.getDefault().asyncExec(new Runnable() { @Override public void run() { treeViewer.update(setList.resolveReference(anEntryReference), null); } }); } @Override public void onTestRunnerCallbackMessageRetrieval(String aCallbackClassName, TestRunnerCallbackMethods aMethod, Serializable[] someData) { // not used in this context } @Override public void onVariableUpdateRetrieval(String aVariableName, Serializable aValue) { // not used in this context } @Override public void onAbortExecution(String anAbortExecutionMessage, String anAbortExecutionStackTrace) { // not used in this context } } private class AutoConnectThread extends Thread { /** * The launch to supervise. */ private ILaunch launch; /** * Creates a new instance. */ AutoConnectThread(ILaunch aLaunch) { super("Integrity Autoconnect Thread"); launch = aLaunch; } @Override public void run() { boolean tempSuccess = false; while (!launch.isTerminated()) { try { if (!tempSuccess && !isConnected()) { // try to connect at least once connectToTestRunner("localhost", IntegrityRemotingConstants.DEFAULT_PORT); tempSuccess = true; } else { // Now we'll wait until the launch has terminated try { Thread.sleep(1000); } catch (InterruptedException exc) { // don't care } } } catch (UnknownHostException exc) { // exceptions are expected, that just means we need to retry } catch (IOException exc) { // exceptions are expected, that just means we need to retry } } executeTestAction.setEnabled(true); executeDebugTestAction.setEnabled(true); }; } }