blob: c66458fc915c16fada469fd104b8a0d2fc61d963 [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/org/documents/epl-v10.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ide.eclipse.adt.internal.launch;
import com.android.ide.common.xml.ManifestData;
import com.android.ide.common.xml.ManifestData.Activity;
import com.android.ide.eclipse.adt.internal.editors.IconFactory;
import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper;
import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper;
import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper.IProjectChooserFilter;
import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper.NonLibraryProjectOnlyFilter;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
import org.eclipse.debug.ui.ILaunchConfigurationTab;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Text;
import java.util.ArrayList;
/**
* Class for the main launch configuration tab.
*/
public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
/**
*
*/
public static final String LAUNCH_TAB_IMAGE = "mainLaunchTab"; //$NON-NLS-1$
protected static final String EMPTY_STRING = ""; //$NON-NLS-1$
protected Text mProjText;
private Button mProjButton;
private Combo mActivityCombo;
private final ArrayList<Activity> mActivities = new ArrayList<Activity>();
private WidgetListener mListener = new WidgetListener();
private Button mDefaultActionButton;
private Button mActivityActionButton;
private Button mDoNothingActionButton;
private int mLaunchAction = LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION;
private ProjectChooserHelper mProjectChooserHelper;
/**
* A listener which handles widget change events for the controls in this
* tab.
*/
private class WidgetListener implements ModifyListener, SelectionListener {
@Override
public void modifyText(ModifyEvent e) {
IProject project = checkParameters();
loadActivities(project);
setDirty(true);
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {/* do nothing */
}
@Override
public void widgetSelected(SelectionEvent e) {
Object source = e.getSource();
if (source == mProjButton) {
handleProjectButtonSelected();
} else {
checkParameters();
}
}
}
public MainLaunchConfigTab() {
}
protected IProjectChooserFilter getProjectFilter() {
return new NonLibraryProjectOnlyFilter();
}
@Override
public void createControl(Composite parent) {
mProjectChooserHelper = new ProjectChooserHelper(parent.getShell(), getProjectFilter());
Font font = parent.getFont();
Composite comp = new Composite(parent, SWT.NONE);
setControl(comp);
GridLayout topLayout = new GridLayout();
topLayout.verticalSpacing = 0;
comp.setLayout(topLayout);
comp.setFont(font);
createProjectEditor(comp);
createVerticalSpacer(comp, 1);
// create the combo for the activity chooser
Group group = new Group(comp, SWT.NONE);
group.setText("Launch Action:");
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
group.setLayoutData(gd);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
group.setLayout(layout);
group.setFont(font);
mDefaultActionButton = new Button(group, SWT.RADIO);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
mDefaultActionButton.setLayoutData(gd);
mDefaultActionButton.setText("Launch Default Activity");
mDefaultActionButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// event are received for both selection and deselection, so we only process
// the selection event to avoid doing it twice.
if (mDefaultActionButton.getSelection() == true) {
mLaunchAction = LaunchConfigDelegate.ACTION_DEFAULT;
mActivityCombo.setEnabled(false);
checkParameters();
}
}
});
mActivityActionButton = new Button(group, SWT.RADIO);
mActivityActionButton.setText("Launch:");
mActivityActionButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// event are received for both selection and deselection, so we only process
// the selection event to avoid doing it twice.
if (mActivityActionButton.getSelection() == true) {
mLaunchAction = LaunchConfigDelegate.ACTION_ACTIVITY;
mActivityCombo.setEnabled(true);
checkParameters();
}
}
});
mActivityCombo = new Combo(group, SWT.DROP_DOWN | SWT.READ_ONLY);
gd = new GridData(GridData.FILL_HORIZONTAL);
mActivityCombo.setLayoutData(gd);
mActivityCombo.clearSelection();
mActivityCombo.setEnabled(false);
mActivityCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
checkParameters();
}
});
mDoNothingActionButton = new Button(group, SWT.RADIO);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
mDoNothingActionButton.setLayoutData(gd);
mDoNothingActionButton.setText("Do Nothing");
mDoNothingActionButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// event are received for both selection and deselection, so we only process
// the selection event to avoid doing it twice.
if (mDoNothingActionButton.getSelection() == true) {
mLaunchAction = LaunchConfigDelegate.ACTION_DO_NOTHING;
mActivityCombo.setEnabled(false);
checkParameters();
}
}
});
}
@Override
public String getName() {
return "Android";
}
@Override
public Image getImage() {
return IconFactory.getInstance().getIcon(LAUNCH_TAB_IMAGE);
}
@Override
public void performApply(ILaunchConfigurationWorkingCopy configuration) {
configuration.setAttribute(
IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, mProjText.getText());
configuration.setAttribute(
IJavaLaunchConfigurationConstants.ATTR_ALLOW_TERMINATE, true);
// add the launch mode
configuration.setAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION, mLaunchAction);
// add the activity
int selection = mActivityCombo.getSelectionIndex();
if (mActivities != null && selection >=0 && selection < mActivities.size()) {
configuration.setAttribute(LaunchConfigDelegate.ATTR_ACTIVITY,
mActivities.get(selection).getName());
}
// link the project and the launch config.
mapResources(configuration);
}
@Override
public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
configuration.setAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION,
LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION);
}
/**
* Creates the widgets for specifying a main type.
*
* @param parent the parent composite
*/
protected void createProjectEditor(Composite parent) {
Font font = parent.getFont();
Group group = new Group(parent, SWT.NONE);
group.setText("Project:");
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
group.setLayoutData(gd);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
group.setLayout(layout);
group.setFont(font);
mProjText = new Text(group, SWT.SINGLE | SWT.BORDER);
gd = new GridData(GridData.FILL_HORIZONTAL);
mProjText.setLayoutData(gd);
mProjText.setFont(font);
mProjText.addModifyListener(mListener);
mProjButton = createPushButton(group, "Browse...", null);
mProjButton.addSelectionListener(mListener);
}
/**
* returns the default listener from this class. For all subclasses this
* listener will only provide the functi Jaonality of updating the current
* tab
*
* @return a widget listener
*/
protected WidgetListener getDefaultListener() {
return mListener;
}
/**
* Return the {@link IJavaProject} corresponding to the project name in the project
* name text field, or null if the text does not match a project name.
* @param javaModel the Java Model object corresponding for the current workspace root.
* @return a IJavaProject object or null.
*/
protected IJavaProject getJavaProject(IJavaModel javaModel) {
String projectName = mProjText.getText().trim();
if (projectName.length() < 1) {
return null;
}
return javaModel.getJavaProject(projectName);
}
/**
* Show a dialog that lets the user select a project. This in turn provides
* context for the main type, allowing the user to key a main type name, or
* constraining the search for main types to the specified project.
*/
protected void handleProjectButtonSelected() {
IJavaProject javaProject = mProjectChooserHelper.chooseJavaProject(
mProjText.getText().trim(),
"Please select a project to launch");
if (javaProject == null) {
return;
}// end if
String projectName = javaProject.getElementName();
mProjText.setText(projectName);
// get the list of activities and fill the combo
IProject project = javaProject.getProject();
loadActivities(project);
}// end handle selected
/**
* Initializes this tab's controls with values from the given
* launch configuration. This method is called when
* a configuration is selected to view or edit, after this
* tab's control has been created.
*
* @param config launch configuration
*
* @see ILaunchConfigurationTab
*/
@Override
public void initializeFrom(ILaunchConfiguration config) {
String projectName = EMPTY_STRING;
try {
projectName = config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME,
EMPTY_STRING);
}// end try
catch (CoreException ce) {
}
mProjText.setText(projectName);
IProject proj = mProjectChooserHelper.getAndroidProject(projectName);
loadActivities(proj);
// load the launch action.
mLaunchAction = LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION;
try {
mLaunchAction = config.getAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION,
mLaunchAction);
} catch (CoreException e) {
// nothing to be done really. launchAction will keep its default value.
}
mDefaultActionButton.setSelection(mLaunchAction == LaunchConfigDelegate.ACTION_DEFAULT);
mActivityActionButton.setSelection(mLaunchAction == LaunchConfigDelegate.ACTION_ACTIVITY);
mDoNothingActionButton.setSelection(
mLaunchAction == LaunchConfigDelegate.ACTION_DO_NOTHING);
// now look for the activity and load it if present, otherwise, revert
// to the current one.
String activityName = EMPTY_STRING;
try {
activityName = config.getAttribute(LaunchConfigDelegate.ATTR_ACTIVITY, EMPTY_STRING);
}// end try
catch (CoreException ce) {
// nothing to be done really. activityName will stay empty
}
if (mLaunchAction != LaunchConfigDelegate.ACTION_ACTIVITY) {
mActivityCombo.setEnabled(false);
mActivityCombo.clearSelection();
} else {
mActivityCombo.setEnabled(true);
if (activityName == null || activityName.equals(EMPTY_STRING)) {
mActivityCombo.clearSelection();
} else if (mActivities != null && mActivities.size() > 0) {
// look for the name of the activity in the combo.
boolean found = false;
for (int i = 0 ; i < mActivities.size() ; i++) {
if (activityName.equals(mActivities.get(i).getName())) {
found = true;
mActivityCombo.select(i);
break;
}
}
// if we haven't found a matching activity we clear the combo selection
if (found == false) {
mActivityCombo.clearSelection();
}
}
}
}
/**
* Associates the launch config and the project. This allows Eclipse to delete the launch
* config when the project is deleted.
*
* @param config the launch config working copy.
*/
protected void mapResources(ILaunchConfigurationWorkingCopy config) {
// get the java model
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IJavaModel javaModel = JavaCore.create(workspaceRoot);
// get the IJavaProject described by the text field.
IJavaProject javaProject = getJavaProject(javaModel);
IResource[] resources = null;
if (javaProject != null) {
resources = AndroidLaunchController.getResourcesToMap(javaProject.getProject());
}
config.setMappedResources(resources);
}
/**
* Loads the ui with the activities of the specified project, and stores the
* activities in <code>mActivities</code>.
* <p/>
* First activity is selected by default if present.
*
* @param project The project to load the activities from.
*/
private void loadActivities(IProject project) {
if (project != null) {
// parse the manifest for the list of activities.
ManifestData manifestData = AndroidManifestHelper.parseForData(project);
if (manifestData != null) {
Activity[] activities = manifestData.getActivities();
mActivities.clear();
mActivityCombo.removeAll();
for (Activity activity : activities) {
if (activity.isExported() && activity.hasAction()) {
mActivities.add(activity);
mActivityCombo.add(activity.getName());
}
}
if (mActivities.size() > 0) {
if (mLaunchAction == LaunchConfigDelegate.ACTION_ACTIVITY) {
mActivityCombo.setEnabled(true);
}
} else {
mActivityCombo.setEnabled(false);
}
// the selection will be set when we update the ui from the current
// config object.
mActivityCombo.clearSelection();
return;
}
}
// if we reach this point, either project is null, or we got an exception during
// the parsing. In either case, we empty the activity list.
mActivityCombo.removeAll();
mActivities.clear();
}
/**
* Checks the parameters for correctness, and update the error message and buttons.
* @return the current IProject of this launch config.
*/
private IProject checkParameters() {
try {
//test the project name first!
String text = mProjText.getText();
if (text.length() == 0) {
setErrorMessage("Project Name is required!");
} else if (text.matches("[a-zA-Z0-9_ \\.-]+") == false) {
setErrorMessage("Project name contains unsupported characters!");
} else {
IJavaProject[] projects = mProjectChooserHelper.getAndroidProjects(null);
IProject found = null;
for (IJavaProject javaProject : projects) {
if (javaProject.getProject().getName().equals(text)) {
found = javaProject.getProject();
break;
}
}
if (found != null) {
setErrorMessage(null);
} else {
setErrorMessage(String.format("There is no android project named '%1$s'",
text));
}
return found;
}
} finally {
updateLaunchConfigurationDialog();
}
return null;
}
}