package com.redhat.ceylon.test.eclipse.plugin.ui;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.HISTORY;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.RELAUNCH;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.RELAUNCH_FAILED;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.STOP;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestMessages.historyLabel;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestMessages.msg;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestMessages.relaunchLabel;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestMessages.relaunchFailedLabel;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestMessages.relaunchFailedNamePostfix;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestMessages.statusTestPlatformJs;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestMessages.statusTestPlatformJvm;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestMessages.statusTestRunFinished;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestMessages.statusTestRunInterrupted;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestMessages.statusTestRunRunning;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestMessages.stopLabel;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestPlugin.LAUNCH_CONFIG_TYPE_JS;
import static com.redhat.ceylon.test.eclipse.plugin.util.CeylonTestUtil.getActivePage;
import static com.redhat.ceylon.test.eclipse.plugin.util.CeylonTestUtil.getDisplay;
import static com.redhat.ceylon.test.eclipse.plugin.util.CeylonTestUtil.getElapsedTimeInSeconds;
import static com.redhat.ceylon.test.eclipse.plugin.util.CeylonTestUtil.getShell;
import static com.redhat.ceylon.test.eclipse.plugin.launch.CeylonTestLaunchShortcut.relaunch;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.UIJob;
import com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry;
import com.redhat.ceylon.test.eclipse.plugin.CeylonTestPlugin;
import com.redhat.ceylon.test.eclipse.plugin.model.TestElement;
import com.redhat.ceylon.test.eclipse.plugin.model.TestRun;
import com.redhat.ceylon.test.eclipse.plugin.model.TestRunContainer;
import com.redhat.ceylon.test.eclipse.plugin.model.TestRunListener;
import com.redhat.ceylon.test.eclipse.plugin.model.TestRunListenerAdapter;
public class TestRunViewPart extends ViewPart {
private static final String NAME = "com.redhat.ceylon.test.eclipse.plugin.testview";
private static final int REFRESH_INTERVAL;
static {
int refresh = 200;
try {
String val = System.getProperty("eclipse.ceylon.testview.refresh");
if( val != null ) {
refresh = Integer.parseInt(val);
CeylonTestPlugin.logInfo("ceylon testview refresh interval specified from system property to value: " + refresh);
}
}
catch(Throwable e) {
CeylonTestPlugin.logError("unable to parse ceylon testview refresh interval from system property", e);
}
REFRESH_INTERVAL = refresh;
}
private CounterPanel counterPanel;
private ProgressBar progressBar;
private SashForm sashForm;
private TestsPanel testsPanel;
private StackTracePanel stackTracePanel;
private IPartListener2 viewPartListener;
private TestRunListener testRunListener;
private TestRun currentTestRun;
private UpdateViewJob updateViewJob = new UpdateViewJob();
private ShowHistoryAction showHistoryAction;
private RelaunchAction relaunchAction;
private RelaunchFailedAction relaunchFailedAction;
private StopAction stopAction;
private boolean isDisposed;
private boolean isVisible;
public static void showPageAsync() {
getDisplay().asyncExec(new Runnable() {
public void run() {
showPage();
}
});
}
public static void showPage() {
try {
IWorkbenchPage page = getActivePage();
if (page != null) {
TestRunViewPart view = (TestRunViewPart) page.findView(NAME);
if (view == null) {
page.showView(NAME, null, IWorkbenchPage.VIEW_VISIBLE);
} else {
page.bringToTop(view);
}
}
} catch (PartInitException e) {
CeylonTestPlugin.logError("", e);
}
}
@Override
public void createPartControl(Composite parent) {
GridLayout layout= new GridLayout(1, false);
layout.marginLeft = 0;
layout.marginRight = 0;
Composite composite= new Composite(parent, SWT.NONE);
composite.setLayout(layout);
createCounterPanel(composite);
createProgressBar(composite);
createSashForm(composite);
createTestsPanel();
createStackTracePanel();
createToolBar();
createViewPartListener();
initCurrentTestRun();
createTestRunListener();
}
private void createViewPartListener() {
viewPartListener = new IPartListener2() {
public void partActivated(IWorkbenchPartReference ref) {}
public void partBroughtToTop(IWorkbenchPartReference ref) {}
public void partInputChanged(IWorkbenchPartReference ref) {}
public void partClosed(IWorkbenchPartReference ref) {}
public void partDeactivated(IWorkbenchPartReference ref) {}
public void partOpened(IWorkbenchPartReference ref) {}
public void partVisible(IWorkbenchPartReference ref) {
if (getSite().getId().equals(ref.getId())) {
isVisible = true;
updateView();
}
}
public void partHidden(IWorkbenchPartReference ref) {
if (getSite().getId().equals(ref.getId())) {
isVisible = false;
}
}
};
getViewSite().getPage().addPartListener(viewPartListener);
}
private void createCounterPanel(Composite composite) {
counterPanel = new CounterPanel(composite);
counterPanel.setLayoutData(GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).create());
}
private void createProgressBar(Composite composite) {
progressBar = new ProgressBar(composite);
progressBar.setLayoutData(GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).create());
}
private void createSashForm(Composite composite) {
sashForm = new SashForm(composite, SWT.VERTICAL);
sashForm.setLayoutData(GridDataFactory.swtDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).create());
}
private void createTestsPanel() {
testsPanel = new TestsPanel(this, sashForm);
testsPanel.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
TestElement selectedTestElement = null;
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
if (selection.size() == 1) {
Object selectedItem = selection.getFirstElement();
if (selectedItem instanceof TestElement) {
selectedTestElement = (TestElement) selectedItem;
}
}
stackTracePanel.setSelectedTestElement(currentTestRun, selectedTestElement);
}
});
}
private void createStackTracePanel() {
stackTracePanel = new StackTracePanel(sashForm);
}
private void createToolBar() {
relaunchAction = new RelaunchAction();
relaunchFailedAction = new RelaunchFailedAction();
stopAction = new StopAction();
showHistoryAction = new ShowHistoryAction();
IToolBarManager toolBarManager = getViewSite().getActionBars().getToolBarManager();
toolBarManager.add(relaunchAction);
toolBarManager.add(relaunchFailedAction);
toolBarManager.add(stopAction);
toolBarManager.add(showHistoryAction);
toolBarManager.update(true);
}
private void initCurrentTestRun() {
if( currentTestRun == null ) {
List<TestRun> testRuns = CeylonTestPlugin.getDefault().getModel().getTestRuns();
if( !testRuns.isEmpty() ) {
setCurrentTestRun(testRuns.get(0));
}
}
}
private void createTestRunListener() {
testRunListener = new TestRunListenerAdapter() {
@Override
public void testRunAdded(TestRun testRun) {
setCurrentTestRun(testRun);
}
@Override
public void testRunRemoved(TestRun testRun) {
if (testRun == currentTestRun) {
setCurrentTestRun(null);
}
}
@Override
public void testRunFinished(TestRun testRun) {
if (testRun == currentTestRun) {
getDisplay().asyncExec(new Runnable() {
public void run() {
testsPanel.moveToFirstFailure();
}
});
}
}
};
TestRunContainer testRunContainer = CeylonTestPlugin.getDefault().getModel();
testRunContainer.addTestRunListener(testRunListener);
}
private void setCurrentTestRun(final TestRun testRun) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
synchronized (TestRun.acquireLock(testRun)) {
currentTestRun = testRun;
testsPanel.setCurrentTestRun(testRun);
updateView();
if( testRun != null ) {
updateViewJob.schedule(REFRESH_INTERVAL);
}
}
}
});
}
private void updateView() {
synchronized (TestRun.acquireLock(currentTestRun)) {
updateStatusMessage();
updateActionState();
counterPanel.updateView(currentTestRun);
progressBar.updateView(currentTestRun);
testsPanel.updateView();
}
}
private void updateStatusMessage() {
String msg = "";
if (currentTestRun != null) {
if (currentTestRun.isRunning()) {
msg = msg(statusTestRunRunning, currentTestRun.getRunName());
}
else if (currentTestRun.isFinished()) {
msg = msg(statusTestRunFinished, getElapsedTimeInSeconds(currentTestRun.getRunElapsedTimeInMilis()));
}
else if (currentTestRun.isInterrupted()) {
msg = msg(statusTestRunInterrupted, currentTestRun.getRunName());
}
try {
msg += " ";
if (LAUNCH_CONFIG_TYPE_JS.equals(currentTestRun.getLaunch().getLaunchConfiguration().getType().getIdentifier())) {
msg += statusTestPlatformJs;
} else {
msg += statusTestPlatformJvm;
}
} catch (CoreException e) {
CeylonTestPlugin.logError("", e);
}
}
setContentDescription(msg);
}
private void updateActionState() {
boolean canRelaunch = false;
boolean canRelaunchFailed = false;
boolean canStop = false;
if (currentTestRun != null) {
canRelaunch = !currentTestRun.isRunning();
canRelaunchFailed = !currentTestRun.isRunning() && currentTestRun.isFailureOrError();
canStop = currentTestRun.isRunning();
}
relaunchAction.setEnabled(canRelaunch);
relaunchFailedAction.setEnabled(canRelaunchFailed);
stopAction.setEnabled(canStop);
}
@Override
public void setFocus() {
}
@Override
public void dispose() {
isDisposed = true;
isVisible = false;
TestRunContainer testRunContainer = CeylonTestPlugin.getDefault().getModel();
testRunContainer.removeTestRunListener(testRunListener);
getViewSite().getPage().removePartListener(viewPartListener);
super.dispose();
}
private class UpdateViewJob extends UIJob {
public UpdateViewJob() {
super("UpdateViewJob");
setSystem(true);
}
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
if (!isDisposed) {
if (isVisible) {
updateView();
}
if (currentTestRun != null && currentTestRun.isRunning()) {
schedule(REFRESH_INTERVAL);
}
}
return Status.OK_STATUS;
}
}
private class RelaunchAction extends Action implements IMenuCreator {
private Menu dropdownMenu;
public RelaunchAction() {
super(relaunchLabel, AS_DROP_DOWN_MENU);
setDescription(relaunchLabel);
setToolTipText(relaunchLabel);
setImageDescriptor(CeylonTestImageRegistry.getImageDescriptor(RELAUNCH));
setEnabled(false);
setMenuCreator(this);
}
@Override
public void run() {
synchronized (TestRun.acquireLock(currentTestRun)) {
if( currentTestRun == null || currentTestRun.isRunning() )
return;
ILaunch launch = currentTestRun.getLaunch();
if( launch == null )
return;
ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration();
if( launchConfiguration == null )
return;
DebugUITools.launch(launchConfiguration, launch.getLaunchMode());
}
}
@Override
public Menu getMenu(Control parent) {
if( dropdownMenu != null ) {
dropdownMenu.dispose();
}
dropdownMenu = new Menu(parent.getShell(), SWT.POP_UP|SWT.NONE);
TestRunContainer testRunContainer = CeylonTestPlugin.getDefault().getModel();
List<TestRun> testRuns = testRunContainer.getTestRuns();
Set<String> testRunNames = new HashSet<String>();
for(TestRun testRun : testRuns) {
if( !testRunNames.contains(testRun.getRunName()) ) {
testRunNames.add(testRun.getRunName());
addActionToMenu(dropdownMenu, new RelaunchMenuAction(testRun));
}
}
return dropdownMenu;
}
private void addActionToMenu(Menu parent, Action action) {
ActionContributionItem item = new ActionContributionItem(action);
item.fill(parent, -1);
}
@Override
public Menu getMenu(Menu parent) {
return null;
}
@Override
public void dispose() {
if( dropdownMenu != null ) {
dropdownMenu.dispose();
dropdownMenu = null;
}
}
}
private class RelaunchMenuAction extends Action {
private final TestRun testRun;
public RelaunchMenuAction(TestRun testRun) {
super(testRun.getRunName());
setDescription(testRun.getRunName());
setToolTipText(testRun.getRunName());
this.testRun = testRun;
}
@Override
public void run() {
ILaunch launch = testRun.getLaunch();
if( launch == null )
return;
ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration();
if( launchConfiguration == null )
return;
DebugUITools.launch(launchConfiguration, launch.getLaunchMode());
}
}
private class RelaunchFailedAction extends Action {
public RelaunchFailedAction() {
super(relaunchFailedLabel);
setDescription(relaunchFailedLabel);
setToolTipText(relaunchFailedLabel);
setImageDescriptor(CeylonTestImageRegistry.getImageDescriptor(RELAUNCH_FAILED));
setEnabled(false);
}
@Override
public void run() {
synchronized (TestRun.acquireLock(currentTestRun)) {
if (currentTestRun == null)
return;
ILaunch launch = currentTestRun.getLaunch();
if (launch == null)
return;
String launchName = launch.getLaunchConfiguration().getName() + " " + relaunchFailedNamePostfix;
String launchMode = launch.getLaunchMode();
List<String> qualifiedNames = new ArrayList<String>();
for (TestElement testElement : currentTestRun.getAtomicTests()) {
if (testElement.getState().isFailureOrError()
&& !qualifiedNames.contains(testElement.getQualifiedName())) {
qualifiedNames.add(testElement.getQualifiedName());
}
}
try {
relaunch(launch, launchName, launchMode, qualifiedNames);
} catch (CoreException e) {
CeylonTestPlugin.logError("", e);
}
}
}
}
private class StopAction extends Action {
public StopAction() {
super(stopLabel);
setDescription(stopLabel);
setToolTipText(stopLabel);
setImageDescriptor(CeylonTestImageRegistry.getImageDescriptor(STOP));
setEnabled(false);
}
@Override
public void run() {
synchronized (TestRun.acquireLock(currentTestRun)) {
if( currentTestRun == null || !currentTestRun.isRunning() )
return;
ILaunch launch = currentTestRun.getLaunch();
if( launch == null || !launch.canTerminate() )
return;
try {
launch.terminate();
} catch (DebugException e) {
CeylonTestPlugin.logError("", e);
}
}
}
}
private class ShowHistoryAction extends Action {
public ShowHistoryAction() {
super(historyLabel);
setImageDescriptor(CeylonTestImageRegistry.getImageDescriptor(HISTORY));
}
@Override
public void run() {
HistoryDialog dlg = new HistoryDialog(getShell());
if (dlg.open() == Dialog.OK) {
TestRun selectedTestRun = dlg.getSelectedTestRun();
if( selectedTestRun != currentTestRun ) {
setCurrentTestRun(selectedTestRun);
}
}
}
}
}