/*******************************************************************************
* Copyright Technophobia Ltd 2012
*
* This file is part of the Substeps Eclipse Plugin.
*
* The Substeps Eclipse Plugin is free software: you can redistribute it and/or modify
* it under the terms of the Eclipse Public License v1.0.
*
* The Substeps Eclipse Plugin is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Eclipse Public License for more details.
*
* You should have received a copy of the Eclipse Public License
* along with the Substeps Eclipse Plugin. If not, see <http://www.eclipse.org/legal/epl-v10.html>.
******************************************************************************/
package com.technophobia.substeps.junit.ui;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.ViewForm;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorActionBarContributor;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.part.EditorActionBarContributor;
import org.eclipse.ui.part.PageSwitcher;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.eclipse.ui.progress.UIJob;
import org.eclipse.ui.statushandlers.StatusManager;
import com.technophobia.eclipse.transformer.Callback;
import com.technophobia.eclipse.ui.Notifier;
import com.technophobia.eclipse.ui.NotifyingUiUpdater;
import com.technophobia.eclipse.ui.Renderer;
import com.technophobia.eclipse.ui.UiUpdater;
import com.technophobia.eclipse.ui.job.StoppableJob;
import com.technophobia.eclipse.ui.part.DefaultVisibilityPartMonitor;
import com.technophobia.eclipse.ui.part.PartMonitor;
import com.technophobia.eclipse.ui.render.OneTimeRenderUpdater;
import com.technophobia.eclipse.ui.view.ViewLayout;
import com.technophobia.eclipse.ui.view.ViewOrientation;
import com.technophobia.substeps.FeatureRunnerPlugin;
import com.technophobia.substeps.junit.action.ActivateOnErrorAction;
import com.technophobia.substeps.junit.action.FailuresOnlyFilterAction;
import com.technophobia.substeps.junit.action.RerunFailedFirstAction;
import com.technophobia.substeps.junit.action.RerunLastTestAction;
import com.technophobia.substeps.junit.action.ScrollLockAction;
import com.technophobia.substeps.junit.action.ShowNextFailureAction;
import com.technophobia.substeps.junit.action.ShowPreviousFailureAction;
import com.technophobia.substeps.junit.action.ShowTestHierarchyAction;
import com.technophobia.substeps.junit.action.ShowTimeAction;
import com.technophobia.substeps.junit.action.StopTestAction;
import com.technophobia.substeps.junit.action.SubstepsCopyAction;
import com.technophobia.substeps.junit.action.SubstepsPasteAction;
import com.technophobia.substeps.junit.action.ToggleOrientationAction;
import com.technophobia.substeps.junit.ui.component.FeatureViewer;
import com.technophobia.substeps.junit.ui.component.ProgressBar;
import com.technophobia.substeps.junit.ui.component.SubstepsCounterPanel;
import com.technophobia.substeps.junit.ui.handler.SubstepsHandlerServiceManager;
import com.technophobia.substeps.junit.ui.help.SubstepsHelpContextIds;
import com.technophobia.substeps.junit.ui.image.ProgressImages;
import com.technophobia.substeps.junit.ui.job.ProcessRunningJob;
import com.technophobia.substeps.junit.ui.job.UpdateJobManager;
import com.technophobia.substeps.junit.ui.job.UpdateSubstepsUIJob;
import com.technophobia.substeps.junit.ui.progress.SubstepsProgressBar;
import com.technophobia.substeps.junit.ui.testsession.JunitTestResultsView;
import com.technophobia.substeps.junit.ui.testsession.TestResultsView;
import com.technophobia.substeps.junit.ui.viewhistory.RunnerViewHistory;
import com.technophobia.substeps.model.SubstepsSessionListener;
import com.technophobia.substeps.model.structure.Status;
import com.technophobia.substeps.model.structure.SubstepsTestElement;
import com.technophobia.substeps.model.structure.SubstepsTestLeafElement;
import com.technophobia.substeps.preferences.PreferencesConstants;
import com.technophobia.substeps.supplier.Supplier;
public class SubstepsFeatureTestRunnerViewPart extends ViewPart implements UpdateJobManager, Notifier<Runnable>,
Callback, IPropertyListener {
public static final String NAME = "com.technophobia.substeps.runner.SubstepsResultView";
private static final IMarker FAMILY_SUBSTEPS_FEATURE_RUN = new IMarker() {
// No-op
};
private static final String RERUN_LAST_COMMAND = "com.technophobia.substeps.junit.rerunLast"; //$NON-NLS-1$
private static final String RERUN_FAILED_FIRST_COMMAND = "com.technophobia.substeps.junit.rerunFailedFirst"; //$NON-NLS-1$
private static final String TAG_SCROLL = "scroll";
private static final String TAG_RATIO = "ratio";
private static final String TAG_ORIENTATION = "orientation";
private static final String TAG_FAILURES_ONLY = "failuresOnly";
private static final String TAG_LAYOUT = "layout";
private static final String TAG_SHOW_TIME = "time";
private static final int REFRESH_INTERVAL = 200;
private SubstepsIconProvider iconProvider;
private ProgressImages progressImages;
private IMemento memento;
private SashForm sashForm;
private ScrollLockAction scrollLockAction;
private ToggleOrientationAction[] toggleOrientationActions;
private Action showTestHierarchyAction;
private ViewOrientation orientation = ViewOrientation.VIEW_ORIENTATION_AUTOMATIC;
private ViewOrientation currentOrientation;
private ViewLayout layout = ViewLayout.HIERARCHICAL;
private Action failuresOnlyFilterAction;
private Action showTimeAction;
private UIJob updateJob;
private StoppableJob substepsIsRunningJob;
private Supplier<Boolean> disposedChecker;
private UiUpdater uiUpdater;
private UiUpdater testCounterUpdater;
private UiUpdater viewTitleUiUpdater;
// private UiUpdater toolbarUiUpdater;
// private UiUpdater statusMessageUpdater;
private final NotifyingUiUpdater<String> infoMessageUpdater;
private FailureTrace failureTrace;
private Supplier<TestRunStats> testRunStatsSupplier;
private SubstepsRunSessionManager sessionManager;
private SubstepsRunSessionListener testRunSessionListener;
private SubstepsHandlerServiceManager handlerServiceManager;
private TestResultsView testResultsView;
private FeatureViewer testViewer;
private PartMonitor partMonitor;
private com.technophobia.substeps.junit.ui.component.CounterPanel counterPanel;
private Clipboard clipboard;
private DirtyListener dirtyListener;
private IMenuListener viewMenuListener;
private boolean autoScroll = false;
private boolean disposed = false;
private boolean showOnErrorOnly = false;
private Composite parent;
private RunnerViewHistory viewHistory;
private SubstepsActionManager actionManager;
private Composite counterComposite;
private ProgressBar progressBar;
private Image originalViewImage;
private Image viewImage;
public SubstepsFeatureTestRunnerViewPart() {
this.disposedChecker = new Supplier<Boolean>() {
@Override
public Boolean get() {
return Boolean.valueOf(isDisposed());
}
};
this.iconProvider = new SubstepsIconProvider(new ImageDescriptorImageLoader(), new ImageDescriptorLoader());
this.infoMessageUpdater = new OneTimeRenderUpdater<String>(new Renderer<String>() {
@Override
public void render(final String t) {
setContentDescription(t);
}
});
}
@Override
public void init(final IViewSite site, final IMemento m) throws PartInitException {
super.init(site, m);
this.memento = m;
this.partMonitor = new DefaultVisibilityPartMonitor(getSite());
this.dirtyListener = new JavaCoreDirtyListener();
this.currentOrientation = ViewOrientation.VIEW_ORIENTATION_AUTOMATIC;
this.testRunStatsSupplier = testRunStatsSupplier();
final IWorkbenchSiteProgressService progressService = getProgressService();
if (progressService != null) {
progressService.showBusyForFamily(FAMILY_SUBSTEPS_FEATURE_RUN);
}
}
private SubstepsActionManager createActionManager() {
final Action stopAction = new StopTestAction(runSessionSupplier(), infoMessageUpdater, iconProvider);
final Action copyAction = new SubstepsCopyAction(getSite().getShell(), failureTrace, clipboard);
final Action rerunFailedFirstAction = new RerunFailedFirstAction(RERUN_FAILED_FIRST_COMMAND,
new FailedTestFirstTestRelauncher(runSessionSupplier(), getSite().getShell(), infoMessageUpdater),
iconProvider);
final Action rerunLastTestAction = new RerunLastTestAction(RERUN_LAST_COMMAND, new TestRelauncher(
runSessionSupplier(), getSite().getShell(), infoMessageUpdater), iconProvider);
final Action nextAction = new ShowNextFailureAction(testViewer, iconProvider);
final Action prevAction = new ShowPreviousFailureAction(testViewer, iconProvider);
return new SubstepsActionManager(stopAction, copyAction, rerunFailedFirstAction, rerunLastTestAction,
nextAction, prevAction);
}
@Override
public void saveState(final IMemento m) {
if (sashForm == null && m != null) { // Keep the old state;
m.putMemento(this.memento);
return;
}
decorateMemento(m);
}
public void setAutoScroll(final boolean scroll) {
autoScroll = scroll;
}
public boolean isAutoScroll() {
return autoScroll;
}
@Override
public synchronized void dispose() {
disposed = true;
if (testRunSessionListener != null)
FeatureRunnerPlugin.instance().getModel().removeTestRunSessionListener(testRunSessionListener);
handlerServiceManager.deactivateHandlers();
sessionManager.setActiveState(null);
if (progressImages != null)
progressImages.dispose();
getViewSite().getPage().removePartListener(partMonitor);
disposeImages();
if (clipboard != null)
clipboard.dispose();
if (viewMenuListener != null) {
getViewSite().getActionBars().getMenuManager().removeMenuListener(viewMenuListener);
}
dirtyListener.removeDirtyListener();
}
@Override
public void setFocus() {
if (testViewer != null)
testViewer.getTestViewerControl().setFocus();
}
@Override
public void createPartControl(final Composite parentComposite) {
this.parent = parentComposite;
addResizeListener(parentComposite);
this.clipboard = new Clipboard(parentComposite.getDisplay());
this.testResultsView = new JunitTestResultsView(getSite().getWorkbenchWindow());
final GridLayout gridLayout = new GridLayout();
gridLayout.marginWidth = 0;
gridLayout.marginHeight = 0;
parentComposite.setLayout(gridLayout);
final UiUpdater tooltipUpdater = new TooltipUpdater(tooltipNotifier());
final UiUpdater statusMessageUpdater = new StatusMessageUiUpdater(getViewSite());
this.counterComposite = createProgressCountPanel(parentComposite);
final SashForm sash = createSashForm(parentComposite);
this.actionManager = createActionManager();
this.sessionManager = new SubstepsRunSessionManager(disposedSashFormChecker(), testViewer, tooltipUpdater,
infoMessageUpdater, viewTitleUiUpdater, statusMessageUpdater, failureTrace, testResultsView,
actionManager, this, testSessionListenerSupplier());
this.handlerServiceManager = new SubstepsHandlerServiceManager((IHandlerService) getSite().getWorkbenchWindow()
.getService(IHandlerService.class));
this.counterComposite.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
sash.setLayoutData(new GridData(GridData.FILL_BOTH));
final IActionBars actionBars = getViewSite().getActionBars();
final Action copyAction = new SubstepsCopyAction(parentComposite.getShell(), failureTrace, clipboard);
copyAction.setActionDefinitionId(ActionFactory.COPY.getCommandId());
actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction);
final Action pasteAction = new SubstepsPasteAction(parentComposite.getShell(), clipboard);
pasteAction.setActionDefinitionId(ActionFactory.PASTE.getCommandId());
actionBars.setGlobalActionHandler(ActionFactory.PASTE.getId(), pasteAction);
this.viewHistory = new RunnerViewHistory(sessionManager, parentComposite.getShell(), sessionManager,
new ImageDescriptorLoader(), iconProvider, pasteAction);
configureToolBar();
initPageSwitcher();
addDropAdapter();
originalViewImage = getTitleImage();
progressImages = new ProgressImages(iconProvider);
PlatformUI.getWorkbench().getHelpSystem().setHelp(parentComposite, SubstepsHelpContextIds.RESULTS_VIEW);
getViewSite().getPage().addPartListener(partMonitor);
setFilterAndLayout(false, ViewLayout.HIERARCHICAL.value());
setShowExecutionTime(true);
if (memento != null) {
restoreLayoutState(memento);
}
memento = null;
testRunSessionListener = new DefaultSubstepsRunSessionListener(displaySupplier(), siteSupplier(),
infoMessageUpdater, sessionManager);
FeatureRunnerPlugin.instance().getModel().addTestRunSessionListener(testRunSessionListener);
// always show youngest test run in view. simulate "sessionAdded" event
// to do that
final List<SubstepsRunSession> testRunSessions = FeatureRunnerPlugin.instance().getModel().getTestRunSessions();
if (!testRunSessions.isEmpty()) {
testRunSessionListener.sessionAdded(testRunSessions.get(0));
}
this.testCounterUpdater = new TestCounterUiUpdater(testRunStatsSupplier, counterPanel, progressBar);
this.viewTitleUiUpdater = new ViewTitleUiUpdater(partMonitor, sessionManager, testRunStatsSupplier,
iconProvider, originalViewImage, progressImages, this);
this.uiUpdater = new SubstepsFeatureUiUpdater(disposedChecker, infoMessageUpdater, testCounterUpdater,
viewTitleUiUpdater, testViewer, testRunStatsSupplier, actionManager);
}
private void decorateMemento(final IMemento m) {
m.putString(TAG_SCROLL, scrollLockAction.isChecked() ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
final int weigths[] = sashForm.getWeights();
final int ratio = (weigths[0] * 1000) / (weigths[0] + weigths[1]);
m.putInteger(TAG_RATIO, ratio);
m.putInteger(TAG_ORIENTATION, orientation.value());
m.putString(TAG_FAILURES_ONLY, failuresOnlyFilterAction.isChecked() ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
m.putInteger(TAG_LAYOUT, layout.value());
m.putString(TAG_SHOW_TIME, showTimeAction.isChecked() ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
public void startUpdateJobs() {
postSyncProcessChanges();
if (updateJob != null) {
return;
}
substepsIsRunningJob = new ProcessRunningJob(
SubstepsFeatureMessages.SubstepsFeatureTestRunnerViewPart_wrapperJobName, FAMILY_SUBSTEPS_FEATURE_RUN,
Job.getJobManager().newLock());
// acquire lock while a test run is running
// the lock is released when the test run terminates
// the wrapper job will wait on this lock.
getProgressService().schedule((Job) substepsIsRunningJob);
updateJob = new UpdateSubstepsUIJob(SubstepsFeatureMessages.SubstepsFeatureTestRunnerViewPart_jobName,
REFRESH_INTERVAL, uiUpdater);
updateJob.schedule(REFRESH_INTERVAL);
}
@Override
public void stopUpdateJobs() {
if (updateJob != null) {
((StoppableJob) updateJob).stop();
updateJob = null;
}
if (substepsIsRunningJob != null && substepsIsRunningJob != null) {
substepsIsRunningJob.stop();
substepsIsRunningJob = null;
}
postSyncProcessChanges();
}
@Override
public void notify(final Runnable r) {
if (!isDisposed())
getDisplay().syncExec(r);
}
@Override
public Runnable currentValue() {
return null;
}
@Override
public void callback() {
warnOfContentChange();
}
@Override
public void propertyChanged(final Object source, final int propId) {
firePropertyChange(propId);
}
private IWorkbenchSiteProgressService getProgressService() {
final IWorkbenchSiteProgressService siteService = (IWorkbenchSiteProgressService) getSite().getAdapter(
IWorkbenchSiteProgressService.class);
if (siteService != null) {
return siteService;
}
return null;
}
private void restoreLayoutState(final IMemento m) {
final Integer ratio = m.getInteger(TAG_RATIO);
if (ratio != null)
sashForm.setWeights(new int[] { ratio.intValue(), 1000 - ratio.intValue() });
final Integer newOrientation = m.getInteger(TAG_ORIENTATION);
if (newOrientation != null)
orientation = ViewOrientation.forValue(newOrientation.intValue());
computeOrientation();
final String scrollLock = m.getString(TAG_SCROLL);
if (scrollLock != null) {
scrollLockAction.setChecked(scrollLock.equals("true")); //$NON-NLS-1$
setAutoScroll(!scrollLockAction.isChecked());
}
final Integer l = m.getInteger(TAG_LAYOUT);
ViewLayout layoutValue = ViewLayout.HIERARCHICAL;
if (layout != null && l != null)
layoutValue = ViewLayout.forValue(l.intValue());
final String failuresOnly = m.getString(TAG_FAILURES_ONLY);
boolean showFailuresOnly = false;
if (failuresOnly != null)
showFailuresOnly = failuresOnly.equals("true"); //$NON-NLS-1$
final String time = m.getString(TAG_SHOW_TIME);
boolean showTime = true;
if (time != null)
showTime = time.equals("true"); //$NON-NLS-1$
setFilterAndLayout(showFailuresOnly, layoutValue.value());
setShowExecutionTime(showTime);
}
private void disposeImages() {
iconProvider.dispose();
}
private SashForm createSashForm(final Composite parentComposite) {
sashForm = new SashForm(parentComposite, SWT.VERTICAL);
final ViewForm top = new ViewForm(sashForm, SWT.NONE);
this.testViewer = new FeatureViewer(top, siteSupplier(), failedTestNotifier(), testRerunner(),
autoScrollNotifier(), testKindDisplayNameSupplier(), iconProvider);
final Composite empty = new Composite(top, SWT.NONE);
empty.setLayout(new Layout() {
@Override
protected Point computeSize(final Composite composite, final int wHint, final int hHint,
final boolean flushCache) {
return new Point(1, 1); // (0, 0) does not work with
// super-intelligent ViewForm
}
@Override
protected void layout(final Composite composite, final boolean flushCache) {
// No-op
}
});
top.setTopLeft(empty); // makes ViewForm draw the horizontal separator
// line ...
top.setContent(testViewer.getTestViewerControl());
final ViewForm bottom = new ViewForm(sashForm, SWT.NONE);
final CLabel label = new CLabel(bottom, SWT.NONE);
label.setText(SubstepsFeatureMessages.SubstepsFeatureTestRunnerViewPart_label_failure);
label.setImage(iconProvider.imageFor(SubstepsFailureTraceIcon.StackView));
bottom.setTopLeft(label);
final ToolBar failureToolBar = new ToolBar(bottom, SWT.FLAT | SWT.WRAP);
bottom.setTopCenter(failureToolBar);
failureTrace = new FailureTrace(bottom, clipboard, failureToolBar, iconProvider, infoMessageUpdater,
runSessionSupplier());
bottom.setContent(failureTrace.getComposite());
sashForm.setWeights(new int[] { 50, 50 });
return sashForm;
}
private void addDropAdapter() {
final DropTarget dropTarget = new DropTarget(parent, DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK
| DND.DROP_DEFAULT);
dropTarget.setTransfer(new Transfer[] { TextTransfer.getInstance() });
class DropAdapter extends DropTargetAdapter {
@Override
public void dragEnter(final DropTargetEvent event) {
event.detail = DND.DROP_COPY;
event.feedback = DND.FEEDBACK_NONE;
}
@Override
public void dragOver(final DropTargetEvent event) {
event.detail = DND.DROP_COPY;
event.feedback = DND.FEEDBACK_NONE;
}
@Override
public void dragOperationChanged(final DropTargetEvent event) {
event.detail = DND.DROP_COPY;
event.feedback = DND.FEEDBACK_NONE;
}
@Override
public void drop(final DropTargetEvent event) {
if (TextTransfer.getInstance().isSupportedType(event.currentDataType)) {
// final String url = (String) event.data;
importTestRunSession();
}
}
}
dropTarget.addDropListener(new DropAdapter());
}
private void initPageSwitcher() {
@SuppressWarnings("unused")
final PageSwitcher pageSwitcher = new PageSwitcher(this) {
@Override
public Object[] getPages() {
return viewHistory.getHistoryEntries().toArray();
}
@Override
public String getName(final Object page) {
return viewHistory.getText((SubstepsRunSession) page);
}
@Override
public ImageDescriptor getImageDescriptor(final Object page) {
return viewHistory.getImageDescriptor(page);
}
@Override
public void activatePage(final Object page) {
viewHistory.setActiveEntry((SubstepsRunSession) page);
}
@Override
public int getCurrentPageIndex() {
return viewHistory.getHistoryEntries().indexOf(viewHistory.getCurrentEntry());
}
};
}
private void addResizeListener(final Composite parentComposite) {
parentComposite.addControlListener(new ControlListener() {
@Override
public void controlMoved(final ControlEvent e) {
// No-op
}
@Override
public void controlResized(final ControlEvent e) {
computeOrientation();
}
});
}
void computeOrientation() {
if (orientation != ViewOrientation.VIEW_ORIENTATION_AUTOMATIC) {
currentOrientation = orientation;
setOrientation(currentOrientation.value());
} else {
final Point size = parent.getSize();
if (size.x != 0 && size.y != 0) {
if (size.x > size.y)
setOrientation(ViewOrientation.VIEW_ORIENTATION_HORIZONTAL.value());
else
setOrientation(ViewOrientation.VIEW_ORIENTATION_VERTICAL.value());
}
}
}
private void configureToolBar() {
final IActionBars actionBars = getViewSite().getActionBars();
final IToolBarManager toolBar = actionBars.getToolBarManager();
final IMenuManager viewMenu = actionBars.getMenuManager();
actionManager.setNextActionEnabled(false);
actionBars.setGlobalActionHandler(ActionFactory.NEXT.getId(), actionManager.nextAction());
actionManager.setPrevActionEnabled(false);
actionBars.setGlobalActionHandler(ActionFactory.PREVIOUS.getId(), actionManager.prevAction());
actionManager.setStopActionEnabled(false);
handlerServiceManager.activateHandlers(RERUN_LAST_COMMAND, new AbstractHandler() {
@Override
public Object execute(final ExecutionEvent event) throws ExecutionException {
actionManager.rerunLastTestAction().run();
return null;
}
@Override
public boolean isEnabled() {
return actionManager.rerunLastTestAction().isEnabled();
}
});
handlerServiceManager.activateHandlers(RERUN_FAILED_FIRST_COMMAND, new AbstractHandler() {
@Override
public Object execute(final ExecutionEvent event) throws ExecutionException {
actionManager.rerunFailedFirstAction().run();
return null;
}
@Override
public boolean isEnabled() {
return actionManager.rerunFailedFirstAction().isEnabled();
}
});
failuresOnlyFilterAction = new FailuresOnlyFilterAction(showFailuresOnlyNotifier(), iconProvider);
scrollLockAction = new ScrollLockAction(autoScrollNotifier(), iconProvider);
scrollLockAction.setChecked(!autoScroll);
final Notifier<ViewOrientation> viewOrientationNotifier = viewOrientationNotifier();
toggleOrientationActions = new ToggleOrientationAction[] {
new ToggleOrientationAction(ViewOrientation.VIEW_ORIENTATION_VERTICAL, viewOrientationNotifier,
iconProvider),
new ToggleOrientationAction(ViewOrientation.VIEW_ORIENTATION_HORIZONTAL, viewOrientationNotifier,
iconProvider),
new ToggleOrientationAction(ViewOrientation.VIEW_ORIENTATION_AUTOMATIC, viewOrientationNotifier,
iconProvider) };
showTestHierarchyAction = new ShowTestHierarchyAction(layoutModeNotifier(), iconProvider);
showTimeAction = new ShowTimeAction(testViewer);
toolBar.add(actionManager.nextAction());
toolBar.add(actionManager.prevAction());
toolBar.add(failuresOnlyFilterAction);
toolBar.add(scrollLockAction);
toolBar.add(new Separator());
toolBar.add(actionManager.rerunLastTestAction());
toolBar.add(actionManager.rerunFailedFirstAction());
toolBar.add(actionManager.stopAction());
toolBar.add(viewHistory.createHistoryDropDownAction());
viewMenu.add(showTestHierarchyAction);
viewMenu.add(showTimeAction);
viewMenu.add(new Separator());
final MenuManager layoutSubMenu = new MenuManager(
SubstepsFeatureMessages.SubstepsFeatureTestRunnerViewPart_layout_menu);
for (int i = 0; i < toggleOrientationActions.length; ++i) {
layoutSubMenu.add(toggleOrientationActions[i]);
}
viewMenu.add(layoutSubMenu);
viewMenu.add(new Separator());
viewMenu.add(failuresOnlyFilterAction);
final ActivateOnErrorAction activateOnErrorAction = new ActivateOnErrorAction(showOnErrorOnly,
showOnErrorOnlyNotifier());
viewMenu.add(activateOnErrorAction);
viewMenuListener = new IMenuListener() {
@Override
public void menuAboutToShow(final IMenuManager manager) {
activateOnErrorAction.update(showOnErrorOnly);
}
};
viewMenu.addMenuListener(viewMenuListener);
actionBars.updateActionBars();
}
@SuppressWarnings("unused")
private IStatusLineManager getStatusLine() {
// we want to show messages globally hence we
// have to go through the active part
final IViewSite site = getViewSite();
final IWorkbenchPage page = site.getPage();
final IWorkbenchPart activePart = page.getActivePart();
if (activePart instanceof IViewPart) {
final IViewPart activeViewPart = (IViewPart) activePart;
final IViewSite activeViewSite = activeViewPart.getViewSite();
return activeViewSite.getActionBars().getStatusLineManager();
}
if (activePart instanceof IEditorPart) {
final IEditorPart activeEditorPart = (IEditorPart) activePart;
final IEditorActionBarContributor contributor = activeEditorPart.getEditorSite().getActionBarContributor();
if (contributor instanceof EditorActionBarContributor)
return ((EditorActionBarContributor) contributor).getActionBars().getStatusLineManager();
}
// no active part
return getViewSite().getActionBars().getStatusLineManager();
}
protected Composite createProgressCountPanel(final Composite parentComposite) {
final Composite composite = new Composite(parentComposite, SWT.NONE);
final GridLayout l = new GridLayout();
composite.setLayout(l);
setCounterColumns(l);
counterPanel = new SubstepsCounterPanel(composite, iconProvider);
counterPanel.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
progressBar = new SubstepsProgressBar(composite);
((Composite) progressBar)
.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
return composite;
}
private void showFailure(final SubstepsTestElement test) {
notify(new Runnable() {
@Override
public void run() {
if (!isDisposed())
failureTrace.showFailure(test);
}
});
}
private boolean isDisposed() {
return disposed || counterPanel.isDisposed();
}
private Display getDisplay() {
return getViewSite().getShell().getDisplay();
}
/*
* @see IWorkbenchPart#getTitleImage()
*/
@Override
public Image getTitleImage() {
if (originalViewImage == null)
originalViewImage = super.getTitleImage();
if (viewImage == null)
return super.getTitleImage();
return viewImage;
}
void codeHasChanged() {
dirtyListener.removeDirtyListener();
if (viewImage == iconProvider.imageFor(SubstepsTestIcon.TestRunOK))
viewImage = iconProvider.imageFor(SubstepsTestIcon.TestRunOKDirty);
else if (viewImage == iconProvider.imageFor(SubstepsTestIcon.TestRunFail))
viewImage = iconProvider.imageFor(SubstepsTestIcon.TestRunFailDirty);
final Runnable r = new Runnable() {
@Override
public void run() {
if (isDisposed())
return;
firePropertyChange(IWorkbenchPart.PROP_TITLE);
}
};
if (!isDisposed())
getDisplay().asyncExec(r);
}
public void rerunTest(final String testId, final String className, final String testName, final String launchMode) {
final boolean buildBeforeLaunch = Platform.getPreferencesService().getBoolean(IDebugUIConstants.PLUGIN_ID,
IDebugUIConstants.PREF_BUILD_BEFORE_LAUNCH, false, null);
try {
final boolean couldLaunch = sessionManager.get().rerunTest(testId, className, testName, launchMode,
buildBeforeLaunch);
if (!couldLaunch) {
MessageDialog.openInformation(getSite().getShell(),
SubstepsFeatureMessages.SubstepsFeatureTestRunnerViewPart_cannotrerun_title,
SubstepsFeatureMessages.SubstepsFeatureTestRunnerViewPart_cannotrerurn_message);
} else if (sessionManager.get().isKeptAlive()) {
final SubstepsTestLeafElement testCaseElement = (SubstepsTestLeafElement) sessionManager.get()
.getTestElement(testId);
testCaseElement.setStatus(Status.RUNNING, null, null, null);
testViewer.registerViewerUpdate(testCaseElement);
postSyncProcessChanges();
}
} catch (final CoreException e) {
ErrorDialog.openError(getSite().getShell(),
SubstepsFeatureMessages.SubstepsFeatureTestRunnerViewPart_error_cannotrerun, e.getMessage(),
e.getStatus());
}
}
private void postSyncProcessChanges() {
notify(new Runnable() {
@Override
public void run() {
uiUpdater.doUpdate();
}
});
}
public void warnOfContentChange() {
final IWorkbenchSiteProgressService service = getProgressService();
if (service != null)
service.warnOfContentChange();
}
public boolean lastLaunchIsKeptAlive() {
final SubstepsRunSession subsepsRunSession = sessionManager.get();
return subsepsRunSession != null && subsepsRunSession.isKeptAlive();
}
private void setOrientation(final int orientation) {
if ((sashForm == null) || sashForm.isDisposed())
return;
final boolean horizontal = orientation == ViewOrientation.VIEW_ORIENTATION_HORIZONTAL.value();
sashForm.setOrientation(horizontal ? SWT.HORIZONTAL : SWT.VERTICAL);
for (int i = 0; i < toggleOrientationActions.length; ++i)
toggleOrientationActions[i].setChecked(orientation == toggleOrientationActions[i].getOrientation());
currentOrientation = ViewOrientation.forValue(orientation);
final GridLayout l = (GridLayout) counterComposite.getLayout();
setCounterColumns(l);
parent.layout();
}
private void setCounterColumns(final GridLayout layout) {
if (currentOrientation.equals(ViewOrientation.VIEW_ORIENTATION_HORIZONTAL))
layout.numColumns = 2;
else
layout.numColumns = 1;
}
static boolean getShowOnErrorOnly() {
return Platform.getPreferencesService().getBoolean(FeatureRunnerPlugin.PLUGIN_ID,
PreferencesConstants.SHOW_ON_ERROR_ONLY, false, null);
}
static void importTestRunSession() {
try {
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
@Override
public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
throw new UnsupportedOperationException("Import is not currently available");
}
});
} catch (final InterruptedException e) {
// cancelled
} catch (final InvocationTargetException e) {
final CoreException ce = (CoreException) e.getCause();
StatusManager.getManager().handle(ce.getStatus(), StatusManager.SHOW | StatusManager.LOG);
}
}
public FailureTrace getFailureTrace() {
return failureTrace;
}
private void setLayoutMode(final int mode) {
setFilterAndLayout(failuresOnlyFilterAction.isChecked(), mode);
}
private void setFilterAndLayout(final boolean failuresOnly, final int layoutMode) {
showTestHierarchyAction.setChecked(layoutMode == ViewLayout.HIERARCHICAL.value());
layout = ViewLayout.forValue(layoutMode);
failuresOnlyFilterAction.setChecked(failuresOnly);
testViewer.setShowFailuresOnly(failuresOnly, layoutMode);
}
private void setShowExecutionTime(final boolean showTime) {
testViewer.setShowTime(showTime);
showTimeAction.setChecked(showTime);
}
SubstepsTestElement[] getAllFailures() {
return sessionManager.get().getAllFailedTestElements();
}
private Supplier<Display> displaySupplier() {
return new Supplier<Display>() {
@Override
public Display get() {
return getDisplay();
}
};
}
private Supplier<IWorkbenchPartSite> siteSupplier() {
return new Supplier<IWorkbenchPartSite>() {
@Override
public IWorkbenchPartSite get() {
return getSite();
}
};
}
private Notifier<Boolean> showFailuresOnlyNotifier() {
return new Notifier<Boolean>() {
@Override
public void notify(final Boolean t) {
setFilterAndLayout(t.booleanValue(), layout.value());
}
@Override
public Boolean currentValue() {
return Boolean.valueOf(failuresOnlyFilterAction.isChecked());
}
};
}
private Notifier<Boolean> autoScrollNotifier() {
return new Notifier<Boolean>() {
@Override
public void notify(final Boolean t) {
setAutoScroll(t.booleanValue());
}
@Override
public Boolean currentValue() {
return Boolean.valueOf(autoScroll);
}
};
}
private Notifier<Boolean> showOnErrorOnlyNotifier() {
return new Notifier<Boolean>() {
@Override
public void notify(final Boolean t) {
showOnErrorOnly = t.booleanValue();
}
@Override
public Boolean currentValue() {
return Boolean.valueOf(showOnErrorOnly);
}
};
}
private Notifier<ViewOrientation> viewOrientationNotifier() {
return new Notifier<ViewOrientation>() {
@Override
public void notify(final ViewOrientation t) {
orientation = t;
computeOrientation();
}
@Override
public ViewOrientation currentValue() {
// TODO Auto-generated method stub
return null;
}
};
}
private Notifier<ViewLayout> layoutModeNotifier() {
return new Notifier<ViewLayout>() {
@Override
public void notify(final ViewLayout t) {
setLayoutMode(t.value());
}
@Override
public ViewLayout currentValue() {
return null;
}
};
}
private Notifier<SubstepsTestElement> failedTestNotifier() {
return new Notifier<SubstepsTestElement>() {
@Override
public void notify(final SubstepsTestElement t) {
showFailure(t);
((SubstepsCopyAction) actionManager.copyAction()).handleTestSelected(t);
}
@Override
public SubstepsTestElement currentValue() {
// TODO Auto-generated method stub
return null;
}
};
}
private Notifier<TestContext> testRerunner() {
return new Notifier<TestContext>() {
@Override
public void notify(final TestContext t) {
rerunTest(t.getTestId(), t.getClassName(), t.getTestName(), t.getLaunchMode());
}
@Override
public TestContext currentValue() {
return null;
}
};
}
private Supplier<String> testKindDisplayNameSupplier() {
return new Supplier<String>() {
@Override
public String get() {
final String testRunnerKind = sessionManager.get().getTestRunnerKind();
return testRunnerKind == null ? "" : testRunnerKind;
}
};
}
private Notifier<String> tooltipNotifier() {
return new Notifier<String>() {
@Override
public void notify(final String t) {
setTitleToolTip(t);
}
@Override
public String currentValue() {
// TODO Auto-generated method stub
return null;
}
};
}
private Supplier<Boolean> disposedSashFormChecker() {
return new Supplier<Boolean>() {
@Override
public Boolean get() {
return Boolean.valueOf(sashForm.isDisposed());
}
};
}
private Supplier<SubstepsSessionListener> testSessionListenerSupplier() {
return new Supplier<SubstepsSessionListener>() {
@Override
public SubstepsSessionListener get() {
return new TestSessionListener(testViewer, SubstepsFeatureTestRunnerViewPart.this, infoMessageUpdater,
uiUpdater, showOnErrorOnlyNotifier(), SubstepsFeatureTestRunnerViewPart.this, actionManager,
sessionManager, testRunStatsSupplier, disposedChecker, autoScrollNotifier(),
SubstepsFeatureTestRunnerViewPart.this, viewTitleUiUpdater, testResultsView, failureTrace,
dirtyListener);
}
};
}
private Supplier<TestRunStats> testRunStatsSupplier() {
return new Supplier<TestRunStats>() {
@Override
public TestRunStats get() {
return sessionManager.get();
}
};
}
private Supplier<SubstepsRunSession> runSessionSupplier() {
return new Supplier<SubstepsRunSession>() {
@Override
public SubstepsRunSession get() {
return sessionManager.get();
}
};
}
}