From 4563c4e2f168df1d6c97206a4ac6444dfa2264ba Mon Sep 17 00:00:00 2001 From: Tor Norbye Date: Thu, 17 Mar 2011 09:00:14 -0700 Subject: [PATCH] Add custom views and third party views to the palette This changeset adds a new category to the palette, "Custom & Third Party Views", which is populated with android.view.View subclasses found in the current project (or any of its libraries), and in any jars included by the project. They can be dragged directly to the canvas, and control clicking on the palette entries will jump to the source. There are a bunch of adjustments in various places to make working with custom views better - from ensuring that we don't use fully qualified class names in default ids, to showing the Java class icon for custom views in outline and elsewhere, to making zero-sized view highlight and expand when selected like we do for laoyuts - since with custom views it's quite easy to end up with an "invisible" view that you can't see after dropping it. There are also some fixes to the code which looks up third party and custom views (which was already used by the Wrap In refactoring) - to handle inner classes, to filter out non public or abstract classes, and most importantly to only include views reachable from the current project (since the view search necessarily is workspace wide.) Change-Id: If1d8c7e5c7dd907a68d8d0962e85c5144e911503 --- .../com.android.ide.eclipse.adt/icons/refresh.png | Bin 0 -> 377 bytes .../editors/descriptors/DescriptorsUtils.java | 21 +- .../internal/editors/layout/ProjectCallback.java | 2 +- .../descriptors/CustomViewDescriptorService.java | 58 ++-- .../editors/layout/gle2/AccordionControl.java | 9 +- .../editors/layout/gle2/CanvasViewInfo.java | 16 +- .../editors/layout/gle2/CustomViewFinder.java | 319 +++++++++++++++++++++ .../internal/editors/layout/gle2/DomUtilities.java | 2 +- .../editors/layout/gle2/IncludeFinder.java | 2 +- .../internal/editors/layout/gle2/LayoutCanvas.java | 2 +- .../internal/editors/layout/gle2/OutlinePage.java | 2 +- .../editors/layout/gle2/PaletteControl.java | 117 +++++++- .../editors/layout/gle2/SelectionItem.java | 7 +- .../editors/layout/gle2/SelectionManager.java | 6 +- .../editors/layout/gle2/ViewHierarchy.java | 4 +- .../layout/refactoring/ChangeViewWizard.java | 3 +- .../editors/layout/refactoring/WrapInWizard.java | 88 +----- .../editors/descriptors/DescriptorsUtilsTest.java | 6 + 18 files changed, 526 insertions(+), 138 deletions(-) create mode 100644 eclipse/plugins/com.android.ide.eclipse.adt/icons/refresh.png create mode 100644 eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CustomViewFinder.java diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/refresh.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/refresh.png new file mode 100644 index 0000000000000000000000000000000000000000..7cbebf415b222361803cb3005d81e05cb7b0a743 GIT binary patch literal 377 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1Igq5z)|R|Zvv zA3t9F`}_XKhYi0!Z29?O%8wT_e!rae^KR9L8x0?CHUD_f@!`RWkC%&o-)lWQP4>`C zg&!9Ze%z?|aiihq+4#LJVjC-jcQ=aeY82g8BeJa)h=6Rd6?p<{iv(BZ39iT!Tw5fx zwpeIQklmdKI;Vst0QgUhO8@`> literal 0 HcmV?d00001 diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/DescriptorsUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/DescriptorsUtils.java index 95edfb394..0384ad57c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/DescriptorsUtils.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/DescriptorsUtils.java @@ -671,6 +671,23 @@ public final class DescriptorsUtils { } /** + * Returns the basename for the given fully qualified class name. It is okay to pass + * a basename to this method which will just be returned back. + * + * @param fqcn The fully qualified class name to convert + * @return the basename of the class name + */ + public static String getBasename(String fqcn) { + String name = fqcn; + int lastDot = name.lastIndexOf('.'); + if (lastDot != -1) { + name = name.substring(lastDot + 1); + } + + return name; + } + + /** * Sets the default layout attributes for the a new UiElementNode. *

