From 7641cd7668c2dda9d198cc660d58d845de677029 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Tue, 16 Mar 2010 10:14:01 -0700 Subject: [PATCH] ADT: New project properties panel for libraries. Change-Id: I21efbcfd4bfcb552e1ecceee7cc611efa6b737f3 --- .../src/com/android/ide/eclipse/adt/AdtPlugin.java | 2 +- .../manifest/model/UiManifestPkgAttrNode.java | 24 +- .../adt/internal/launch/EmulatorConfigTab.java | 2 +- .../adt/internal/launch/MainLaunchConfigTab.java | 54 ++-- .../junit/AndroidJUnitLaunchConfigurationTab.java | 162 +++++----- .../adt/internal/project/BaseProjectHelper.java | 19 +- .../adt/internal/project/ProjectChooserHelper.java | 74 ++++- .../eclipse/adt/internal/project/ProjectState.java | 33 ++ .../internal/properties/AndroidPropertyPage.java | 129 ++++++-- .../adt/internal/properties/LibraryProperties.java | 358 +++++++++++++++++++++ .../resources/manager/GlobalProjectMonitor.java | 3 +- .../android/ide/eclipse/adt/internal/sdk/Sdk.java | 95 +----- .../internal/wizards/export/ProjectCheckPage.java | 50 +-- .../newproject/NewTestProjectCreationPage.java | 2 +- .../wizards/newxmlfile/NewXmlFileCreationPage.java | 2 +- .../sdklib/internal/project/ProjectProperties.java | 10 + 16 files changed, 742 insertions(+), 277 deletions(-) create mode 100644 eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/properties/LibraryProperties.java diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java index 508a86f6a..6208b4576 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java @@ -1371,7 +1371,7 @@ public class AdtPlugin extends AbstractUIPlugin { // after the SDK is reloaded synchronized (Sdk.getLock()) { // get the project to refresh. - IJavaProject[] androidProjects = BaseProjectHelper.getAndroidProjects(); + IJavaProject[] androidProjects = BaseProjectHelper.getAndroidProjects(null /*filter*/); mPostLoadProjectsToResolve.addAll(Arrays.asList(androidProjects)); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/model/UiManifestPkgAttrNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/model/UiManifestPkgAttrNode.java index 5687ece17..faf5dccc5 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/model/UiManifestPkgAttrNode.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/model/UiManifestPkgAttrNode.java @@ -108,7 +108,7 @@ public class UiManifestPkgAttrNode extends UiTextAttributeNode { }); formText.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE)); SectionHelper.addControlTooltip(formText, desc.getTooltip()); - + Composite composite = toolkit.createComposite(parent); composite.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE)); GridLayout gl = new GridLayout(2, false); @@ -117,7 +117,7 @@ public class UiManifestPkgAttrNode extends UiTextAttributeNode { // Fixes missing text borders under GTK... also requires adding a 1-pixel margin // for the text field below toolkit.paintBordersFor(composite); - + final Text text = toolkit.createText(composite, getCurrentValue()); GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalIndent = 1; // Needed by the fixed composite borders under GTK @@ -126,7 +126,7 @@ public class UiManifestPkgAttrNode extends UiTextAttributeNode { setTextWidget(text); Button browseButton = toolkit.createButton(composite, "Browse...", SWT.PUSH); - + browseButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { @@ -134,9 +134,9 @@ public class UiManifestPkgAttrNode extends UiTextAttributeNode { doBrowseClick(); } }); - + } - + /* (non-java doc) * Adds a validator to the text field that calls managedForm.getMessageManager(). */ @@ -172,7 +172,7 @@ public class UiManifestPkgAttrNode extends UiTextAttributeNode { * Handles response to the Browse button by creating a Package dialog. * */ private void doBrowseClick() { - + // Display the list of AndroidManifest packages in a selection dialog ElementListSelectionDialog dialog = new ElementListSelectionDialog( getTextWidget().getShell(), @@ -219,7 +219,7 @@ public class UiManifestPkgAttrNode extends UiTextAttributeNode { private void doLabelClick() { // get the current package name String package_name = getTextWidget().getText().trim(); - + if (package_name.length() == 0) { createNewProject(); } else { @@ -231,13 +231,13 @@ public class UiManifestPkgAttrNode extends UiTextAttributeNode { * When the label is clicked and there's already a package name, this method * attempts to find the project matching the android package name and it attempts * to open the manifest editor. - * + * * @param package_name The android package name to find. Must not be null. */ private void displayExistingManifest(String package_name) { // Look for the first project that uses this package name - for (IJavaProject project : BaseProjectHelper.getAndroidProjects()) { + for (IJavaProject project : BaseProjectHelper.getAndroidProjects(null /*filter*/)) { // check that there is indeed a manifest file. IFile manifestFile = AndroidManifestParser.getManifest(project.getProject()); if (manifestFile == null) { @@ -257,7 +257,7 @@ public class UiManifestPkgAttrNode extends UiTextAttributeNode { } if (package_name.equals(parser.getPackage())) { - // Found the project. + // Found the project. IWorkbenchWindow win = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (win != null) { @@ -303,14 +303,14 @@ public class UiManifestPkgAttrNode extends UiTextAttributeNode { /** * Returns all the possible android package names that could be used. * The prefix is not used. - * + * * {@inheritDoc} */ @Override public String[] getPossibleValues(String prefix) { TreeSet packages = new TreeSet(); - for (IJavaProject project : BaseProjectHelper.getAndroidProjects()) { + for (IJavaProject project : BaseProjectHelper.getAndroidProjects(null /*filter*/)) { // check that there is indeed a manifest file. IFile manifestFile = AndroidManifestParser.getManifest(project.getProject()); if (manifestFile == null) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/EmulatorConfigTab.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/EmulatorConfigTab.java index 21163914d..36bd2fcfb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/EmulatorConfigTab.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/EmulatorConfigTab.java @@ -346,7 +346,7 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab { IProject project = null; // get the list of existing Android projects from the workspace. - IJavaProject[] projects = BaseProjectHelper.getAndroidProjects(); + IJavaProject[] projects = BaseProjectHelper.getAndroidProjects(null /*filter*/); if (projects != null) { // look for the project whose name we read from the configuration. for (IJavaProject p : projects) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/MainLaunchConfigTab.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/MainLaunchConfigTab.java index 2b57f30ad..2c96c9862 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/MainLaunchConfigTab.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/MainLaunchConfigTab.java @@ -20,6 +20,7 @@ import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.project.AndroidManifestParser; import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper; +import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper.NonLibraryProjectOnlyFilter; import com.android.ide.eclipse.adt.internal.project.AndroidManifestParser.Activity; import org.eclipse.core.resources.IProject; @@ -59,12 +60,12 @@ import java.util.ArrayList; public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { /** - * + * */ public static final String LAUNCH_TAB_IMAGE = "mainLaunchTab.png"; //$NON-NLS-1$ protected static final String EMPTY_STRING = ""; //$NON-NLS-1$ - + protected Text mProjText; private Button mProjButton; @@ -77,9 +78,9 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { 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. @@ -109,7 +110,8 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { } public void createControl(Composite parent) { - mProjectChooserHelper = new ProjectChooserHelper(parent.getShell()); + mProjectChooserHelper = new ProjectChooserHelper(parent.getShell(), + new NonLibraryProjectOnlyFilter()); Font font = parent.getFont(); Composite comp = new Composite(parent, SWT.NONE); @@ -175,7 +177,7 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { checkParameters(); } }); - + mDoNothingActionButton = new Button(group, SWT.RADIO); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; @@ -193,7 +195,7 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { } } }); - + } public String getName() { @@ -214,14 +216,14 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { // 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); } @@ -293,7 +295,7 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { }// end if String projectName = javaProject.getElementName(); mProjText.setText(projectName); - + // get the list of activities and fill the combo IProject project = javaProject.getProject(); loadActivities(project); @@ -304,9 +306,9 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { * 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 */ public void initializeFrom(ILaunchConfiguration config) { @@ -321,7 +323,7 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { IProject proj = mProjectChooserHelper.getAndroidProject(projectName); loadActivities(proj); - + // load the launch action. mLaunchAction = LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION; try { @@ -330,7 +332,7 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { } 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( @@ -363,7 +365,7 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { break; } } - + // if we haven't found a matching activity we clear the combo selection if (found == false) { mActivityCombo.clearSelection(); @@ -397,7 +399,7 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { * activities in mActivities. *

* First activity is selected by default if present. - * + * * @param project The project to load the activities from. */ private void loadActivities(IProject project) { @@ -412,14 +414,14 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { 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); @@ -427,11 +429,11 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { } else { mActivityCombo.setEnabled(false); } - + // the selection will be set when we update the ui from the current // config object. mActivityCombo.clearSelection(); - + return; } @@ -440,13 +442,13 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { // already so there's nothing to do. } } - + // 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. @@ -467,22 +469,22 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { 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; } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java index 8f162a6e4..565601167 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java @@ -100,7 +100,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat private Label mProjLabel; private Text mProjText; private Button mProjButton; - + // Test class UI widgets private Text mTestText; private Button mSearchButton; @@ -113,7 +113,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat private Button mContainerSearchButton; private Button mTestContainerRadioButton; private Button mTestRadioButton; - private Label mTestLabel; + private Label mTestLabel; // Android specific members private Image mTabIcon = null; @@ -128,27 +128,27 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat * @see org.eclipse.debug.ui.ILaunchConfigurationTab#createControl(org.eclipse.swt.widgets.Composite) */ public void createControl(Composite parent) { - mProjectChooserHelper = new ProjectChooserHelper(parent.getShell()); + mProjectChooserHelper = new ProjectChooserHelper(parent.getShell(), null /*filter*/); Composite comp = new Composite(parent, SWT.NONE); setControl(comp); GridLayout topLayout = new GridLayout(); topLayout.numColumns = 3; - comp.setLayout(topLayout); - + comp.setLayout(topLayout); + createSingleTestSection(comp); createTestContainerSelectionGroup(comp); - + createSpacer(comp); - + createInstrumentationGroup(comp); createSpacer(comp); - + Dialog.applyDialogFont(comp); // TODO: add help link here when available - //PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), + //PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), // IJUnitHelpContextIds.LAUNCH_CONFIGURATION_DIALOG_JUNIT_MAIN_TAB); validatePage(); } @@ -160,41 +160,41 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat gd.horizontalSpan = 3; label.setLayoutData(gd); } - + private void createSingleTestSection(Composite comp) { mTestRadioButton = new Button(comp, SWT.RADIO); - mTestRadioButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_oneTest); + mTestRadioButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_oneTest); GridData gd = new GridData(); gd.horizontalSpan = 3; - mTestRadioButton.setLayoutData(gd); + mTestRadioButton.setLayoutData(gd); mTestRadioButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (mTestRadioButton.getSelection()) { testModeChanged(); - } + } } }); - + mProjLabel = new Label(comp, SWT.NONE); - mProjLabel.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_project); + mProjLabel.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_project); gd = new GridData(); gd.horizontalIndent = 25; mProjLabel.setLayoutData(gd); - + mProjText = new Text(comp, SWT.SINGLE | SWT.BORDER); mProjText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mProjText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent evt) { validatePage(); - updateLaunchConfigurationDialog(); - mSearchButton.setEnabled(mTestRadioButton.getSelection() && + updateLaunchConfigurationDialog(); + mSearchButton.setEnabled(mTestRadioButton.getSelection() && mProjText.getText().length() > 0); } }); - + mProjButton = new Button(comp, SWT.PUSH); - mProjButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_browse); + mProjButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_browse); mProjButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent evt) { @@ -202,14 +202,14 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat } }); setButtonGridData(mProjButton); - + mTestLabel = new Label(comp, SWT.NONE); gd = new GridData(); gd.horizontalIndent = 25; mTestLabel.setLayoutData(gd); - mTestLabel.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_test); - - + mTestLabel.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_test); + + mTestText = new Text(comp, SWT.SINGLE | SWT.BORDER); mTestText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mTestText.addModifyListener(new ModifyListener() { @@ -218,10 +218,10 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat updateLaunchConfigurationDialog(); } }); - + mSearchButton = new Button(comp, SWT.PUSH); mSearchButton.setEnabled(mProjText.getText().length() > 0); - mSearchButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_search); + mSearchButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_search); mSearchButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent evt) { @@ -229,9 +229,9 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat } }); setButtonGridData(mSearchButton); - + new Label(comp, SWT.NONE); - + mTestMethodLabel = new Label(comp, SWT.NONE); mTestMethodLabel.setText(""); //$NON-NLS-1$ gd = new GridData(); @@ -242,7 +242,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat private void createTestContainerSelectionGroup(Composite comp) { mTestContainerRadioButton = new Button(comp, SWT.RADIO); mTestContainerRadioButton.setText( - "Run all tests in the selected project, or package"); + "Run all tests in the selected project, or package"); GridData gd = new GridData(); gd.horizontalSpan = 3; mTestContainerRadioButton.setLayoutData(gd); @@ -268,23 +268,23 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat }); mContainerSearchButton = new Button(comp, SWT.PUSH); - mContainerSearchButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_search); + mContainerSearchButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_search); mContainerSearchButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent evt) { handleContainerSearchButtonSelected(); } }); - setButtonGridData(mContainerSearchButton); + setButtonGridData(mContainerSearchButton); } - + private void createInstrumentationGroup(Composite comp) { Label loaderLabel = new Label(comp, SWT.NONE); loaderLabel.setText("Instrumentation runner:"); GridData gd = new GridData(); gd.horizontalIndent = 0; loaderLabel.setLayoutData(gd); - + mInstrumentationCombo = new Combo(comp, SWT.DROP_DOWN | SWT.READ_ONLY); gd = new GridData(GridData.FILL_HORIZONTAL); mInstrumentationCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); @@ -302,7 +302,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat IJavaElement javaElement = chooseContainer(mContainerElement); if (javaElement != null) { setContainerElement(javaElement); - } + } } private void setContainerElement(IJavaElement javaElement) { @@ -324,17 +324,17 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat } catch (CoreException ce) { // ignore } - + if (containerHandle.length() > 0) { updateTestContainerFromConfig(config); } else { updateTestTypeFromConfig(config); - } + } IProject proj = mProjectChooserHelper.getAndroidProject(projectName); loadInstrumentations(proj); updateInstrumentationFromConfig(config); - + validatePage(); } @@ -358,7 +358,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat } if (!found) { mInstrumentationCombo.clearSelection(); - } + } } private String updateProjectFromConfig(ILaunchConfiguration config) { @@ -386,18 +386,18 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat } mTestRadioButton.setSelection(true); setEnableSingleTestGroup(true); - setEnableContainerTestGroup(false); + setEnableContainerTestGroup(false); mTestContainerRadioButton.setSelection(false); mTestText.setText(testTypeName); - mContainerText.setText(EMPTY_STRING); + mContainerText.setText(EMPTY_STRING); setTestMethodLabel(mOriginalTestMethodName); } private void setTestMethodLabel(String testMethodName) { if (!EMPTY_STRING.equals(testMethodName)) { mTestMethodLabel.setText( - JUnitMessages.JUnitLaunchConfigurationTab_label_method + - mOriginalTestMethodName); + JUnitMessages.JUnitLaunchConfigurationTab_label_method + + mOriginalTestMethodName); } else { mTestMethodLabel.setText(EMPTY_STRING); } @@ -417,14 +417,14 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat } if (containerElement != null) { mContainerElement = containerElement; - } + } mTestContainerRadioButton.setSelection(true); setEnableSingleTestGroup(false); - setEnableContainerTestGroup(true); + setEnableContainerTestGroup(true); mTestRadioButton.setSelection(false); if (mContainerElement != null) { mContainerText.setText(getPresentationName(mContainerElement)); - } + } mTestText.setText(EMPTY_STRING); } @@ -434,9 +434,9 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat */ public void performApply(ILaunchConfigurationWorkingCopy config) { if (mTestContainerRadioButton.getSelection() && mContainerElement != null) { - config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, + config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, mContainerElement.getJavaProject().getElementName()); - config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, + config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, mContainerElement.getHandleIdentifier()); config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, EMPTY_STRING); @@ -460,14 +460,14 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat AdtPlugin.log(e, "Error occurred saving configuration"); //$NON-NLS-1$ } AndroidJUnitLaunchConfigDelegate.setJUnitDefaults(config); - + config.setAttribute(AndroidJUnitLaunchConfigDelegate.ATTR_INSTR_NAME, getSelectedInstrumentation()); } private void mapResources(ILaunchConfigurationWorkingCopy config) throws CoreException { JUnitMigrationDelegate.mapResources(config); - } + } /* (non-Javadoc) * @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#dispose() @@ -510,9 +510,9 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat // remember the selected radio button radioSetting[0] = mTestRadioButton.getSelection(); radioSetting[1] = mTestContainerRadioButton.getSelection(); - + types = TestSearchEngine.findTests(getLaunchConfigurationDialog(), javaProject, - getTestKind()); + getTestKind()); } catch (InterruptedException e) { setErrorMessage(e.getMessage()); return; @@ -525,8 +525,8 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat } SelectionDialog dialog = new TestSelectionDialog(shell, types); - dialog.setTitle(JUnitMessages.JUnitLaunchConfigurationTab_testdialog_title); - dialog.setMessage(JUnitMessages.JUnitLaunchConfigurationTab_testdialog_message); + dialog.setTitle(JUnitMessages.JUnitLaunchConfigurationTab_testdialog_title); + dialog.setMessage(JUnitMessages.JUnitLaunchConfigurationTab_testdialog_message); if (dialog.open() == Window.CANCEL) { return; } @@ -534,7 +534,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat Object[] results = dialog.getResult(); if ((results == null) || (results.length < 1)) { return; - } + } IType type = (IType) results[0]; if (type != null) { @@ -562,7 +562,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat String projectName = project.getElementName(); mProjText.setText(projectName); - loadInstrumentations(project.getProject()); + loadInstrumentations(project.getProject()); } /** @@ -571,7 +571,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat */ private IJavaProject getJavaProject() { String projectName = getProjectName(); - return getJavaModel().getJavaProject(projectName); + return getJavaModel().getJavaProject(projectName); } /** @@ -618,14 +618,14 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat IJavaProject javaProject = getJavaModel().getJavaProject(projText); if (javaProject != null && javaProject.exists()) { setContainerElement(javaProject); - } + } } } validatePage(); updateLaunchConfigurationDialog(); } - private void validatePage() { + private void validatePage() { setErrorMessage(null); setMessage(null); @@ -648,7 +648,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat IResource.PROJECT); if (!status.isOK() || !Path.ROOT.isValidSegment(projectName)) { setErrorMessage(Messages.format( - JUnitMessages.JUnitLaunchConfigurationTab_error_invalidProjectName, + JUnitMessages.JUnitLaunchConfigurationTab_error_invalidProjectName, projectName)); return; } @@ -676,7 +676,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat JUnitMessages.JUnitLaunchConfigurationTab_error_test_class_not_found, new String[] { className, projectName })); return; - } + } } catch (CoreException e) { AdtPlugin.log(e, "validatePage failed"); //$NON-NLS-1$ } @@ -686,8 +686,8 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat private void validateJavaProject(IJavaProject javaProject) { if (!TestSearchEngine.hasTestCaseType(javaProject)) { - setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_testcasenotonpath); - return; + setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_testcasenotonpath); + return; } } @@ -706,7 +706,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat private String getSelectedInstrumentation() { int selectionIndex = mInstrumentationCombo.getSelectionIndex(); - if (mInstrumentations != null && selectionIndex >= 0 && + if (mInstrumentations != null && selectionIndex >= 0 && selectionIndex < mInstrumentations.length) { return mInstrumentations[selectionIndex]; } @@ -750,11 +750,11 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat private void initializeTestAttributes(IJavaElement javaElement, ILaunchConfigurationWorkingCopy config) { - if (javaElement != null && javaElement.getElementType() < IJavaElement.COMPILATION_UNIT) { + if (javaElement != null && javaElement.getElementType() < IJavaElement.COMPILATION_UNIT) { initializeTestContainer(javaElement, config); } else { initializeTestType(javaElement, config); - } + } } private void initializeTestContainer(IJavaElement javaElement, @@ -792,14 +792,14 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat testKindId = testKind.getId(); IType[] types = TestSearchEngine.findTests(getLaunchConfigurationDialog(), - javaElement, testKind); + javaElement, testKind); if ((types == null) || (types.length < 1)) { return; } // Simply grab the first main type found in the searched element name = types[0].getFullyQualifiedName('.'); - - } + + } } catch (InterruptedException ie) { // ignore } catch (InvocationTargetException ite) { @@ -809,7 +809,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat if (testKindId != null) { config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND, testKindId); - } + } initializeName(config, name); } @@ -817,7 +817,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat * @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName() */ public String getName() { - return JUnitMessages.JUnitLaunchConfigurationTab_tab_label; + return JUnitMessages.JUnitLaunchConfigurationTab_tab_label; } @SuppressWarnings("unchecked") @@ -837,7 +837,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat ViewerFilter filter = new TypedViewerFilter(acceptedClasses) { @Override public boolean select(Viewer viewer, Object parent, Object element) { - if (element instanceof IPackageFragmentRoot && + if (element instanceof IPackageFragmentRoot && ((IPackageFragmentRoot) element).isArchive()) { return false; } @@ -851,17 +851,17 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat } return super.select(viewer, parent, element); } - }; + }; AndroidJavaElementContentProvider provider = new AndroidJavaElementContentProvider(); ILabelProvider labelProvider = new JavaElementLabelProvider( - JavaElementLabelProvider.SHOW_DEFAULT); - ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), + JavaElementLabelProvider.SHOW_DEFAULT); + ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), labelProvider, provider); dialog.setValidator(validator); dialog.setComparator(new JavaElementComparator()); - dialog.setTitle(JUnitMessages.JUnitLaunchConfigurationTab_folderdialog_title); - dialog.setMessage(JUnitMessages.JUnitLaunchConfigurationTab_folderdialog_message); + dialog.setTitle(JUnitMessages.JUnitLaunchConfigurationTab_folderdialog_title); + dialog.setMessage(JUnitMessages.JUnitLaunchConfigurationTab_folderdialog_message); dialog.addFilter(filter); dialog.setInput(JavaCore.create(getWorkspaceRoot())); dialog.setInitialSelection(initElement); @@ -881,7 +881,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat /** * Returns the current Java element context from which to initialize * default settings, or null if none. - * + * * @return Java element context. */ private IJavaElement getContext() { @@ -948,13 +948,13 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat /** * Loads the UI with the instrumentations of the specified project, and stores the * instrumentations in mInstrumentations. - * + * * @param project the {@link IProject} to load the instrumentations from. */ private void loadInstrumentations(IProject project) { try { mInstrValidator = new InstrumentationRunnerValidator(project); - mInstrumentations = (mInstrValidator == null ? null : + mInstrumentations = (mInstrValidator == null ? null : mInstrValidator.getInstrumentationNames()); if (mInstrumentations != null) { mInstrumentationCombo.removeAll(); @@ -983,13 +983,13 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat extends StandardJavaElementContentProvider { /** - * Override parent to return only Android projects if at the root. Otherwise, use parent + * Override parent to return only Android projects if at the root. Otherwise, use parent * functionality. */ @Override public Object[] getChildren(Object element) { if (element instanceof IJavaModel) { - return BaseProjectHelper.getAndroidProjects((IJavaModel) element); + return BaseProjectHelper.getAndroidProjects((IJavaModel) element, null /*filter*/); } return super.getChildren(element); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/BaseProjectHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/BaseProjectHelper.java index 772470049..3712dc41c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/BaseProjectHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/BaseProjectHelper.java @@ -64,6 +64,13 @@ public final class BaseProjectHelper { public static final String TEST_CLASS_OK = null; /** + * Project filter to be used with {@link BaseProjectHelper#getAndroidProjects(IProjectFilter)}. + */ + public static interface IProjectFilter { + boolean accept(IProject project); + } + + /** * returns a list of source classpath for a specified project * @param javaProject * @return a list of path relative to the workspace root. @@ -360,13 +367,14 @@ public final class BaseProjectHelper { /** * Returns the list of android-flagged projects. This list contains projects that are opened * in the workspace and that are flagged as android project (through the android nature) + * @param filter an optional filter to control which android project are returned. Can be null. * @return an array of IJavaProject, which can be empty if no projects match. */ - public static IJavaProject[] getAndroidProjects() { + public static IJavaProject[] getAndroidProjects(IProjectFilter filter) { IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); IJavaModel javaModel = JavaCore.create(workspaceRoot); - return getAndroidProjects(javaModel); + return getAndroidProjects(javaModel, filter); } /** @@ -374,9 +382,10 @@ public final class BaseProjectHelper { * This list contains projects that are opened in the workspace and that are flagged as android * project (through the android nature) * @param javaModel the Java Model object corresponding for the current workspace root. + * @param filter an optional filter to control which android project are returned. Can be null. * @return an array of IJavaProject, which can be empty if no projects match. */ - public static IJavaProject[] getAndroidProjects(IJavaModel javaModel) { + public static IJavaProject[] getAndroidProjects(IJavaModel javaModel, IProjectFilter filter) { // get the java projects IJavaProject[] javaProjectList = null; try { @@ -397,7 +406,9 @@ public final class BaseProjectHelper { // check if it's an android project based on its nature try { if (project.hasNature(AndroidConstants.NATURE)) { - androidProjectList.add(javaProject); + if (filter == null || filter.accept(project)) { + androidProjectList.add(javaProject); + } } } catch (CoreException e) { // this exception, thrown by IProject.hasNature(), means the project either doesn't diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectChooserHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectChooserHelper.java index e6cac8a15..e549d5825 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectChooserHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectChooserHelper.java @@ -16,6 +16,9 @@ package com.android.ide.eclipse.adt.internal.project; +import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper.IProjectFilter; +import com.android.ide.eclipse.adt.internal.sdk.Sdk; + import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; @@ -35,6 +38,7 @@ import org.eclipse.ui.dialogs.ElementListSelectionDialog; public class ProjectChooserHelper { private final Shell mParentShell; + private final IProjectChooserFilter mFilter; /** * List of current android projects. Since the dialog is modal, we'll just get @@ -42,9 +46,57 @@ public class ProjectChooserHelper { */ private IJavaProject[] mAndroidProjects; - public ProjectChooserHelper(Shell parentShell) { + /** + * Interface to filter out some project displayed by {@link ProjectChooserHelper}. + * + * @see IProjectFilter + */ + public interface IProjectChooserFilter extends IProjectFilter { + /** + * Whether the Project Chooser can compute the project list once and cache the result. + *

If false the project list is recomputed every time the dialog is opened. + */ + boolean useCache(); + } + + /** + * An implementation of {@link IProjectChooserFilter} that only displays non-library projects. + */ + public final static class NonLibraryProjectOnlyFilter implements IProjectChooserFilter { + public boolean accept(IProject project) { + ProjectState state = Sdk.getProjectState(project); + return state.isLibrary() == false; + } + + public boolean useCache() { + return true; + } + } + + /** + * An implementation of {@link IProjectChooserFilter} that only displays library projects. + */ + public final static class LibraryProjectOnlyFilter implements IProjectChooserFilter { + public boolean accept(IProject project) { + ProjectState state = Sdk.getProjectState(project); + return state.isLibrary(); + } + + public boolean useCache() { + return true; + } + } + + /** + * Creates a new project chooser. + * @param parentShell the parent {@link Shell} for the dialog. + * @param filter a filter to only accept certain projects. Can be null. + */ + public ProjectChooserHelper(Shell parentShell, IProjectChooserFilter filter) { mParentShell = parentShell; + mFilter = filter; } + /** * Displays a project chooser dialog which lists all available projects with the Android nature. *

@@ -85,31 +137,33 @@ public class ProjectChooserHelper { } return null; } - + /** * Returns the list of Android projects. *

* Because this list can be time consuming, this class caches the list of project. * It is recommended to call this method instead of * {@link BaseProjectHelper#getAndroidProjects()}. - * + * * @param javaModel the java model. Can be null. */ public IJavaProject[] getAndroidProjects(IJavaModel javaModel) { - if (mAndroidProjects == null) { + // recompute only if we don't have the projects already or the filter is dynamic + // and prevent usage of a cache. + if (mAndroidProjects == null || (mFilter != null && mFilter.useCache() == false)) { if (javaModel == null) { - mAndroidProjects = BaseProjectHelper.getAndroidProjects(); + mAndroidProjects = BaseProjectHelper.getAndroidProjects(mFilter); } else { - mAndroidProjects = BaseProjectHelper.getAndroidProjects(javaModel); + mAndroidProjects = BaseProjectHelper.getAndroidProjects(javaModel, mFilter); } } - + return mAndroidProjects; } - + /** * Helper method to get the Android project with the given name - * + * * @param projectName the name of the project to find * @return the {@link IProject} for the Android project. null if not found. */ @@ -123,7 +177,7 @@ public class ProjectChooserHelper { break; } } - } + } return iproject; } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectState.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectState.java index 50ddc9c3f..a4c7f1524 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectState.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectState.java @@ -19,16 +19,21 @@ package com.android.ide.eclipse.adt.internal.project; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.SdkConstants; import com.android.sdklib.internal.project.ApkSettings; import com.android.sdklib.internal.project.ProjectProperties; import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -290,6 +295,15 @@ public final class ProjectState { } /** + * Returns the list of {@link LibraryState}. + */ + public List getLibraries() { + synchronized (mLibraries) { + return Collections.unmodifiableList(mLibraries); + } + } + + /** * Convenience method returning all the IProject objects for the resolved libraries. *

If some dependencies are not resolved (or their projects is not opened in Eclipse), * they will not show up in this list. @@ -474,6 +488,25 @@ public final class ProjectState { return null; } + /** + * Saves the default.properties file and refreshes it to make sure that it gets reloaded + * by Eclipse + */ + public void saveProperties() { + try { + mProperties.save(); + + IResource defaultProp = mProject.findMember(SdkConstants.FN_DEFAULT_PROPERTIES); + defaultProp.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + private IStatus replaceLibraryProperty(String oldValue, String newValue) { int index = 1; while (true) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/properties/AndroidPropertyPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/properties/AndroidPropertyPage.java index d9d66e9c1..f31e318de 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/properties/AndroidPropertyPage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/properties/AndroidPropertyPage.java @@ -16,9 +16,10 @@ package com.android.ide.eclipse.adt.internal.properties; +import com.android.ide.eclipse.adt.internal.project.ProjectState; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.internal.project.ApkSettings; +import com.android.sdklib.internal.project.ProjectProperties; import com.android.sdkuilib.internal.widgets.SdkTargetSelector; import org.eclipse.core.resources.IProject; @@ -27,9 +28,10 @@ import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Group; import org.eclipse.ui.IWorkbenchPropertyPage; import org.eclipse.ui.dialogs.PropertyPage; @@ -43,8 +45,10 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope private IProject mProject; private SdkTargetSelector mSelector; + private Button mIsLibrary; // APK-SPLIT: This is not yet supported, so we hide the UI // private Button mSplitByDensity; + private LibraryProperties mLibraryDependencies; public AndroidPropertyPage() { // pass @@ -66,10 +70,28 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope top.setLayoutData(new GridData(GridData.FILL_BOTH)); top.setLayout(new GridLayout(1, false)); - Label l = new Label(top, SWT.NONE); - l.setText("Project Build Target"); + Group targetGroup = new Group(top, SWT.NONE); + targetGroup.setLayoutData(new GridData(GridData.FILL_BOTH)); + targetGroup.setLayout(new GridLayout(1, false)); + targetGroup.setText("Project Build Target"); - mSelector = new SdkTargetSelector(top, targets); + mSelector = new SdkTargetSelector(targetGroup, targets); + + Group libraryGroup = new Group(top, SWT.NONE); + libraryGroup.setLayoutData(new GridData(GridData.FILL_BOTH)); + libraryGroup.setLayout(new GridLayout(1, false)); + libraryGroup.setText("Library"); + + mIsLibrary = new Button(libraryGroup, SWT.CHECK); + mIsLibrary.setText("Is Library"); + mIsLibrary.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + mLibraryDependencies.setEnabled(!mIsLibrary.getSelection()); + } + }); + + mLibraryDependencies = new LibraryProperties(libraryGroup); /* * APK-SPLIT: This is not yet supported, so we hide the UI @@ -83,28 +105,13 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope */ // fill the ui - Sdk currentSdk = Sdk.getCurrent(); - if (currentSdk != null && mProject.isOpen()) { - // get the target - IAndroidTarget target = currentSdk.getTarget(mProject); - if (target != null) { - mSelector.setSelection(target); - } - - /* - * APK-SPLIT: This is not yet supported, so we hide the UI - // get the project settings - ApkSettings settings = currentSdk.getApkSettings(mProject); - mSplitByDensity.setSelection(settings.isSplitByDpi()); - */ - } + fillUi(); + // add callbacks mSelector.setSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { - // look for the selection and validate the page if there is a selection - IAndroidTarget target = mSelector.getSelected(); - setValid(target != null); + updateValidity(); } }); @@ -118,16 +125,78 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope @Override public boolean performOk() { Sdk currentSdk = Sdk.getCurrent(); - if (currentSdk != null) { - ApkSettings apkSettings = new ApkSettings(); - /* - * APK-SPLIT: This is not yet supported, so we hide the UI - apkSettings.setSplitByDensity(mSplitByDensity.getSelection()); - */ + if (currentSdk != null && mProject.isOpen()) { + ProjectState state = Sdk.getProjectState(mProject); + + // simply update the project properties. Eclipse will be notified of the file change + // and will reload it smartly (detecting differences) and updating the ProjectState. + // See Sdk.mFileListener + ProjectProperties properties = null; + boolean mustSaveProp = false; + + IAndroidTarget newTarget = mSelector.getSelected(); + if (newTarget != state.getTarget()) { + properties = state.getProperties(); + properties.setProperty(ProjectProperties.PROPERTY_TARGET, newTarget.hashString()); + mustSaveProp = true; + } - currentSdk.setProject(mProject, mSelector.getSelected(), apkSettings); + if (mIsLibrary.getSelection() != state.isLibrary()) { + properties = state.getProperties(); + properties.setProperty(ProjectProperties.PROPERTY_LIBRARY, + Boolean.toString(mIsLibrary.getSelection())); + mustSaveProp = true; + } + + if (mLibraryDependencies.save(mIsLibrary.getSelection())) { + mustSaveProp = true; + } + + // TODO: update ApkSettings. + + if (mustSaveProp) { + state.saveProperties(); + } } return true; } + + @Override + protected void performDefaults() { + fillUi(); + updateValidity(); + } + + private void fillUi() { + if (Sdk.getCurrent() != null && mProject.isOpen()) { + ProjectState state = Sdk.getProjectState(mProject); + + // get the target + IAndroidTarget target = state.getTarget();; + if (target != null) { + mSelector.setSelection(target); + } + + mIsLibrary.setSelection(state.isLibrary()); + + mLibraryDependencies.setContent(state); + mLibraryDependencies.setEnabled(!state.isLibrary()); + + /* + * APK-SPLIT: This is not yet supported, so we hide the UI + // get the project settings + ApkSettings settings = currentSdk.getApkSettings(mProject); + mSplitByDensity.setSelection(settings.isSplitByDpi()); + */ + } + + } + + private void updateValidity() { + // look for the selection and validate the page if there is a selection + IAndroidTarget target = mSelector.getSelected(); + setValid(target != null); + } + } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/properties/LibraryProperties.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/properties/LibraryProperties.java new file mode 100644 index 000000000..6bcc0d33f --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/properties/LibraryProperties.java @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2010 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.properties; + +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper; +import com.android.ide.eclipse.adt.internal.project.ProjectState; +import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper.IProjectChooserFilter; +import com.android.ide.eclipse.adt.internal.project.ProjectState.LibraryState; +import com.android.ide.eclipse.adt.internal.sdk.Sdk; +import com.android.sdklib.internal.project.ProjectProperties; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + + +/** + * Self-contained UI to edit the library dependencies of a Project. + */ +final class LibraryProperties { + + private Composite mTop; + private Table mTable; + private Image mMatchIcon; + private Image mErrorIcon; + private Button mAddButton; + private Button mRemoveButton; + private Button mUpButton; + private Button mDownButton; + private ProjectChooserHelper mProjectChooser; + + private ProjectState mState; + private final List mItemDataList = new ArrayList(); + private boolean mMustSave = false; + + /** + * Internal struct to store library info in the table item. + */ + private final static class ItemData { + String relativePath; + IProject project; + } + + /** + * {@link IProjectChooserFilter} implementation that dynamically ignores libraries + * that are already dependencies. + */ + IProjectChooserFilter mFilter = new IProjectChooserFilter() { + public boolean accept(IProject project) { + // first check if it's a library + ProjectState state = Sdk.getProjectState(project); + if (state != null) { + if (state.isLibrary() == false || project == mState.getProject()) { + return false; + } + + // then check if the library is not already part of the dependencies. + for (ItemData data : mItemDataList) { + if (data.project == project) { + return false; + } + } + + return true; + } + + return false; + } + + public boolean useCache() { + return false; + } + }; + + LibraryProperties(Composite parent) { + + mMatchIcon = AdtPlugin.getImageDescriptor("/icons/match.png").createImage(); //$NON-NLS-1$ + mErrorIcon = AdtPlugin.getImageDescriptor("/icons/error.png").createImage(); //$NON-NLS-1$ + + + // Layout has 2 column + mTop = new Composite(parent, SWT.NONE); + mTop.setLayout(new GridLayout(2, false)); + mTop.setLayoutData(new GridData(GridData.FILL_BOTH)); + mTop.setFont(parent.getFont()); + mTop.addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + mMatchIcon.dispose(); + mErrorIcon.dispose(); + } + }); + + mTable = new Table(mTop, SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE); + mTable.setLayoutData(new GridData(GridData.FILL_BOTH)); + mTable.setHeaderVisible(true); + mTable.setLinesVisible(false); + mTable.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + resetEnabled(); + } + }); + + final TableColumn column0 = new TableColumn(mTable, SWT.NONE); + column0.setText("Reference"); + final TableColumn column1 = new TableColumn(mTable, SWT.NONE); + column1.setText("Project"); + + Composite buttons = new Composite(mTop, SWT.NONE); + buttons.setLayout(new GridLayout()); + buttons.setLayoutData(new GridData(GridData.FILL_VERTICAL)); + + mProjectChooser = new ProjectChooserHelper(parent.getShell(), mFilter); + + mAddButton = new Button(buttons, SWT.PUSH | SWT.FLAT); + mAddButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mAddButton.setText("Add..."); + mAddButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + IJavaProject javaProject = mProjectChooser.chooseJavaProject(null); + if (javaProject != null) { + IProject iProject = javaProject.getProject(); + IPath relativePath = Sdk.makeRelativeTo( + iProject.getLocation(), mState.getProject().getLocation()); + + addItem(relativePath.toString(), iProject, -1); + resetEnabled(); + mMustSave = true; + } + } + }); + + mRemoveButton = new Button(buttons, SWT.PUSH | SWT.FLAT); + mRemoveButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mRemoveButton.setText("Remove"); + mRemoveButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + // selection is ensured and in single mode. + TableItem selection = mTable.getSelection()[0]; + ItemData data = (ItemData) selection.getData(); + mItemDataList.remove(data); + mTable.remove(mTable.getSelectionIndex()); + resetEnabled(); + } + }); + + Label l = new Label(buttons, SWT.SEPARATOR | SWT.HORIZONTAL); + l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + mUpButton = new Button(buttons, SWT.PUSH | SWT.FLAT); + mUpButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mUpButton.setText("Up"); + mUpButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + int index = mTable.getSelectionIndex(); + ItemData data = mItemDataList.remove(index); + mTable.remove(index); + + // add at a lower index. + addItem(data.relativePath, data.project, index - 1); + + // reset the selection + mTable.select(index - 1); + resetEnabled(); + } + }); + + mDownButton = new Button(buttons, SWT.PUSH | SWT.FLAT); + mDownButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mDownButton.setText("Down"); + mDownButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + int index = mTable.getSelectionIndex(); + ItemData data = mItemDataList.remove(index); + mTable.remove(index); + + // add at a higher index. + addItem(data.relativePath, data.project, index + 1); + + // reset the selection + mTable.select(index + 1); + resetEnabled(); + } + }); + + adjustColumnsWidth(mTable, column0, column1); + } + + /** + * Sets or reset the content. + * @param state the {@link ProjectState} to display + */ + void setContent(ProjectState state) { + mState = state; + + // reset content + mTable.removeAll(); + mItemDataList.clear(); + + // get the libraries and make a copy of the data we need. + List libs = state.getLibraries(); + + for (LibraryState lib : libs) { + ProjectState libState = lib.getProjectState(); + addItem(lib.getRelativePath(), libState != null ? libState.getProject() : null, -1); + } + + mMustSave = false; + + resetEnabled(); + } + + /** + * Saves the state of the UI into the {@link ProjectState} object that was given to + * {@link #setContent(ProjectState)}. + *

This only saves the data into the {@link ProjectProperties} of the state, but does + * not update the {@link ProjectState} or the list of {@link LibraryState}. + * @param isLibrary the new library flag of the project. + * @return true if there was actually new data saved in the project state, false + * otherwise. + */ + boolean save(boolean isLibrary) { + boolean mustSave = mMustSave || (isLibrary && mState.getLibraries().size() > 0); + if (mustSave) { + // remove all previous library dependencies. + ProjectProperties props = mState.getProperties(); + Set keys = props.keySet(); + for (String key : keys) { + if (key.startsWith(ProjectProperties.PROPERTY_LIB_REF)) { + props.removeProperty(key); + } + } + + // now add the new libraries. + if (isLibrary == false) { + int index = 1; + for (ItemData data : mItemDataList) { + props.setProperty(ProjectProperties.PROPERTY_LIB_REF + index++, + data.relativePath); + } + } + } + + mMustSave = false; + return mustSave; + } + + /** + * Enables or disables the whole widget. + * @param enabled whether the widget must be enabled or not. + */ + void setEnabled(boolean enabled) { + if (enabled == false) { + mTable.setEnabled(false); + mAddButton.setEnabled(false); + mRemoveButton.setEnabled(false); + mUpButton.setEnabled(false); + mDownButton.setEnabled(false); + } else { + mTable.setEnabled(true); + mAddButton.setEnabled(true); + resetEnabled(); + } + } + + private void resetEnabled() { + int index = mTable.getSelectionIndex(); + mRemoveButton.setEnabled(index != -1); + mUpButton.setEnabled(index > 0); + mDownButton.setEnabled(index != -1 && index < mTable.getItemCount() - 1); + } + + /** + * Adds a new item and stores a {@link Stuff} into {@link #mStuff}. + * + * @param relativePath the relative path of the library entry + * @param project the associated IProject + * @param index if different than -1, the index at which to insert the item. + */ + private void addItem(String relativePath, IProject project, int index) { + ItemData data = new ItemData(); + data.relativePath = relativePath; + data.project = project; + TableItem item; + if (index == -1) { + mItemDataList.add(data); + item = new TableItem(mTable, SWT.NONE); + } else { + mItemDataList.add(index, data); + item = new TableItem(mTable, SWT.NONE, index); + } + item.setData(data); + item.setText(0, data.relativePath); + item.setImage( data.project != null ? mMatchIcon : mErrorIcon); + item.setText(1, data.project != null ? data.project.getName() : "?"); + } + + /** + * Adds a listener to adjust the columns width when the parent is resized. + *

+ * If we need something more fancy, we might want to use this: + * http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet77.java?view=co + */ + private void adjustColumnsWidth(final Table table, + final TableColumn column0, + final TableColumn column1) { + // Add a listener to resize the column to the full width of the table + table.addControlListener(new ControlAdapter() { + @Override + public void controlResized(ControlEvent e) { + Rectangle r = table.getClientArea(); + column0.setWidth(r.width * 50 / 100); // 50% + column1.setWidth(r.width * 50 / 100); // 50% + } + }); + } +} + diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java index 9666d444b..c6d16d457 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java @@ -361,7 +361,8 @@ public final class GlobalProjectMonitor { // get the list of opened android projects. IWorkspaceRoot workspaceRoot = mWorkspace.getRoot(); IJavaModel javaModel = JavaCore.create(workspaceRoot); - IJavaProject[] androidProjects = BaseProjectHelper.getAndroidProjects(javaModel); + IJavaProject[] androidProjects = BaseProjectHelper.getAndroidProjects(javaModel, + null /*filter*/); for (IJavaProject androidProject : androidProjects) { listener.projectOpenedWithWorkspace(androidProject.getProject()); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java index 2dc59817b..1948761de 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java @@ -34,7 +34,6 @@ import com.android.sdklib.ISdkLog; import com.android.sdklib.SdkConstants; import com.android.sdklib.SdkManager; import com.android.sdklib.internal.avd.AvdManager; -import com.android.sdklib.internal.project.ApkSettings; import com.android.sdklib.internal.project.ProjectProperties; import com.android.sdklib.internal.project.ProjectProperties.PropertyType; @@ -323,85 +322,6 @@ public final class Sdk { } /** - * Sets a new target and/or a new set of APK settings for a given project. - * - * @param project the project to receive the new apk configurations. - * @param target The new target to set, or null to not change the current target. - * @param settings a new {@link ApkSettings} object to set or null to not change - * the current settings. - */ - public void setProject(IProject project, IAndroidTarget target, - ApkSettings settings) { - if (target == null && settings == null) { - return; - } - - synchronized (sLock) { - boolean resolveProject = false; - - ProjectState state = getProjectState(project); - if (state == null) { - return; - } - - ProjectProperties properties = state.getProperties(); - - if (target != null) { - // look for the current target of the project - IAndroidTarget previousTarget = state.getTarget(); - - if (target != previousTarget) { - // save the target hash string in the project persistent property - properties.setProperty(ProjectProperties.PROPERTY_TARGET, target.hashString()); - - // put it in a local map for easy access. - state.setTarget(target); - - resolveProject = true; - } - } - - if (settings != null) { - state.setApkSettings(settings); - - // save the project settings into the project persistent property - settings.write(properties); - } - - // we are done with the modification. Save the property file. - try { - properties.save(); - } catch (IOException e) { - AdtPlugin.log(e, "Failed to save default.properties for project '%s'", - project.getName()); - } - - if (resolveProject) { - // force a resolve of the project by updating the classpath container. - // This will also force a recompile. - IJavaProject javaProject = JavaCore.create(project); - AndroidClasspathContainerInitializer.updateProjects( - new IJavaProject[] { javaProject }); - } else { - // always do a full clean/build. - try { - project.build(IncrementalProjectBuilder.CLEAN_BUILD, null); - } catch (CoreException e) { - // failed to build? force resolve instead. - IJavaProject javaProject = JavaCore.create(project); - AndroidClasspathContainerInitializer.updateProjects( - new IJavaProject[] { javaProject }); - } - } - - // finally, update the opened editors. - if (resolveProject) { - AdtPlugin.getDefault().updateTargetListeners(project); - } - } - } - - /** * Returns the {@link ProjectState} object associated with a given project. *

* This method is the only way to properly get the project's {@link ProjectState} @@ -968,9 +888,11 @@ public final class Sdk { // reload the libraries if needed if (diff.hasDiff()) { for (LibraryState removedState : diff.removed) { - unlinkLibrary(state, - removedState.getProjectState().getProject(), - false /*doInJob*/); + ProjectState removePState = removedState.getProjectState(); + if (removePState != null) { + unlinkLibrary(state, removePState.getProject(), + false /*doInJob*/); + } } if (diff.added) { @@ -989,7 +911,7 @@ public final class Sdk { } // need to force a full recompile. - iProject.build( IncrementalProjectBuilder.FULL_BUILD, monitor); + iProject.build(IncrementalProjectBuilder.FULL_BUILD, monitor); } // apply the new target if needed. @@ -1000,6 +922,9 @@ public final class Sdk { AndroidClasspathContainerInitializer.updateProjects( new IJavaProject[] { javaProject }); } + + // update the editors to reload with the new target + AdtPlugin.getDefault().updateTargetListeners(iProject); } } catch (CoreException e) { // This can't happen as it's only for closed project (or non existing) @@ -1291,7 +1216,7 @@ public final class Sdk { * @param base the IPath to base the relative path on. * @return the relative IPath */ - private static IPath makeRelativeTo(IPath target, IPath base) { + public static IPath makeRelativeTo(IPath target, IPath base) { //can't make relative if devices are not equal if (target.getDevice() != base.getDevice() && (target.getDevice() == null || !target.getDevice().equalsIgnoreCase(base.getDevice()))) diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ProjectCheckPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ProjectCheckPage.java index 4b8cb69ff..11a40e5e0 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ProjectCheckPage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ProjectCheckPage.java @@ -22,6 +22,7 @@ import com.android.ide.eclipse.adt.internal.project.AndroidManifestParser; import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper; import com.android.ide.eclipse.adt.internal.project.ProjectHelper; +import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper.NonLibraryProjectOnlyFilter; import com.android.ide.eclipse.adt.internal.wizards.export.ExportWizard.ExportWizardPage; import org.eclipse.core.resources.IFolder; @@ -45,7 +46,7 @@ import org.eclipse.swt.widgets.Text; import java.io.File; /** - * First Export Wizard Page. Display warning/errors. + * First Export Wizard Page. Display warning/errors. */ final class ProjectCheckPage extends ExportWizardPage { private final static String IMG_ERROR = "error.png"; //$NON-NLS-1$ @@ -71,7 +72,8 @@ final class ProjectCheckPage extends ExportWizardPage { } public void createControl(Composite parent) { - mProjectChooserHelper = new ProjectChooserHelper(parent.getShell()); + mProjectChooserHelper = new ProjectChooserHelper(parent.getShell(), + new NonLibraryProjectOnlyFilter()); mDisplay = parent.getDisplay(); GridLayout gl = null; @@ -80,7 +82,7 @@ final class ProjectCheckPage extends ExportWizardPage { mTopComposite = new Composite(parent, SWT.NONE); mTopComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); mTopComposite.setLayout(new GridLayout(1, false)); - + // composite for the project selection. Composite projectComposite = new Composite(mTopComposite, SWT.NONE); projectComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); @@ -130,11 +132,11 @@ final class ProjectCheckPage extends ExportWizardPage { if (project != null) { mProjectText.setText(project.getName()); } - + mFirstOnShow = false; } } - + private void buildErrorUi(IProject project) { // Show description the first time setErrorMessage(null); @@ -163,14 +165,14 @@ final class ProjectCheckPage extends ExportWizardPage { if (ProjectHelper.hasError(project, true)) { addError(mErrorComposite, "Project has compilation error(s)"); } - + // check the project output IFolder outputIFolder = BaseProjectHelper.getOutputFolder(project); if (outputIFolder != null) { String outputOsPath = outputIFolder.getLocation().toOSString(); String apkFilePath = outputOsPath + File.separator + project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE; - + File f = new File(apkFilePath); if (f.isFile() == false) { addError(mErrorComposite, @@ -191,12 +193,12 @@ final class ProjectCheckPage extends ExportWizardPage { true /* gatherData */, false /* markErrors */); Boolean debuggable = manifestParser.getDebuggable(); - + if (debuggable != null && debuggable == Boolean.TRUE) { addWarning(mErrorComposite, - "The manifest 'debuggable' attribute is set to true.\nYou should set it to false for applications that you release to the public."); + "The manifest 'debuggable' attribute is set to true.\nYou should set it to false for applications that you release to the public."); } - + // check for mapview stuff } } catch (CoreException e) { @@ -204,7 +206,7 @@ final class ProjectCheckPage extends ExportWizardPage { addError(mErrorComposite, "Unable to get project nature"); } } - + if (mHasMessage == false) { Label label = new Label(mErrorComposite, SWT.NONE); GridData gd = new GridData(GridData.FILL_HORIZONTAL); @@ -212,10 +214,10 @@ final class ProjectCheckPage extends ExportWizardPage { label.setLayoutData(gd); label.setText("No errors found. Click Next."); } - + mTopComposite.layout(); } - + /** * Adds an error label to a {@link Composite} object. * @param parent the Composite parent. @@ -225,17 +227,17 @@ final class ProjectCheckPage extends ExportWizardPage { if (mError == null) { mError = AdtPlugin.getImageLoader().loadImage(IMG_ERROR, mDisplay); } - + new Label(parent, SWT.NONE).setImage(mError); Label label = new Label(parent, SWT.NONE); label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); label.setText(message); - + setErrorMessage("Application cannot be exported due to the error(s) below."); setPageComplete(false); mHasMessage = true; } - + /** * Adds a warning label to a {@link Composite} object. * @param parent the Composite parent. @@ -245,26 +247,26 @@ final class ProjectCheckPage extends ExportWizardPage { if (mWarning == null) { mWarning = AdtPlugin.getImageLoader().loadImage(IMG_WARNING, mDisplay); } - + new Label(parent, SWT.NONE).setImage(mWarning); Label label = new Label(parent, SWT.NONE); label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); label.setText(message); - + mHasMessage = true; } - + /** * Checks the parameters for correctness, and update the error message and buttons. */ private void handleProjectNameChange() { setPageComplete(false); - + if (mErrorComposite != null) { mErrorComposite.dispose(); mErrorComposite = null; } - + // update the wizard with the new project mWizard.setProject(null); @@ -282,12 +284,12 @@ final class ProjectCheckPage extends ExportWizardPage { found = javaProject.getProject(); break; } - + } - + if (found != null) { setErrorMessage(null); - + // update the wizard with the new project mWizard.setProject(found); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java index 28855a28e..ce6e118af 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java @@ -523,7 +523,7 @@ public class NewTestProjectCreationPage extends WizardPage { } }); - mProjectChooserHelper = new ProjectChooserHelper(parent.getShell()); + mProjectChooserHelper = new ProjectChooserHelper(parent.getShell(), null /*filter*/); } else { // Part of NPW mode: no selection. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java index 4cedff2b3..dc4d8520e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java @@ -536,7 +536,7 @@ class NewXmlFileCreationPage extends WizardPage { onProjectBrowse(); } }); - mProjectChooserHelper = new ProjectChooserHelper(parent.getShell()); + mProjectChooserHelper = new ProjectChooserHelper(parent.getShell(), null /*filter*/); ++col; col = padWithEmptyCells(parent, col); diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java index b73c863aa..2fbaadd9e 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java @@ -24,7 +24,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.Map.Entry; /** @@ -236,6 +238,14 @@ public final class ProjectProperties { } /** + * Returns a set of the property keys. Unlike {@link Map#keySet()} this is not a view of the + * map keys. Modifying the returned {@link Set} will not impact the underlying {@link Map}. + */ + public synchronized Set keySet() { + return new HashSet(mProperties.keySet()); + } + + /** * Reloads the properties from the underlying file. */ public synchronized void reload() { -- 2.11.0