package org.rubypeople.rdt.internal.testunit.ui;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.AbstractSet;
import java.util.HashSet;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchListener;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
import org.rubypeople.rdt.core.IRubyElement;
import org.rubypeople.rdt.core.IType;
import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.testunit.ITestRunListener;
import org.rubypeople.rdt.testunit.launcher.TestUnitLaunchConfigurationDelegate;
/**
* The main plugin class to be used in the desktop.
*/
public class TestunitPlugin extends AbstractUIPlugin implements ILaunchListener {
public static final String PLUGIN_ID = "org.rubypeople.rdt.testunit"; //$NON-NLS-1$
public static final String TESTUNIT_PORT_ATTR = "org.rubypeople.rdt.testunit.port"; //$NON-NLS-1$
//The shared instance.
private static TestunitPlugin plugin;
//Resource bundle.
private ResourceBundle resourceBundle;
/**
* Use to track new launches. We need to do this so that we only attach a
* TestRunner once to a launch. Once a test runner is connected it is
* removed from the set.
*/
private AbstractSet<ILaunch> fTrackedLaunches = new HashSet<ILaunch>(20);
private Set<ITestRunListener> fTestRunListeners = new HashSet<ITestRunListener>();
private static URL fgIconBaseURL;
/**
* The constructor.
*/
public TestunitPlugin() {
super();
String pathSuffix = "icons/full/"; //$NON-NLS-1$
try {
fgIconBaseURL = new URL(Platform.getBundle(PLUGIN_ID).getEntry("/"), pathSuffix); //$NON-NLS-1$
} catch (MalformedURLException e) {
// do nothing
}
try {
resourceBundle = ResourceBundle.getBundle("org.rubypeople.rdt.testunit.TestunitPluginResources");
} catch (MissingResourceException x) {
resourceBundle = null;
}
}
public static URL makeIconFileURL(String name) throws MalformedURLException {
if (TestunitPlugin.fgIconBaseURL == null) throw new MalformedURLException();
return new URL(TestunitPlugin.fgIconBaseURL, name);
}
public static ImageDescriptor getImageDescriptor(String relativePath) {
try {
return ImageDescriptor.createFromURL(makeIconFileURL(relativePath));
} catch (MalformedURLException e) {
// should not happen
return ImageDescriptor.getMissingImageDescriptor();
}
}
/**
* This method is called upon plug-in activation
*/
public void start(BundleContext context) throws Exception {
plugin = this;
super.start(context);
ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
launchManager.addLaunchListener(this);
}
/**
* This method is called when the plug-in is stopped
*/
public void stop(BundleContext context) throws Exception {
super.stop(context);
}
/**
* Returns the shared instance.
*/
public static TestunitPlugin getDefault() {
return plugin;
}
/**
* Returns the string from the plugin's resource bundle, or 'key' if not
* found.
*/
public static String getResourceString(String key) {
ResourceBundle bundle = TestunitPlugin.getDefault().getResourceBundle();
try {
return (bundle != null) ? bundle.getString(key) : key;
} catch (MissingResourceException e) {
return key;
}
}
/**
* Returns the plugin's resource bundle,
*/
public ResourceBundle getResourceBundle() {
return resourceBundle;
}
public static String getPluginId() {
return PLUGIN_ID;
}
public static void log(Throwable e) {
log(new Status(IStatus.ERROR, getPluginId(), IStatus.ERROR, "Error", e)); //$NON-NLS-1$
}
public static void log(IStatus status) {
getDefault().getLog().log(status);
}
public static Shell getActiveWorkbenchShell() {
IWorkbenchWindow workBenchWindow = getActiveWorkbenchWindow();
if (workBenchWindow == null) return null;
return workBenchWindow.getShell();
}
/**
* Returns the active workbench window
*
* @return the active workbench window
*/
public static IWorkbenchWindow getActiveWorkbenchWindow() {
if (plugin == null) return null;
IWorkbench workBench = plugin.getWorkbench();
if (workBench == null) return null;
return workBench.getActiveWorkbenchWindow();
}
public static IWorkspace getWorkspace() {
return RubyCore.getWorkspace();
}
public static Display getDisplay() {
Display display = Display.getCurrent();
if (display == null) {
display = Display.getDefault();
}
return display;
}
public static IWorkbenchPage getActivePage() {
IWorkbenchWindow activeWorkbenchWindow = getActiveWorkbenchWindow();
if (activeWorkbenchWindow == null) return null;
return activeWorkbenchWindow.getActivePage();
}
public void connectTestRunner(ILaunch launch, IType finalType, int port) {
TestUnitView testRunnerViewPart = showTestUnitViewInActivePage(findTestUnitViewInActivePage());
if (testRunnerViewPart != null) testRunnerViewPart.startTestRunListening(port, finalType, launch, fTestRunListeners);
}
public void addTestRunListener(ITestRunListener listener) {
fTestRunListeners.add(listener);
}
public void removeTestRunListener(ITestRunListener listener) {
fTestRunListeners.remove(listener);
}
private TestUnitView showTestUnitViewInActivePage(TestUnitView testRunner) {
IWorkbenchPart activePart = null;
IWorkbenchPage page = null;
try {
// TODO: have to force the creation of view part contents
// otherwise the UI will not be updated
if (testRunner != null && testRunner.isCreated()) return testRunner;
page = getActivePage();
if (page == null) return null;
activePart = page.getActivePart();
// show the result view if it isn't shown yet
return (TestUnitView) page.showView(TestUnitView.NAME);
} catch (PartInitException pie) {
log(pie);
return null;
} finally {
//restore focus stolen by the creation of the result view
if (page != null && activePart != null) page.activate(activePart);
}
}
public TestUnitView findTestUnitViewInActivePage() {
IWorkbenchPage page = getActivePage();
if (page == null) return null;
return (TestUnitView) page.findView(TestUnitView.NAME);
}
/**
* @param string
*/
public static void log(String string) {
log(new Throwable(string));
}
/*
* @see ILaunchListener#launchRemoved(ILaunch)
*/
public void launchRemoved(final ILaunch launch) {
if (!fTrackedLaunches.remove(launch))
return;
getDisplay().asyncExec(new Runnable() {
public void run() {
TestUnitView testRunnerViewPart = findTestRunnerViewPartInActivePage();
if (testRunnerViewPart != null && testRunnerViewPart.isCreated() && launch.equals(testRunnerViewPart.getLastLaunch())) testRunnerViewPart.reset();
}
});
}
private TestUnitView findTestRunnerViewPartInActivePage() {
IWorkbenchPage page = getActivePage();
if (page == null) return null;
return (TestUnitView) page.findView(TestUnitView.NAME);
}
/*
* @see ILaunchListener#launchChanged(ILaunch)
*/
public void launchChanged(final ILaunch launch) {
if (!fTrackedLaunches.contains(launch)) return;
ILaunchConfiguration config = launch.getLaunchConfiguration();
IType launchedType= null;
if (config != null) {
String typeStr = launch.getAttribute(TestUnitLaunchConfigurationDelegate.TESTTYPE_ATTR);
if (typeStr != null && typeStr.trim().length() > 0) {
IRubyElement element = RubyCore.create(typeStr);
if (element instanceof IType)
launchedType = (IType) element;
}
}
fTrackedLaunches.remove(launch);
final IType finalType= launchedType;
final int finalPort = Integer.parseInt(launch.getAttribute(TESTUNIT_PORT_ATTR));
getDisplay().asyncExec(new Runnable() {
public void run() {
connectTestRunner(launch, finalType, finalPort);
}
});
}
/*
* @see ILaunchListener#launchAdded(ILaunch)
*/
public void launchAdded(ILaunch launch) {
try {
if (launch == null || launch.getLaunchConfiguration() == null || launch.getLaunchConfiguration().getType() == null) return;
if (launch.getLaunchConfiguration().getType().getDelegate(launch.getLaunchMode()).getClass() != TestUnitLaunchConfigurationDelegate.class) {
return;
}
fTrackedLaunches.add(launch);
} catch (Exception ex) {
log(ex);
}
}
}