/* Copyright (C) 2009 Mobile Sorcery AB
This program is free software; you can redistribute it and/or modify it
under the terms of the Eclipse Public License v1.0.
This program 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 v1.0 for
more details.
You should have received a copy of the Eclipse Public License v1.0 along
with this program. It is also available at http://www.eclipse.org/legal/epl-v10.html
*/
package com.mobilesorcery.sdk.ui.internal.launch;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
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.ILaunchShortcut2;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
import com.mobilesorcery.sdk.core.CoreMoSyncPlugin;
import com.mobilesorcery.sdk.core.ILaunchConstants;
import com.mobilesorcery.sdk.core.launch.AutomaticEmulatorLauncher;
import com.mobilesorcery.sdk.core.launch.IEmulatorLauncher;
import com.mobilesorcery.sdk.internal.launch.EmulatorLaunchConfigurationDelegate;
public class MoreLaunchShortCut implements ILaunchShortcut2 {
private static MoreLaunchShortCut instance = new MoreLaunchShortCut();
public static MoreLaunchShortCut getDefault() {
return instance;
}
@Override
public void launch(ISelection selection, String mode) {
launch(getProjectFromSelection(selection), mode);
}
private IProject getProjectFromSelection(ISelection selection) {
if (selection instanceof IStructuredSelection) {
return getProjectFromSelection(((IStructuredSelection) selection).toArray());
}
return null;
}
private IProject getProjectFromSelection(Object[] selectionArray) {
IProject project = null;
for (int i = 0; project == null && i < selectionArray.length; i++) {
Object selection = selectionArray[i];
if (selection instanceof IEditorPart) {
selection = ((IEditorPart) selection).getEditorInput();
}
if (selection instanceof IAdaptable) {
selection = ((IAdaptable) selection).getAdapter(IResource.class);
}
if (selection instanceof IResource) {
project = ((IResource) selection).getProject();
}
}
return project;
}
private void launch(IProject project, String mode) {
if (project != null) {
ILaunchConfiguration config = findLaunchConfiguration(project, mode);
if (config != null) {
try {
DebugUITools.buildAndLaunch(config, mode, new NullProgressMonitor());
} catch (CoreException e) {
ErrorDialog.openError(getShell(), "Error Launching " + config.getName(), e.getMessage(), e.getStatus());
}
}
}
}
@Override
public void launch(IEditorPart part, String mode) {
launch(getProjectFromSelection(new Object[] { part }), mode);
}
private Map<String, Object> getDefaultParams() {
Map<String, Object> emulator = new HashMap<String, Object>();
emulator.put(ILaunchConstants.ON_DEVICE, false);
return emulator;
}
private ILaunchConfiguration findLaunchConfiguration(IProject project, String mode) {
return findLaunchConfiguration(project, mode, getDefaultParams());
}
public ILaunchConfiguration findLaunchConfiguration(IProject project, String mode, Map<String, Object> matchingParameters) {
ILaunchConfiguration configuration = null;
List candidateConfigs = getCandidateConfigs(project, mode, matchingParameters);
int candidateCount = candidateConfigs.size();
if (candidateCount < 1) {
configuration = createConfiguration(project, mode, matchingParameters);
} else if (candidateCount == 1) {
configuration = (ILaunchConfiguration) candidateConfigs.get(0);
} else {
ILaunchConfiguration config = chooseConfiguration(candidateConfigs, mode);
if (config != null) {
configuration = config;
}
}
return configuration;
}
private static ILaunchConfigurationType getMoreConfigType() {
ILaunchManager lm = DebugPlugin.getDefault().getLaunchManager();
ILaunchConfigurationType configType = lm.getLaunchConfigurationType(EmulatorLaunchConfigurationDelegate.ID);
return configType;
}
protected ILaunchConfigurationType getConfigType() {
return getMoreConfigType();
}
/**
* Clients should override.
* @return
*/
protected String getPreferredLauncherId() {
return AutomaticEmulatorLauncher.ID;
}
public ILaunchConfiguration createConfiguration(IProject project, String mode, Map<String, Object> parameters) {
return createConfiguration(project, mode, getPreferredLauncherId(), parameters);
}
public ILaunchConfiguration createConfiguration(IProject project, String mode, String launcherId, Map<String, Object> parameters) {
ILaunchConfiguration config = null;
try {
ILaunchConfigurationType configType = getConfigType();
boolean onDevice = Boolean.TRUE.equals(parameters.get(ILaunchConstants.ON_DEVICE));
String basename = project.getName() + (onDevice ? " - On device" : "");
String launchConfigName = DebugPlugin.getDefault().getLaunchManager().generateLaunchConfigurationName(basename);
ILaunchConfigurationWorkingCopy wc = configType.newInstance(null, launchConfigName);
if ("run".equals(mode)) {
wc.setAttribute(DebugPlugin.ATTR_PROCESS_FACTORY_ID, "com.mobilesorcery.sdk.builder.nonterminableprocessfactory");
}
DebugUITools.setLaunchPerspective(configType, ILaunchManager.RUN_MODE, IDebugUIConstants.PERSPECTIVE_DEFAULT);
DebugUITools.setLaunchPerspective(configType, ILaunchManager.DEBUG_MODE, IDebugUIConstants.PERSPECTIVE_DEFAULT);
EmulatorLaunchConfigurationDelegate.configureLaunchConfigForSourceLookup(wc);
wc.setAttribute(ILaunchConstants.PROJECT, project.getName());
// Let the launcher add its own attributes
IEmulatorLauncher launcher = CoreMoSyncPlugin.getDefault().getEmulatorLauncher(launcherId);
wc.setAttribute(ILaunchConstants.LAUNCH_DELEGATE_ID, launcherId);
launcher.setDefaultAttributes(wc);
// Bah. Only booleans and strings for now
for (Map.Entry<String, Object> parameter : parameters.entrySet()) {
Object value = parameter.getValue();
String key = parameter.getKey();
if (value instanceof Boolean) {
wc.setAttribute(key, (Boolean) value);
} else if (value instanceof String) {
wc.setAttribute(key, (String) value);
} else if (value instanceof List) {
wc.setAttribute(key, (List) value);
} else {
throw new CoreException(new Status(IStatus.ERROR, CoreMoSyncPlugin.PLUGIN_ID, "Illegal type"));
}
}
config = wc.doSave();
} catch (CoreException ce) {
CoreMoSyncPlugin.getDefault().getLog().log(
new Status(IStatus.WARNING, CoreMoSyncPlugin.PLUGIN_ID, "Could not create launch configuration", ce));
}
return config;
}
/**
* Returns the configuration to launch with (or null if none, in which case a default configuration will be selected)
* @return
*/
protected String getInitialConfigurationId(IProject project, String mode) {
return null;
}
public List<ILaunchConfiguration> getCandidateConfigs(IProject project, String mode, Map<String, Object> matchingParameters) {
ILaunchConfigurationType configType = getConfigType();
List<ILaunchConfiguration> candidateConfigs = Collections.EMPTY_LIST;
if (project != null) {
try {
ILaunchConfiguration[] configs = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(configType);
candidateConfigs = new ArrayList<ILaunchConfiguration>(configs.length);
for (int i = 0; i < configs.length; i++) {
ILaunchConfiguration config = configs[i];
if (doesConfigMatch(config, project, mode, matchingParameters)) {
candidateConfigs.add(config);
}
}
} catch (CoreException ce) {
CoreMoSyncPlugin.getDefault().getLog().log(
new Status(IStatus.WARNING, CoreMoSyncPlugin.PLUGIN_ID, "Could not find launch configurations", ce));
}
}
return candidateConfigs;
}
private boolean doesConfigMatch(ILaunchConfiguration config, IProject project, String mode, Map<String, Object> matchingParameters) throws CoreException {
return EmulatorLaunchConfigurationDelegate.doesConfigMatch(config, project, mode, matchingParameters);
}
private ILaunchConfiguration chooseConfiguration(List configList, String mode) {
IDebugModelPresentation labelProvider = DebugUITools.newDebugModelPresentation();
ElementListSelectionDialog dialog = new ElementListSelectionDialog(getShell(), labelProvider);
dialog.setElements(configList.toArray());
dialog.setTitle("MoSync Emulator launch configuration");
dialog.setMessage("Select launch configuration");
dialog.setMultipleSelection(false);
int result = dialog.open();
labelProvider.dispose();
if (result == ElementListSelectionDialog.OK) {
return (ILaunchConfiguration) dialog.getFirstResult();
}
return null;
}
private Shell getShell() {
Shell shell = null;
IWorkbenchWindow workbenchWindow = CoreMoSyncPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow();
if (workbenchWindow != null) {
shell = workbenchWindow.getShell();
}
return shell;
}
// ILaunchShortcut2
@Override
public ILaunchConfiguration[] getLaunchConfigurations(ISelection selection) {
return getCandidateConfigs(getProjectFromSelection(selection), "run", getDefaultParams()).toArray(new ILaunchConfiguration[0]);
}
@Override
public ILaunchConfiguration[] getLaunchConfigurations(IEditorPart editorpart) {
return getCandidateConfigs(getProjectFromSelection(new Object[] { editorpart }), "run", getDefaultParams()).toArray(new ILaunchConfiguration[0]);
}
@Override
public IResource getLaunchableResource(ISelection selection) {
return getProjectFromSelection(selection);
}
@Override
public IResource getLaunchableResource(IEditorPart editorpart) {
return getProjectFromSelection(new Object[] { editorpart });
}
}