/*
* Copyright (c) 2009, IETR/INSA of Rennes
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the IETR/INSA of Rennes nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package net.sf.orcc.ui.launching;
import static net.sf.orcc.OrccLaunchConstants.BACKEND;
import static net.sf.orcc.OrccLaunchConstants.COMPILE_XDF;
import static net.sf.orcc.OrccLaunchConstants.OUTPUT_FOLDER;
import static net.sf.orcc.OrccLaunchConstants.PROJECT;
import static net.sf.orcc.OrccLaunchConstants.RUN_CONFIG_TYPE;
import static net.sf.orcc.OrccLaunchConstants.XDF_FILE;
import static net.sf.orcc.util.OrccUtil.getQualifiedName;
import java.util.ArrayList;
import java.util.List;
import net.sf.orcc.backends.BackendFactory;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugModelPresentation;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.ILaunchShortcut;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
/**
* This class defines the launch shortcut to launch an Orcc compilation.
*
* @author Matthieu Wipliez
*
*/
public class OrccRunLaunchShortcut implements ILaunchShortcut {
/**
* Opens a directory dialog to select the output folder.
*
* @param shell
* the shell
* @param resource
* input file
* @return output folder
*/
private String browseOutputFolder(Shell shell, IResource resource) {
DirectoryDialog dialog = new DirectoryDialog(shell, SWT.NONE);
dialog.setMessage("Please select an output folder:");
dialog.setText("Choose output folder");
// set initial directory
String location = resource.getParent().getLocation().toOSString();
dialog.setFilterPath(location);
return dialog.open();
}
/**
* Chooses a configuration and launch it. If no configuration exists, create
* one.
*
* @param resource
* input file
* @param configs
* a possibly empty array of configurations
*/
private void chooseAndLaunch(IResource resource,
ILaunchConfiguration[] configs) {
if (configs.length == 0) {
Shell shell = getShell();
// no configuration: Create one
ILaunchConfiguration config = createConfiguration(resource);
if (config != null) {
// open launch dialog so the user can tune the settings
DebugUITools.openLaunchConfigurationDialogOnGroup(shell,
new StructuredSelection(config),
IDebugUIConstants.ID_RUN_LAUNCH_GROUP);
}
return;
}
ILaunchConfiguration config = null;
if (configs.length == 1) {
// one existing configuration
config = configs[0];
} else {
// several existing configurations, prompt the user
config = chooseConfiguration(configs);
}
if (config != null) {
DebugUITools.launch(config, ILaunchManager.RUN_MODE);
}
}
/**
* Prompts the user to choose a back-end.
*
* @return the back-end chosen, or <code>null</code>
*/
private String chooseBackend() {
ILabelProvider labelProvider = new LabelProvider();
ElementListSelectionDialog dialog = new ElementListSelectionDialog(
getShell(), labelProvider);
BackendFactory factory = BackendFactory.getInstance();
dialog.setElements(factory.listPlugins().toArray());
dialog.setTitle("Select backend");
dialog.setMessage("&Select backend:");
dialog.setMultipleSelection(false);
int result = dialog.open();
labelProvider.dispose();
if (result == Window.OK) {
return (String) dialog.getFirstResult();
}
return null;
}
/**
* Prompts the user a launch configuration if there are several of them.
*
* @param configs
* a non-empty array of configurations
* @return the launch configuration chosen, or <code>null</code>
*/
private ILaunchConfiguration chooseConfiguration(
ILaunchConfiguration[] configs) {
IDebugModelPresentation labelProvider = DebugUITools
.newDebugModelPresentation();
ElementListSelectionDialog dialog = new ElementListSelectionDialog(
getShell(), labelProvider);
dialog.setElements(configs);
dialog.setTitle("Select Orcc compilation");
dialog.setMessage("&Select existing configuration:");
dialog.setMultipleSelection(false);
int result = dialog.open();
labelProvider.dispose();
if (result == Window.OK) {
return (ILaunchConfiguration) dialog.getFirstResult();
}
return null;
}
/**
* Creates a configuration based on the input file. Prompts the user to pick
* an output folder and a back-end.
*
* @param file
* the input file
* @return the launch configuration created, or <code>null</code>
*/
private ILaunchConfiguration createConfiguration(IResource resource) {
ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
String id = RUN_CONFIG_TYPE;
ILaunchConfigurationType type = manager.getLaunchConfigurationType(id);
ILaunchConfiguration config = null;
try {
String folder = browseOutputFolder(getShell(), resource);
if (folder == null) {
return null;
}
String backend = chooseBackend();
if (backend == null) {
return null;
}
// generate configuration name
String name = getConfigurationName(resource, backend);
name = manager.generateLaunchConfigurationName(name);
// create configuration
ILaunchConfigurationWorkingCopy wc = type.newInstance(null, name);
wc.setAttribute(PROJECT, resource.getProject().getName());
wc.setAttribute(BACKEND, backend);
wc.setAttribute(COMPILE_XDF, true);
if (resource.getType() == IResource.FILE) {
wc.setAttribute(XDF_FILE, getQualifiedName((IFile) resource));
}
wc.setAttribute(OUTPUT_FOLDER, folder);
config = wc.doSave();
} catch (CoreException e) {
e.printStackTrace();
}
return config;
}
private String getConfigurationName(IResource resource, String backend) {
String name;
if (resource.getType() == IResource.FILE) {
name = getQualifiedName((IFile) resource);
} else {
name = resource.getName();
}
return name + " - " + backend;
}
/**
* Returns the configurations associated with the given input file.
*
* @param resource
* an input file
* @return a possibly empty, possibly <code>null</code> array of
* configurations
*/
private ILaunchConfiguration[] getConfigurations(IResource resource) {
ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
String id = RUN_CONFIG_TYPE;
ILaunchConfigurationType type = manager.getLaunchConfigurationType(id);
try {
// configurations that match the given resource
List<ILaunchConfiguration> configs = new ArrayList<ILaunchConfiguration>();
// candidates
ILaunchConfiguration[] candidates = manager
.getLaunchConfigurations(type);
String name = null;
if (resource.getType() == IResource.FILE) {
name = getQualifiedName((IFile) resource);
}
for (ILaunchConfiguration config : candidates) {
String fileName = config.getAttribute(XDF_FILE, "");
if (fileName.equals(name)) {
configs.add(config);
}
}
return configs.toArray(new ILaunchConfiguration[] {});
} catch (CoreException e) {
e.printStackTrace();
return null;
}
}
public IResource getLaunchableResource(IEditorPart editorpart) {
IEditorInput input = editorpart.getEditorInput();
if (input instanceof IFileEditorInput) {
return ((IFileEditorInput) input).getFile();
}
return null;
}
public IResource getLaunchableResource(ISelection selection) {
if (selection instanceof IStructuredSelection) {
IStructuredSelection ssel = (IStructuredSelection) selection;
Object obj = ssel.getFirstElement();
if (obj instanceof IResource) {
return (IResource) obj;
}
}
return null;
}
private Shell getShell() {
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
return window.getShell();
}
@Override
public void launch(IEditorPart editor, String mode) {
IResource resource = getLaunchableResource(editor);
if (resource != null) {
chooseAndLaunch(resource, getConfigurations(resource));
}
}
@Override
public void launch(ISelection selection, String mode) {
IResource resource = getLaunchableResource(selection);
if (resource != null) {
chooseAndLaunch(resource, getConfigurations(resource));
}
}
}