diff options
7 files changed, 582 insertions, 36 deletions
diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/AllocationInfo.java b/ddms/libs/ddmlib/src/com/android/ddmlib/AllocationInfo.java index ecf55ab..90bd7d4 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/AllocationInfo.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/AllocationInfo.java @@ -22,13 +22,14 @@ import java.util.Comparator; * Holds an Allocation information. */ public class AllocationInfo implements IStackTraceInfo { - private String mAllocatedClass; - private int mAllocationSize; - private short mThreadId; - private StackTraceElement[] mStackTrace; + private final String mAllocatedClass; + private final int mAllocNumber; + private final int mAllocationSize; + private final short mThreadId; + private final StackTraceElement[] mStackTrace; public static enum SortMode { - SIZE, CLASS, THREAD, IN_CLASS, IN_METHOD; + NUMBER, SIZE, CLASS, THREAD, IN_CLASS, IN_METHOD; } public final static class AllocationSorter implements Comparator<AllocationInfo> { @@ -58,6 +59,9 @@ public class AllocationInfo implements IStackTraceInfo { public int compare(AllocationInfo o1, AllocationInfo o2) { int diff = 0; switch (mSortMode) { + case NUMBER: + diff = o1.mAllocNumber - o2.mAllocNumber; + break; case SIZE: // pass, since diff is init with 0, we'll use SIZE compare below // as a back up anyway. @@ -113,8 +117,9 @@ public class AllocationInfo implements IStackTraceInfo { /* * Simple constructor. */ - AllocationInfo(String allocatedClass, int allocationSize, + AllocationInfo(int allocNumber, String allocatedClass, int allocationSize, short threadId, StackTraceElement[] stackTrace) { + mAllocNumber = allocNumber; mAllocatedClass = allocatedClass; mAllocationSize = allocationSize; mThreadId = threadId; @@ -122,6 +127,14 @@ public class AllocationInfo implements IStackTraceInfo { } /** + * Returns the allocation number. Allocations are numbered as they happen with the most + * recent one having the highest number + */ + public int getAllocNumber() { + return mAllocNumber; + } + + /** * Returns the name of the allocated class. */ public String getAllocatedClass() { diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/HandleHeap.java b/ddms/libs/ddmlib/src/com/android/ddmlib/HandleHeap.java index 0964226..1761b79 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/HandleHeap.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/HandleHeap.java @@ -512,6 +512,7 @@ final class HandleHeap extends ChunkHandler { data.position(messageHdrLen); ArrayList<AllocationInfo> list = new ArrayList<AllocationInfo>(numEntries); + int allocNumber = numEntries; // order value for the entry. This is sent in reverse order. for (int i = 0; i < numEntries; i++) { int totalSize; int threadId, classNameIndex, stackDepth; @@ -552,7 +553,7 @@ final class HandleHeap extends ChunkHandler { data.get(); } - list.add(new AllocationInfo(classNames[classNameIndex], + list.add(new AllocationInfo(allocNumber--, classNames[classNameIndex], totalSize, (short) threadId, steArray)); } diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/AllocationPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/AllocationPanel.java index d9492c3..e28b37e 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/AllocationPanel.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/AllocationPanel.java @@ -67,6 +67,7 @@ import java.util.Arrays; */ public class AllocationPanel extends TablePanel { + private final static String PREFS_ALLOC_COL_NUMBER = "allocPanel.Col00"; //$NON-NLS-1$ private final static String PREFS_ALLOC_COL_SIZE = "allocPanel.Col0"; //$NON-NLS-1$ private final static String PREFS_ALLOC_COL_CLASS = "allocPanel.Col1"; //$NON-NLS-1$ private final static String PREFS_ALLOC_COL_THREAD = "allocPanel.Col2"; //$NON-NLS-1$ @@ -142,14 +143,16 @@ public class AllocationPanel extends TablePanel { AllocationInfo alloc = (AllocationInfo)element; switch (columnIndex) { case 0: - return Integer.toString(alloc.getSize()); + return Integer.toString(alloc.getAllocNumber()); case 1: - return alloc.getAllocatedClass(); + return Integer.toString(alloc.getSize()); case 2: - return Short.toString(alloc.getThreadId()); + return alloc.getAllocatedClass(); case 3: - return alloc.getFirstTraceClassName(); + return Short.toString(alloc.getThreadId()); case 4: + return alloc.getFirstTraceClassName(); + case 5: return alloc.getFirstTraceMethodName(); } } @@ -255,6 +258,19 @@ public class AllocationPanel extends TablePanel { mAllocationTable.setHeaderVisible(true); mAllocationTable.setLinesVisible(true); + final TableColumn numberCol = TableHelper.createTableColumn( + mAllocationTable, + "Alloc Order", + SWT.RIGHT, + "Alloc Order", //$NON-NLS-1$ + PREFS_ALLOC_COL_NUMBER, store); + numberCol.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + setSortColumn(numberCol, SortMode.NUMBER); + } + }); + final TableColumn sizeCol = TableHelper.createTableColumn( mAllocationTable, "Allocation Size", diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml index e6a5e82..4dfeadc 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml +++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml @@ -411,6 +411,15 @@ </classpathContainerInitializer> </extension> <extension + point="org.eclipse.jdt.ui.classpathContainerPage"> + <classpathContainerPage + name="Android Classpath Container" + class="com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerPage" + id="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"> + </classpathContainerPage> + </extension> + + <extension point="org.eclipse.ui.exportWizards"> <category id="com.android.ide.eclipse.wizards.category" @@ -681,10 +690,18 @@ modes="run,debug" name="Android JUnit Test" public="true" - sourceLocatorId="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector" + sourceLocatorId="com.android.ide.eclipse.adt.internal.sourcelookup.AdtSourceLookupDirector" sourcePathComputerId="org.eclipse.jdt.launching.sourceLookup.javaSourcePathComputer"> </launchConfigurationType> </extension> + <extension point="org.eclipse.debug.core.sourceLocators"> + <sourceLocator + id="com.android.ide.eclipse.adt.internal.sourcelookup.AdtSourceLookupDirector" + class="com.android.ide.eclipse.adt.internal.sourcelookup.AdtSourceLookupDirector" + name="%sourceLocator.name"> + </sourceLocator> + </extension> + <extension point="org.eclipse.debug.ui.launchConfigurationTypeImages"> <launchConfigurationTypeImage diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerInitializer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerInitializer.java index 402e24a..50df52a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerInitializer.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerInitializer.java @@ -21,18 +21,24 @@ import com.android.ide.eclipse.adt.AndroidConstants; import com.android.ide.eclipse.adt.internal.sdk.LoadStatus; import com.android.ide.eclipse.adt.internal.sdk.ProjectState; import com.android.ide.eclipse.adt.internal.sdk.Sdk; +import com.android.sdklib.AndroidVersion; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.IAndroidTarget.IOptionalLibrary; +import com.android.sdklib.SdkConstants; import org.eclipse.core.resources.IMarker; 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.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jdt.core.ClasspathContainerInitializer; @@ -40,13 +46,18 @@ import org.eclipse.jdt.core.IAccessRule; import org.eclipse.jdt.core.IClasspathAttribute; import org.eclipse.jdt.core.IClasspathContainer; import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaModel; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; +import org.osgi.framework.Bundle; import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; +import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.regex.Pattern; @@ -56,8 +67,21 @@ import java.util.regex.Pattern; * {@link IProject}s. This removes the hard-coded path to the android.jar. */ public class AndroidClasspathContainerInitializer extends ClasspathContainerInitializer { + + public static final String SOURCES_ZIP = "/sources.zip"; //$NON-NLS-1$ + + public static final String COM_ANDROID_IDE_ECLIPSE_ADT_SOURCE = + "com.android.ide.eclipse.source"; //$NON-NLS-1$ + + private static final String ANDROID_API_REFERENCE = + "http://developer.android.com/reference/"; //$NON-NLS-1$ + + private final static String PROPERTY_ANDROID_API = "androidApi"; //$NON-NLS-1$ + + private final static String PROPERTY_ANDROID_SOURCE = "androidSource"; //$NON-NLS-1$ + /** The container id for the android framework jar file */ - private final static String CONTAINER_ID = + public final static String CONTAINER_ID = "com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"; //$NON-NLS-1$ /** path separator to store multiple paths in a single property. This is guaranteed to not @@ -155,6 +179,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit String markerMessage = null; boolean outputToConsole = true; + IAndroidTarget target = null; try { AdtPlugin plugin = AdtPlugin.getDefault(); @@ -170,7 +195,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit "Project has no default.properties file! Edit the project properties to set one."); } else { // this might be null if the sdk is not yet loaded. - IAndroidTarget target = state.getTarget(); + target = state.getTarget(); // if we are loaded and the target is non null, we create a valid // ClassPathContainer @@ -207,7 +232,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit // this is the case where there is a hashString but the SDK is not yet // loaded and therefore we can't get the target yet. // We check if there is a cache of the needed information. - AndroidClasspathContainer container = getContainerFromCache(iProject); + AndroidClasspathContainer container = getContainerFromCache(iProject, target); if (container == null) { // either the cache was wrong (ie folder does not exists anymore), or @@ -343,7 +368,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit String[] paths = getTargetPaths(target); // create the classpath entry from the paths - IClasspathEntry[] entries = createClasspathEntriesFromPaths(paths); + IClasspathEntry[] entries = createClasspathEntriesFromPaths(paths, target); // paths now contains all the path required to recreate the IClasspathEntry with no // target info. We encode them in a single string, with each path separated by @@ -364,7 +389,8 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit /** * Generates an {@link AndroidClasspathContainer} from the project cache, if possible. */ - private static AndroidClasspathContainer getContainerFromCache(IProject project) { + private static AndroidClasspathContainer getContainerFromCache(IProject project, + IAndroidTarget target) { // get the cached info from the project persistent properties. String cache = ProjectHelper.loadStringProperty(project, PROPERTY_CONTAINER_CACHE); String targetNameCache = ProjectHelper.loadStringProperty(project, PROPERTY_TARGET_NAME); @@ -423,7 +449,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit return null; } - IClasspathEntry[] entries = createClasspathEntriesFromPaths(paths); + IClasspathEntry[] entries = createClasspathEntriesFromPaths(paths, target); return new AndroidClasspathContainer(entries, new Path(CONTAINER_ID), targetNameCache); @@ -433,30 +459,90 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit * Generates an array of {@link IClasspathEntry} from a set of paths. * @see #getTargetPaths(IAndroidTarget) */ - private static IClasspathEntry[] createClasspathEntriesFromPaths(String[] paths) { + private static IClasspathEntry[] createClasspathEntriesFromPaths(String[] paths, + IAndroidTarget target) { ArrayList<IClasspathEntry> list = new ArrayList<IClasspathEntry>(); // First, we create the IClasspathEntry for the framework. // now add the android framework to the class path. // create the path object. - IPath android_lib = new Path(paths[CACHE_INDEX_JAR]); - IPath android_src = new Path(paths[CACHE_INDEX_SRC]); + IPath androidLib = new Path(paths[CACHE_INDEX_JAR]); + + IPath androidSrc = null; + String androidSrcOsPath = null; + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + if (target != null) { + androidSrcOsPath = + ProjectHelper.loadStringProperty(root, getAndroidSourceProperty(target)); + } + if (androidSrcOsPath != null && androidSrcOsPath.trim().length() > 0) { + androidSrc = new Path(androidSrcOsPath); + } + if (androidSrc == null) { + androidSrc = new Path(paths[CACHE_INDEX_SRC]); + File androidSrcFile = new File(paths[CACHE_INDEX_SRC]); + if (!androidSrcFile.isDirectory()) { + androidSrc = null; + } + } - // create the java doc link. - IClasspathAttribute cpAttribute = JavaCore.newClasspathAttribute( - IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, - paths[CACHE_INDEX_DOCS_URI]); + if (androidSrc == null && target != null) { + Bundle bundle = getSourceBundle(); + + if (bundle != null) { + AndroidVersion version = target.getVersion(); + String apiString = version.getApiString(); + String sourcePath = apiString + SOURCES_ZIP; + URL sourceURL = bundle.getEntry(sourcePath); + if (sourceURL != null) { + URL url = null; + try { + url = FileLocator.resolve(sourceURL); + } catch (IOException ignore) { + } + if (url != null) { + androidSrcOsPath = url.getFile(); + if (new File(androidSrcOsPath).isFile()) { + androidSrc = new Path(androidSrcOsPath); + } + } + } + } + } - // create the access rule to restrict access to classes in com.android.internal - IAccessRule accessRule = JavaCore.newAccessRule( - new Path("com/android/internal/**"), //$NON-NLS-1$ + // create the java doc link. + String androidApiURL = ProjectHelper.loadStringProperty(root, PROPERTY_ANDROID_API); + String apiURL = null; + if (androidApiURL != null) { + apiURL = androidApiURL; + } else { + if (testURL(androidApiURL)) { + apiURL = androidApiURL; + } else if (testURL(paths[CACHE_INDEX_DOCS_URI])) { + apiURL = paths[CACHE_INDEX_DOCS_URI]; + } else if (testURL(ANDROID_API_REFERENCE)) { + apiURL = ANDROID_API_REFERENCE; + } + } + IClasspathAttribute[] attributes = null; + if (apiURL != null) { + + IClasspathAttribute cpAttribute = JavaCore.newClasspathAttribute( + IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, apiURL); + attributes = new IClasspathAttribute[] { + cpAttribute + }; + } + // create the access rule to restrict access to classes in + // com.android.internal + IAccessRule accessRule = JavaCore.newAccessRule(new Path("com/android/internal/**"), //$NON-NLS-1$ IAccessRule.K_NON_ACCESSIBLE); - IClasspathEntry frameworkClasspathEntry = JavaCore.newLibraryEntry(android_lib, - android_src, // source attachment path - null, // default source attachment root path. + IClasspathEntry frameworkClasspathEntry = JavaCore.newLibraryEntry(androidLib, + androidSrc, // source attachment path + null, // default source attachment root path. new IAccessRule[] { accessRule }, - new IClasspathAttribute[] { cpAttribute }, + attributes, false // not exported. ); @@ -469,12 +555,11 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit while (i < paths.length) { Path jarPath = new Path(paths[i++]); - IClasspathAttribute[] attributes = null; + attributes = null; if (docPath.length() > 0) { attributes = new IClasspathAttribute[] { - JavaCore.newClasspathAttribute( - IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, - docPath) + JavaCore.newClasspathAttribute( + IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, docPath) }; } @@ -490,9 +575,51 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit } } + if (apiURL != null) { + ProjectHelper.saveStringProperty(root, PROPERTY_ANDROID_API, apiURL); + } + if (androidSrc != null && target != null) { + ProjectHelper.saveStringProperty(root, getAndroidSourceProperty(target), + androidSrc.toOSString()); + } return list.toArray(new IClasspathEntry[list.size()]); } + private static Bundle getSourceBundle() { + String bundleId = System.getProperty(COM_ANDROID_IDE_ECLIPSE_ADT_SOURCE, + COM_ANDROID_IDE_ECLIPSE_ADT_SOURCE); + Bundle bundle = Platform.getBundle(bundleId); + return bundle; + } + + private static String getAndroidSourceProperty(IAndroidTarget target) { + if (target == null) { + return null; + } + String androidSourceProperty = PROPERTY_ANDROID_SOURCE + "_" + + target.getVersion().getApiString(); + return androidSourceProperty; + } + + private static boolean testURL(String androidApiURL) { + boolean valid = false; + InputStream is = null; + try { + URL testURL = new URL(androidApiURL); + is = testURL.openStream(); + valid = true; + } catch (Exception ignore) { + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException ignore) { + } + } + } + return valid; + } + /** * Checks the projects' caches. If the cache was valid, the project is removed from the list. * @param projects the list of projects to check. @@ -651,4 +778,86 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit return paths.toArray(new String[paths.size()]); } + + @Override + public boolean canUpdateClasspathContainer(IPath containerPath, IJavaProject project) { + return true; + } + + @Override + public void requestClasspathContainerUpdate(IPath containerPath, IJavaProject project, + IClasspathContainer containerSuggestion) throws CoreException { + AdtPlugin plugin = AdtPlugin.getDefault(); + + synchronized (Sdk.getLock()) { + boolean sdkIsLoaded = plugin.getSdkLoadStatus() == LoadStatus.LOADED; + + // check if the project has a valid target. + IAndroidTarget target = null; + if (sdkIsLoaded) { + target = Sdk.getCurrent().getTarget(project.getProject()); + } + if (sdkIsLoaded && target != null) { + String[] paths = getTargetPaths(target); + IPath android_lib = new Path(paths[CACHE_INDEX_JAR]); + IClasspathEntry[] entries = containerSuggestion.getClasspathEntries(); + for (int i = 0; i < entries.length; i++) { + IClasspathEntry entry = entries[i]; + if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { + IPath entryPath = entry.getPath(); + + if (entryPath != null) { + if (entryPath.equals(android_lib)) { + IPath entrySrcPath = entry.getSourceAttachmentPath(); + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + if (entrySrcPath != null) { + ProjectHelper.saveStringProperty(root, + getAndroidSourceProperty(target), + entrySrcPath.toString()); + } else { + ProjectHelper.saveStringProperty(root, + getAndroidSourceProperty(target), null); + } + IClasspathAttribute[] extraAttributtes = entry.getExtraAttributes(); + for (int j = 0; j < extraAttributtes.length; j++) { + IClasspathAttribute extraAttribute = extraAttributtes[j]; + if (IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME + .equals(extraAttribute.getName())) { + ProjectHelper.saveStringProperty(root, + PROPERTY_ANDROID_API, extraAttribute.getValue()); + + } + } + } + } + } + } + rebindClasspathEntries(project.getJavaModel(), containerPath); + } + } + } + + private static void rebindClasspathEntries(IJavaModel model, IPath containerPath) + throws JavaModelException { + ArrayList affectedProjects = new ArrayList(); + + IJavaProject[] projects = model.getJavaProjects(); + for (int i = 0; i < projects.length; i++) { + IJavaProject project = projects[i]; + IClasspathEntry[] entries = project.getRawClasspath(); + for (int k = 0; k < entries.length; k++) { + IClasspathEntry curr = entries[k]; + if (curr.getEntryKind() == IClasspathEntry.CPE_CONTAINER + && containerPath.equals(curr.getPath())) { + affectedProjects.add(project); + } + } + } + if (!affectedProjects.isEmpty()) { + IJavaProject[] affected = (IJavaProject[]) affectedProjects + .toArray(new IJavaProject[affectedProjects.size()]); + updateProjects(affected); + } + } + } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerPage.java new file mode 100644 index 0000000..4641c22 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerPage.java @@ -0,0 +1,193 @@ +/* + * 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.project; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.internal.ui.dialogs.StatusInfo; +import org.eclipse.jdt.internal.ui.dialogs.StatusUtil; +import org.eclipse.jdt.ui.wizards.IClasspathContainerPage; +import org.eclipse.jdt.ui.wizards.IClasspathContainerPageExtension; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; + +import java.util.Arrays; + +public class AndroidClasspathContainerPage extends WizardPage implements IClasspathContainerPage, + IClasspathContainerPageExtension { + + private IProject mOwnerProject; + + private String mLibsProjectName; + + private Combo mProjectsCombo; + + private IStatus mCurrStatus; + + private boolean mPageVisible; + + public AndroidClasspathContainerPage() { + super("AndroidClasspathContainerPage"); //$NON-NLS-1$ + mPageVisible = false; + mCurrStatus = new StatusInfo(); + setTitle("Android Libraries"); + setDescription("This container manages classpath entries for Android container"); + } + + public IClasspathEntry getSelection() { + IPath path = new Path(AndroidClasspathContainerInitializer.CONTAINER_ID); + + final int index = this.mProjectsCombo.getSelectionIndex(); + if (index != -1) { + final String selectedProjectName = this.mProjectsCombo.getItem(index); + + if (this.mOwnerProject == null + || !selectedProjectName.equals(this.mOwnerProject.getName())) { + path = path.append(selectedProjectName); + } + } + + return JavaCore.newContainerEntry(path); + } + + public void setSelection(final IClasspathEntry cpentry) { + final IPath path = cpentry == null ? null : cpentry.getPath(); + + if (path == null || path.segmentCount() == 1) { + if (this.mOwnerProject != null) { + this.mLibsProjectName = this.mOwnerProject.getName(); + } + } else { + this.mLibsProjectName = path.segment(1); + } + } + + public void createControl(final Composite parent) { + final Composite composite = new Composite(parent, SWT.NONE); + composite.setLayout(new GridLayout(2, false)); + + final Label label = new Label(composite, SWT.NONE); + label.setText("Project:"); + + final String[] androidProjects = getAndroidProjects(); + + this.mProjectsCombo = new Combo(composite, SWT.READ_ONLY); + this.mProjectsCombo.setItems(androidProjects); + + final int index; + + if (this.mOwnerProject != null) { + index = indexOf(androidProjects, this.mLibsProjectName); + } else { + if (this.mProjectsCombo.getItemCount() > 0) { + index = 0; + } else { + index = -1; + } + } + + if (index != -1) { + this.mProjectsCombo.select(index); + } + + final GridData gd = new GridData(); + gd.grabExcessHorizontalSpace = true; + gd.minimumWidth = 100; + + this.mProjectsCombo.setLayoutData(gd); + + setControl(composite); + } + + public boolean finish() { + return true; + } + + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + mPageVisible = visible; + // policy: wizards are not allowed to come up with an error message + if (visible && mCurrStatus.matches(IStatus.ERROR)) { + StatusInfo status = new StatusInfo(); + status.setError(""); //$NON-NLS-1$ + mCurrStatus = status; + } + updateStatus(mCurrStatus); + } + + /** + * Updates the status line and the OK button according to the given status + * + * @param status status to apply + */ + protected void updateStatus(IStatus status) { + mCurrStatus = status; + setPageComplete(!status.matches(IStatus.ERROR)); + if (mPageVisible) { + StatusUtil.applyToStatusLine(this, status); + } + } + + /** + * Updates the status line and the OK button according to the status + * evaluate from an array of status. The most severe error is taken. In case + * that two status with the same severity exists, the status with lower + * index is taken. + * + * @param status the array of status + */ + protected void updateStatus(IStatus[] status) { + updateStatus(StatusUtil.getMostSevere(status)); + } + + public void initialize(final IJavaProject project, final IClasspathEntry[] currentEntries) { + this.mOwnerProject = (project == null ? null : project.getProject()); + } + + private static String[] getAndroidProjects() { + IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); + final String[] names = new String[projects.length]; + for (int i = 0; i < projects.length; i++) { + names[i] = projects[i].getName(); + } + Arrays.sort(names); + return names; + } + + private static int indexOf(final String[] array, final String str) { + for (int i = 0; i < array.length; i++) { + if (array[i].equals(str)) { + return i; + } + } + return -1; + } + +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sourcelookup/AdtSourceLookupDirector.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sourcelookup/AdtSourceLookupDirector.java new file mode 100755 index 0000000..612ef76 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sourcelookup/AdtSourceLookupDirector.java @@ -0,0 +1,97 @@ +/*
+ * 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.sourcelookup;
+
+import com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerInitializer;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;
+import org.eclipse.debug.core.sourcelookup.containers.DefaultSourceContainer;
+import org.eclipse.debug.core.sourcelookup.containers.DirectorySourceContainer;
+import org.eclipse.debug.core.sourcelookup.containers.ExternalArchiveSourceContainer;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.internal.launching.JavaSourceLookupDirector;
+
+import java.io.File;
+
+public class AdtSourceLookupDirector extends JavaSourceLookupDirector {
+
+ @Override
+ public void initializeDefaults(ILaunchConfiguration configuration) throws CoreException {
+ dispose();
+ setLaunchConfiguration(configuration);
+ String projectName = configuration.getAttribute("org.eclipse.jdt.launching.PROJECT_ATTR", //$NON-NLS-1$
+ ""); //$NON-NLS-1$
+ if (projectName != null && projectName.length() > 0) {
+ IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+ if (project != null && project.isOpen()) {
+ IJavaProject javaProject = JavaCore.create(project);
+ if (javaProject != null && javaProject.isOpen()) {
+ IClasspathEntry[] entries = javaProject.getRawClasspath();
+ IClasspathEntry androidEntry = null;
+ for (int i = 0; i < entries.length; i++) {
+ IClasspathEntry entry = entries[i];
+ if (entry.getPath() != null
+ && AndroidClasspathContainerInitializer.CONTAINER_ID.equals(entry
+ .getPath().toString())) {
+ androidEntry = entry;
+ break;
+ }
+ }
+ if (androidEntry != null) {
+ IPath sourceAttachmentPath = androidEntry.getSourceAttachmentPath();
+ if (sourceAttachmentPath != null) {
+ String androidSrc = sourceAttachmentPath.toString();
+ if (androidSrc != null && androidSrc.trim().length() > 0) {
+ File srcFile = new File(androidSrc);
+ ISourceContainer adtContainer = null;
+ if (srcFile.isFile()) {
+ adtContainer = new ExternalArchiveSourceContainer(androidSrc,
+ true);
+ }
+ if (srcFile.isDirectory()) {
+ adtContainer = new DirectorySourceContainer(srcFile, false);
+ }
+ if (adtContainer != null) {
+ ISourceContainer defaultContainer =
+ new DefaultSourceContainer();
+ setSourceContainers(new ISourceContainer[] {
+ adtContainer, defaultContainer
+ });
+ initializeParticipants();
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ setSourceContainers(new ISourceContainer[] {
+ new DefaultSourceContainer()
+ });
+ initializeParticipants();
+ }
+
+}
|