* Note that ideally the node should already be part of a hierarchy so that its @@ -706,7 +723,7 @@ public final class DescriptorsUtils { // Don't set default text value into edit texts - they typically start out blank if (!descriptor.getXmlLocalName().equals(EDIT_TEXT)) { - String type = descriptor.getUiName(); + String type = getBasename(descriptor.getUiName()); node.setAttributeValue( ATTR_TEXT, SdkConstants.NS_RESOURCES, @@ -745,7 +762,7 @@ public final class DescriptorsUtils { * (e.g. "@+id/something") */ public static String getFreeWidgetId(UiElementNode uiNode) { - String name = uiNode.getDescriptor().getXmlLocalName(); + String name = getBasename(uiNode.getDescriptor().getXmlLocalName()); return getFreeWidgetId(uiNode.getUiRoot(), name); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java index d4ba57f9f..804156a22 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java @@ -19,8 +19,8 @@ package com.android.ide.eclipse.adt.internal.editors.layout; import com.android.ide.common.rendering.api.IProjectCallback; import com.android.ide.common.rendering.api.LayoutLog; import com.android.ide.common.rendering.legacy.LegacyCallback; -import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AdtConstants; +import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; import com.android.ide.eclipse.adt.internal.resources.manager.ProjectClassLoader; import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java index bfc8bb01d..db72ac62b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java @@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout.descriptors; import com.android.ide.common.resources.platform.ViewClassInfo; import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils; import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.sdklib.IAndroidTarget; @@ -29,6 +30,10 @@ import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeHierarchy; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.ui.ISharedImages; +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.graphics.Image; import java.util.HashMap; import java.util.List; @@ -157,16 +162,9 @@ public final class CustomViewDescriptorService { if (parentDescriptor != null) { // we have a valid parent, lets create a new ViewElementDescriptor. - ViewElementDescriptor descriptor = new ViewElementDescriptor(fqcn, - fqcn, // ui_name - fqcn, // canonical class name - null, // tooltip - null, // sdk_url - getAttributeDescriptor(type, parentDescriptor), - null, // layout attributes - null, // children - false /* mandatory */); - + String name = DescriptorsUtils.getBasename(fqcn); + ViewElementDescriptor descriptor = new CustomViewDescriptor(name, fqcn, + getAttributeDescriptor(type, parentDescriptor)); descriptor.setSuperClass(parentDescriptor); synchronized (mCustomDescriptorMap) { @@ -242,16 +240,9 @@ public final class CustomViewDescriptorService { if (parentDescriptor != null) { // parent class is a valid View class with a descriptor, so we create one // for this class. - ViewElementDescriptor descriptor = new ViewElementDescriptor(fqcn, - fqcn, // ui_name - fqcn, // canonical name - null, // tooltip - null, // sdk_url - getAttributeDescriptor(type, parentDescriptor), - null, // layout attributes - null, // children - false /* mandatory */); - + String name = DescriptorsUtils.getBasename(fqcn); + ViewElementDescriptor descriptor = new CustomViewDescriptor(name, fqcn, + getAttributeDescriptor(type, parentDescriptor)); descriptor.setSuperClass(parentDescriptor); // add it to the map @@ -290,4 +281,31 @@ public final class CustomViewDescriptorService { // TODO add the class attribute descriptors to the parent descriptors. return parentDescriptor.getAttributes(); } + + private class CustomViewDescriptor extends ViewElementDescriptor { + public CustomViewDescriptor(String name, String fqcn, AttributeDescriptor[] attributes) { + super( + fqcn, // xml name + name, // ui name + fqcn, // full class name + fqcn, // tooltip + null, // sdk_url + attributes, + null, // layout attributes + null, // children + false // mandatory + ); + } + + @Override + public Image getGenericIcon() { + // Java source file icon. We could use the Java class icon here + // (IMG_OBJS_CLASS), but it does not work well on anything but + // white backgrounds + ISharedImages sharedImages = JavaUI.getSharedImages(); + String key = ISharedImages.IMG_OBJS_CUNIT; + ImageDescriptor descriptor = sharedImages.getImageDescriptor(key); + return descriptor.createImage(); + } + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/AccordionControl.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/AccordionControl.java index 24c582d86..3c18b1643 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/AccordionControl.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/AccordionControl.java @@ -82,8 +82,8 @@ public abstract class AccordionControl extends Composite { * overridden to lay out the children with a different layout than the default * vertical RowLayout */ - protected Composite createChildContainer(Composite parent) { - Composite composite = new Composite(parent, SWT.NONE); + protected Composite createChildContainer(Composite parent, Object header, int style) { + Composite composite = new Composite(parent, style); if (mWrap) { RowLayout layout = new RowLayout(SWT.HORIZONTAL); layout.center = true; @@ -335,9 +335,12 @@ public abstract class AccordionControl extends Composite { updateIcon(label); if (!scrollGridData.exclude && scrolledComposite.getContent() == null) { - Composite composite = createChildContainer(scrolledComposite); Object header = getHeader(label); + Composite composite = createChildContainer(scrolledComposite, header, SWT.NONE); createChildren(composite, header); + while (composite.getParent() != scrolledComposite) { + composite = composite.getParent(); + } scrolledComposite.setContent(composite); scrolledComposite.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java index 30dc3e97e..2bb89014e 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java @@ -363,16 +363,16 @@ public class CanvasViewInfo implements IPropertySource { } /** - * Returns true if this {@link CanvasViewInfo} represents an invisible parent - in - * other words, a view that can have children, and that has zero bounds making it - * effectively invisible. (We don't actually look for -0- bounds, but - * bounds smaller than SELECTION_MIN_SIZE.) + * Returns true if this {@link CanvasViewInfo} represents an invisible widget that + * should be highlighted when selected. This is the case for any layout that is less than the minimum + * threshold ({@link #SELECTION_MIN_SIZE}), or any other view that has -0- bounds. * - * @return True if this is an invisible parent. + * @return True if this is a tiny layout or invisible view */ - public boolean isInvisibleParent() { + public boolean isInvisible() { if (mAbsRect.width < SELECTION_MIN_SIZE || mAbsRect.height < SELECTION_MIN_SIZE) { - return mUiViewNode != null && mUiViewNode.getDescriptor().hasChildren(); + return mUiViewNode != null && (mUiViewNode.getDescriptor().hasChildren() || + mAbsRect.width <= 0 || mAbsRect.height <= 0); } return false; @@ -383,7 +383,7 @@ public class CanvasViewInfo implements IPropertySource { * make it visible during selection or dragging? Note that this is NOT considered to * be the case in the explode-all-views mode where all nodes have their padding * increased; it's only used for views that individually exploded because they were - * requested visible and they returned true for {@link #isInvisibleParent()}. + * requested visible and they returned true for {@link #isInvisible()}. * * @return True if this is an exploded node. */ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CustomViewFinder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CustomViewFinder.java new file mode 100644 index 000000000..8cb0d2634 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CustomViewFinder.java @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2011 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.editors.layout.gle2; + +import static com.android.sdklib.SdkConstants.CLASS_VIEW; +import static com.android.sdklib.SdkConstants.CLASS_VIEWGROUP; +import static com.android.sdklib.SdkConstants.FN_FRAMEWORK_LIBRARY; + +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.sdk.ProjectState; +import com.android.ide.eclipse.adt.internal.sdk.Sdk; +import com.android.util.Pair; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +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.QualifiedName; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMember; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.search.IJavaSearchConstants; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchEngine; +import org.eclipse.jdt.core.search.SearchMatch; +import org.eclipse.jdt.core.search.SearchParticipant; +import org.eclipse.jdt.core.search.SearchPattern; +import org.eclipse.jdt.core.search.SearchRequestor; +import org.eclipse.jdt.internal.core.ResolvedBinaryType; +import org.eclipse.jdt.internal.core.ResolvedSourceType; +import org.eclipse.swt.widgets.Display; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * The {@link CustomViewFinder} can look up the custom views and third party views + * available for a given project. + */ +@SuppressWarnings("restriction") // JDT model access for custom-view class lookup +public class CustomViewFinder { + /** + * Qualified name for the per-project non-persistent property storing the + * {@link CustomViewFinder} for this project + */ + private final static QualifiedName CUSTOM_VIEW_FINDER = new QualifiedName(AdtPlugin.PLUGIN_ID, + "viewfinder"); //$NON-NLS-1$ + + /** Project that this view finder locates views for */ + private final IProject mProject; + + private final List mListeners = new ArrayList(); + + private List mCustomViews; + private List mThirdPartyViews; + private boolean mRefreshing; + + /** + * Constructs an {@link CustomViewFinder} for the given project. Don't use this method; + * use the {@link #get} factory method instead. + * + * @param project project to create an {@link CustomViewFinder} for + */ + private CustomViewFinder(IProject project) { + mProject = project; + } + + /** + * Returns the {@link CustomViewFinder} for the given project + * + * @param project the project the finder is associated with + * @return a {@CustomViewFinder} for the given project, never null + */ + public static CustomViewFinder get(IProject project) { + CustomViewFinder finder = null; + try { + finder = (CustomViewFinder) project.getSessionProperty(CUSTOM_VIEW_FINDER); + } catch (CoreException e) { + // Not a problem; we will just create a new one + } + + if (finder == null) { + finder = new CustomViewFinder(project); + try { + project.setSessionProperty(CUSTOM_VIEW_FINDER, finder); + } catch (CoreException e) { + AdtPlugin.log(e, "Can't store CustomViewFinder"); + } + } + + return finder; + } + + public void refresh() { + refresh(null); + } + + public void refresh(final Listener listener) { + // Add this listener to the list of listeners which should be notified when the + // search is done. (There could be more than one since multiple requests could + // arrive for a slow search since the search is run in a different thread). + if (listener != null) { + synchronized (this) { + mListeners.add(listener); + } + } + synchronized (this) { + if (listener != null) { + mListeners.add(listener); + } + if (mRefreshing) { + return; + } + mRefreshing = true; + } + + FindViewsJob job = new FindViewsJob(); + job.schedule(); + } + + public Collection getCustomViews() { + return mCustomViews == null ? null : Collections.unmodifiableCollection(mCustomViews); + } + + public Collection getThirdPartyViews() { + return mThirdPartyViews == null + ? null : Collections.unmodifiableCollection(mThirdPartyViews); + } + + public Collection getAllViews() { + // Not yet initialized: return null + if (mCustomViews == null) { + return null; + } + List all = new ArrayList(mCustomViews.size() + mThirdPartyViews.size()); + all.addAll(mCustomViews); + all.addAll(mThirdPartyViews); + return all; + } + + /** + * Returns a pair of view lists - the custom views and the 3rd-party views. + * This method performs no caching; it is the same as asking the custom view finder + * to refresh itself and then waiting for the answer and returning it. + * + * @param project the Android project + * @param layoutsOnly if true, only search for layouts + * @return a pair of lists, the first containing custom views and the second + * containing 3rd party views + */ + public static Pair,List> findViews( + final IProject project, boolean layoutsOnly) { + CustomViewFinder finder = get(project); + + return finder.findViews(layoutsOnly); + } + + private Pair,List> findViews(final boolean layoutsOnly) { + final List customViews = new ArrayList(); + final List thirdPartyViews = new ArrayList(); + + ProjectState state = Sdk.getProjectState(mProject); + final List libraries = state != null + ? state.getFullLibraryProjects() : Collections.emptyList(); + + SearchRequestor requestor = new SearchRequestor() { + @Override + public void acceptSearchMatch(SearchMatch match) throws CoreException { + Object element = match.getElement(); + if (element instanceof ResolvedBinaryType) { + // Third party view + ResolvedBinaryType type = (ResolvedBinaryType) element; + IPackageFragment fragment = type.getPackageFragment(); + IPath path = fragment.getPath(); + String last = path.lastSegment(); + // Filter out android.jar stuff + if (last.equals(FN_FRAMEWORK_LIBRARY)) { + return; + } + if (!isValidView(type, layoutsOnly)) { + return; + } + + IProject matchProject = match.getResource().getProject(); + if (mProject == matchProject || libraries.contains(matchProject)) { + String fqn = type.getFullyQualifiedName(); + thirdPartyViews.add(fqn); + } + } else if (element instanceof ResolvedSourceType) { + // User custom view + IProject matchProject = match.getResource().getProject(); + if (mProject == matchProject || libraries.contains(matchProject)) { + ResolvedSourceType type = (ResolvedSourceType) element; + if (!isValidView(type, layoutsOnly)) { + return; + } + String fqn = type.getFullyQualifiedName(); + fqn = fqn.replace('$', '.'); + customViews.add(fqn); + } + } + } + }; + try { + IJavaProject javaProject = (IJavaProject) mProject.getNature(JavaCore.NATURE_ID); + if (javaProject != null) { + String className = layoutsOnly ? CLASS_VIEWGROUP : CLASS_VIEW; + IType activityType = javaProject.findType(className); + if (activityType != null) { + IJavaSearchScope scope = SearchEngine.createHierarchyScope(activityType); + SearchParticipant[] participants = new SearchParticipant[] { + SearchEngine.getDefaultSearchParticipant() + }; + int matchRule = SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CASE_SENSITIVE; + SearchPattern pattern = SearchPattern.createPattern("*", + IJavaSearchConstants.CLASS, IJavaSearchConstants.DECLARATIONS, + matchRule); + SearchEngine engine = new SearchEngine(); + engine.search(pattern, participants, scope, requestor, + new NullProgressMonitor()); + } + } + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + + if (!layoutsOnly) { + // Update our cached answers (unless we were filtered on only layouts) + mCustomViews = customViews; + mThirdPartyViews = thirdPartyViews; + } + + return Pair.of(customViews, thirdPartyViews); + } + + /** + * Determines whether the given member is a valid android.view.View to be added to the + * list of custom views or third party views. It checks that the view is public and + * not abstract for example. + */ + private static boolean isValidView(IMember member, boolean layoutsOnly) + throws JavaModelException { + int flags = member.getFlags(); + if (Flags.isAbstract(flags) || !Flags.isPublic(flags)) { + return false; + } + + // TODO: if (layoutsOnly) perhaps try to filter out AdapterViews and other ViewGroups + // not willing to accept children via XML + return true; + } + + /** + * Interface implemented by clients of the {@link CustomViewFinder} to be notified + * when a custom view search has completed. Will always be called on the SWT event + * dispatch thread. + */ + public interface Listener { + void viewsUpdated(Collection customViews, Collection thirdPartyViews); + } + + /** + * Job for performing class search off the UI thread. This is marked as a system job + * so that it won't show up in the progress monitor etc. + */ + private class FindViewsJob extends Job { + FindViewsJob() { + super("Find Custom Views"); + setSystem(true); + } + @Override + protected IStatus run(IProgressMonitor monitor) { + Pair, List> views = findViews(false); + mCustomViews = views.getFirst(); + mThirdPartyViews = views.getSecond(); + + // Notify listeners on SWT's UI thread + Display.getDefault().asyncExec(new Runnable() { + public void run() { + Collection customViews = + Collections.unmodifiableCollection(mCustomViews); + Collection thirdPartyViews = + Collections.unmodifiableCollection(mThirdPartyViews); + synchronized (this) { + for (Listener l : mListeners) { + l.viewsUpdated(customViews, thirdPartyViews); + } + mListeners.clear(); + mRefreshing = false; + } + } + }); + return Status.OK_STATUS; + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DomUtilities.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DomUtilities.java index 753010f0a..6d1c25b73 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DomUtilities.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DomUtilities.java @@ -300,7 +300,7 @@ public class DomUtilities { addLowercaseIds(element.getOwnerDocument().getDocumentElement(), ids); if (prefix == null) { - prefix = element.getTagName(); + prefix = DescriptorsUtils.getBasename(element.getTagName()); } String generated; int num = 1; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/IncludeFinder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/IncludeFinder.java index 9da4af92c..86e33be10 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/IncludeFinder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/IncludeFinder.java @@ -90,7 +90,7 @@ public class IncludeFinder { * {@link IncludeFinder} for this project */ private final static QualifiedName INCLUDE_FINDER = new QualifiedName(AdtPlugin.PLUGIN_ID, - "finder"); //$NON-NLS-1$ + "includefinder"); //$NON-NLS-1$ /** Project that the include finder locates includes for */ private final IProject mProject; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java index d29544de4..277c1945c 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java @@ -747,6 +747,7 @@ public class LayoutCanvas extends Canvas { if (mShowInvisible == show) { return; } + mShowInvisible = show; // Optimization: Avoid doing work when we don't have invisible parents (on show) // or formerly exploded nodes (on hide). @@ -756,7 +757,6 @@ public class LayoutCanvas extends Canvas { return; } - mShowInvisible = show; mLayoutEditor.recomputeLayout(); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java index b08e61604..3c1bd6ad3 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java @@ -483,7 +483,7 @@ public class OutlinePage extends ContentOutlinePage } } if (img == null) { - img = desc.getCustomizedIcon(); + img = desc.getGenericIcon(); } if (img != null) { if (node.hasError()) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteControl.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteControl.java index 89e02df3d..0353d1fca 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteControl.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteControl.java @@ -32,11 +32,13 @@ import com.android.ide.common.rendering.api.RenderSession; import com.android.ide.common.rendering.api.ViewInfo; import com.android.ide.common.rendering.api.SessionParams.RenderingMode; import com.android.ide.eclipse.adt.internal.editors.IconFactory; +import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils; import com.android.ide.eclipse.adt.internal.editors.descriptors.DocumentDescriptor; import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor; import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor; import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite; +import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.CustomViewDescriptorService; import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor; import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeFactory; import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeProxy; @@ -48,6 +50,7 @@ import com.android.ide.eclipse.adt.internal.editors.ui.DecorComposite; import com.android.ide.eclipse.adt.internal.editors.ui.IDecorContent; import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode; import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; +import com.android.ide.eclipse.adt.internal.editors.xml.Hyperlinks; import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; import com.android.ide.eclipse.adt.internal.sdk.Sdk; @@ -70,6 +73,7 @@ import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.MenuDetectEvent; import org.eclipse.swt.events.MenuDetectListener; +import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseTrackListener; import org.eclipse.swt.events.SelectionAdapter; @@ -82,6 +86,9 @@ import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; +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.Display; @@ -96,6 +103,7 @@ import java.awt.image.BufferedImage; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -438,6 +446,8 @@ public class PaletteControl extends Composite { categoryToItems.put(category, categoryItems); } + headers.add("Custom & Library Views"); + // Set the categories to expand the first item if // (1) we don't have a previously selected category, or // (2) there's just one category anyway, or @@ -445,7 +455,8 @@ public class PaletteControl extends Composite { // doesn't exist anymore (can happen when you toggle "Show Categories") if ((expandedCategories == null && headers.size() > 0) || headers.size() == 1 || (expandedCategories != null && expandedCategories.size() >= 1 - && !headers.contains(expandedCategories.iterator().next()))) { + && !headers.contains( + expandedCategories.iterator().next().replace("&&", "&")))) { //$NON-NLS-1$ //$NON-NLS-2$ // Expand the first category if we don't have a previous selection (e.g. refresh) expandedCategories = Collections.singleton(headers.get(0)); } @@ -458,10 +469,45 @@ public class PaletteControl extends Composite { mAccordion = new AccordionControl(this, SWT.NONE, headers, fillVertical, wrap, expandedCategories) { @Override - protected Composite createChildContainer(Composite parent) { - Composite composite = super.createChildContainer(parent); - if (mPaletteMode.isPreview() && mBackground != null) { - composite.setBackground(mBackground); + protected Composite createChildContainer(Composite parent, Object header, int style) { + assert categoryToItems != null; + List list = categoryToItems.get(header); + final Composite composite; + if (list == null) { + assert header.equals("Custom & Library Views"); + + Composite wrapper = new Composite(parent, SWT.NONE); + GridLayout gridLayout = new GridLayout(1, false); + gridLayout.marginWidth = gridLayout.marginHeight = 0; + gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0; + gridLayout.marginBottom = 3; + wrapper.setLayout(gridLayout); + if (mPaletteMode.isPreview() && mBackground != null) { + wrapper.setBackground(mBackground); + } + composite = super.createChildContainer(wrapper, header, + style | SWT.NO_BACKGROUND); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); + + Button refreshButton = new Button(wrapper, SWT.PUSH | SWT.FLAT); + refreshButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, + false, false, 1, 1)); + refreshButton.setText("Refresh"); + refreshButton.setImage(IconFactory.getInstance().getIcon("refresh")); //$NON-NLS-1$ + refreshButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + CustomViewFinder finder = CustomViewFinder.get(mEditor.getProject()); + finder.refresh(new ViewFinderListener(composite)); + } + }); + + wrapper.layout(true); + } else { + composite = super.createChildContainer(parent, header, style); + if (mPaletteMode.isPreview() && mBackground != null) { + composite.setBackground(mBackground); + } } addMenu(composite); return composite; @@ -470,8 +516,14 @@ public class PaletteControl extends Composite { protected void createChildren(Composite parent, Object header) { assert categoryToItems != null; List list = categoryToItems.get(header); - for (ViewElementDescriptor desc : list) { - createItem(parent, desc); + if (list == null) { + assert header.equals("Custom & Library Views"); + addCustomItems(parent); + return; + } else { + for (ViewElementDescriptor desc : list) { + createItem(parent, desc); + } } } }; @@ -493,6 +545,40 @@ public class PaletteControl extends Composite { layout(true); } + protected void addCustomItems(final Composite parent) { + final CustomViewFinder finder = CustomViewFinder.get(mEditor.getProject()); + Collection allViews = finder.getAllViews(); + if (allViews == null) { // Not yet initialized: trigger an async refresh + finder.refresh(new ViewFinderListener(parent)); + return; + } + + // Remove previous content + for (Control c : parent.getChildren()) { + c.dispose(); + } + + // Add new views + for (final String fqcn : allViews) { + CustomViewDescriptorService service = CustomViewDescriptorService.getInstance(); + ViewElementDescriptor desc = service.getDescriptor(mEditor.getProject(), fqcn); + Control item = createItem(parent, desc); + + // Add control-click listener on custom view items to you can warp to + if (item instanceof IconTextItem) { + IconTextItem it = (IconTextItem) item; + it.addMouseListener(new MouseAdapter() { + @Override + public void mouseDown(MouseEvent e) { + if ((e.stateMask & SWT.MOD1) != 0) { + Hyperlinks.openJavaClass(mEditor.getProject(), fqcn); + } + } + }); + } + } + } + /* package */ GraphicalEditorPart getEditor() { return mEditor; } @@ -824,7 +910,8 @@ public class PaletteControl extends Composite { // This doesn't apply to all, but doesn't seem to cause harm and makes for a // better experience with text-oriented views like buttons and texts - element.setAttributeNS(ANDROID_URI, ATTR_TEXT, mDesc.getUiName()); + element.setAttributeNS(ANDROID_URI, ATTR_TEXT, + DescriptorsUtils.getBasename(mDesc.getUiName())); // Is this a palette variation? if (mDesc instanceof PaletteMetadataDescriptor) { @@ -1107,4 +1194,18 @@ public class PaletteControl extends Composite { menu.setLocation(x, y); menu.setVisible(true); } + + private final class ViewFinderListener implements CustomViewFinder.Listener { + private final Composite mParent; + + private ViewFinderListener(Composite parent) { + this.mParent = parent; + } + + public void viewsUpdated(Collection customViews, + Collection thirdPartyViews) { + addCustomItems(mParent); + mParent.layout(true); + } + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionItem.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionItem.java index 1e9eebebf..01b931401 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionItem.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionItem.java @@ -146,6 +146,11 @@ class SelectionItem { * @return true if this selection item is a layout */ public boolean isLayout() { - return mCanvasViewInfo.getUiViewNode().getDescriptor().hasChildren(); + UiViewElementNode node = mCanvasViewInfo.getUiViewNode(); + if (node != null) { + return node.getDescriptor().hasChildren(); + } else { + return false; + } } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java index e34ecbfb5..be17b686e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java @@ -218,7 +218,7 @@ public class SelectionManager implements ISelectionProvider { mSelections.add(createSelection(newVi)); changed = true; } - if (newVi.isInvisibleParent()) { + if (newVi.isInvisible()) { redoLayout = true; } } @@ -419,7 +419,7 @@ public class SelectionManager implements ISelectionProvider { if (vi != null) { mSelections.add(createSelection(vi)); - if (vi.isInvisibleParent()) { + if (vi.isInvisible()) { redoLayout = true; } } @@ -461,7 +461,7 @@ public class SelectionManager implements ISelectionProvider { if (viewInfos != null) { for (CanvasViewInfo viewInfo : viewInfos) { mSelections.add(createSelection(viewInfo)); - if (viewInfo.isInvisibleParent()) { + if (viewInfo.isInvisible()) { redoLayout = true; } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ViewHierarchy.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ViewHierarchy.java index 16d8f4374..8624cd323 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ViewHierarchy.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ViewHierarchy.java @@ -82,7 +82,7 @@ public class ViewHierarchy { private boolean mIsResultValid; /** - * A list of invisible parents (see {@link CanvasViewInfo#isInvisibleParent()} for + * A list of invisible parents (see {@link CanvasViewInfo#isInvisible()} for * details) in the current view hierarchy. */ private final List mInvisibleParents = new ArrayList(); @@ -293,7 +293,7 @@ public class ViewHierarchy { return; } - if (vi.isInvisibleParent()) { + if (vi.isInvisible()) { mInvisibleParents.add(vi); } else if (invisibleNodes != null) { UiViewElementNode key = vi.getUiViewNode(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewWizard.java index 96d8408ba..1372006c3 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewWizard.java @@ -19,6 +19,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout.refactoring; import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor; import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors; import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CustomViewFinder; import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository; import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; import com.android.ide.eclipse.adt.internal.sdk.Sdk; @@ -122,7 +123,7 @@ class ChangeViewWizard extends VisualRefactoringWizard { } Pair,List> result = - WrapInWizard.findViews(mProject, false); + CustomViewFinder.findViews(mProject, false); List customViews = result.getFirst(); List thirdPartyViews = result.getSecond(); if (customViews.size() > 0) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInWizard.java index d9e746ce3..69df9a159 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInWizard.java @@ -22,13 +22,10 @@ import static com.android.ide.common.layout.LayoutConstants.FQCN_RADIO_BUTTON; import static com.android.ide.common.layout.LayoutConstants.GESTURE_OVERLAY_VIEW; import static com.android.ide.common.layout.LayoutConstants.RADIO_GROUP; import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.VIEW_INCLUDE; -import static com.android.sdklib.SdkConstants.CLASS_VIEW; -import static com.android.sdklib.SdkConstants.CLASS_VIEWGROUP; -import static com.android.sdklib.SdkConstants.FN_FRAMEWORK_LIBRARY; -import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor; import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CustomViewFinder; import com.android.ide.eclipse.adt.internal.editors.layout.gre.PaletteMetadataDescriptor; import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository; import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator; @@ -39,22 +36,6 @@ import com.android.sdklib.IAndroidTarget; import com.android.util.Pair; import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IPackageFragment; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.search.IJavaSearchConstants; -import org.eclipse.jdt.core.search.IJavaSearchScope; -import org.eclipse.jdt.core.search.SearchEngine; -import org.eclipse.jdt.core.search.SearchMatch; -import org.eclipse.jdt.core.search.SearchParticipant; -import org.eclipse.jdt.core.search.SearchPattern; -import org.eclipse.jdt.core.search.SearchRequestor; -import org.eclipse.jdt.internal.core.ResolvedBinaryType; -import org.eclipse.jdt.internal.core.ResolvedSourceType; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; @@ -68,8 +49,7 @@ import java.util.Collections; import java.util.List; import java.util.Set; -@SuppressWarnings("restriction") // JDT model access for custom-view class lookup -class WrapInWizard extends VisualRefactoringWizard { +public class WrapInWizard extends VisualRefactoringWizard { private static final String SEPARATOR_LABEL = "----------------------------------------"; //$NON-NLS-1$ @@ -196,7 +176,7 @@ class WrapInWizard extends VisualRefactoringWizard { classNames.add(Pair.of(null, null)); } - Pair,List> result = findViews(project, true); + Pair,List> result = CustomViewFinder.findViews(project, true); List customViews = result.getFirst(); List thirdPartyViews = result.getSecond(); if (customViews.size() > 0) { @@ -284,66 +264,4 @@ class WrapInWizard extends VisualRefactoringWizard { return classNames; } - - /** - * Returns a pair of view lists - the custom views and the 3rd-party views - * - * @param project the Android project - * @param layoutsOnly if true, only search for layouts - * @return a pair of lists, the first containing custom views and the second - * containing 3rd party views - */ - public static Pair,List> findViews(IProject project, boolean layoutsOnly) { - final List customViews = new ArrayList(); - final List thirdPartyViews = new ArrayList(); - - SearchRequestor requestor = new SearchRequestor() { - @Override - public void acceptSearchMatch(SearchMatch match) throws CoreException { - Object element = match.getElement(); - - if (element instanceof ResolvedBinaryType) { - ResolvedBinaryType bt = (ResolvedBinaryType) element; - IPackageFragment fragment = bt.getPackageFragment(); - IPath path = fragment.getPath(); - String last = path.lastSegment(); - // Filter out android.jar stuff - if (last.equals(FN_FRAMEWORK_LIBRARY)) { - return; - } - String fqn = bt.getFullyQualifiedName(); - thirdPartyViews.add(fqn); - } else if (element instanceof ResolvedSourceType) { - ResolvedSourceType type = (ResolvedSourceType) element; - String fqn = type.getFullyQualifiedName(); - // User custom view - customViews.add(fqn); - } - } - }; - try { - IJavaProject javaProject = (IJavaProject) project.getNature(JavaCore.NATURE_ID); - if (javaProject != null) { - String className = layoutsOnly ? CLASS_VIEWGROUP : CLASS_VIEW; - IType activityType = javaProject.findType(className); - if (activityType != null) { - IJavaSearchScope scope = SearchEngine.createHierarchyScope(activityType); - SearchParticipant[] participants = new SearchParticipant[] { - SearchEngine.getDefaultSearchParticipant() - }; - int matchRule = SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CASE_SENSITIVE; - SearchPattern pattern = SearchPattern.createPattern("*", - IJavaSearchConstants.CLASS, IJavaSearchConstants.DECLARATIONS, - matchRule); - SearchEngine engine = new SearchEngine(); - engine.search(pattern, participants, scope, requestor, - new NullProgressMonitor()); - } - } - } catch (CoreException e) { - AdtPlugin.log(e, null); - } - - return Pair.of(customViews, thirdPartyViews); - } } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/descriptors/DescriptorsUtilsTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/descriptors/DescriptorsUtilsTest.java index bc0f36f95..580fbaada 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/descriptors/DescriptorsUtilsTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/descriptors/DescriptorsUtilsTest.java @@ -240,4 +240,10 @@ public class DescriptorsUtilsTest extends TestCase { return super.findClass(name); } } + + public void testGetBasename() { + assertEquals("Foo", DescriptorsUtils.getBasename("Foo")); + assertEquals("Foo", DescriptorsUtils.getBasename("foo.Foo")); + assertEquals("String", DescriptorsUtils.getBasename("java.util.String")); + } } -- 2.11.0