diff options
18 files changed, 526 insertions, 138 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/refresh.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/refresh.png Binary files differnew file mode 100644 index 0000000..7cbebf4 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/icons/refresh.png 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 95edfb3..0384ad5 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. * <p/> * 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 d4ba57f..804156a 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 bfc8bb0..db72ac6 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 24c582d..3c18b16 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 30dc3e9..2bb8901 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 0000000..8cb0d26 --- /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<Listener> mListeners = new ArrayList<Listener>(); + + private List<String> mCustomViews; + private List<String> 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<String> getCustomViews() { + return mCustomViews == null ? null : Collections.unmodifiableCollection(mCustomViews); + } + + public Collection<String> getThirdPartyViews() { + return mThirdPartyViews == null + ? null : Collections.unmodifiableCollection(mThirdPartyViews); + } + + public Collection<String> getAllViews() { + // Not yet initialized: return null + if (mCustomViews == null) { + return null; + } + List<String> all = new ArrayList<String>(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<String>,List<String>> findViews( + final IProject project, boolean layoutsOnly) { + CustomViewFinder finder = get(project); + + return finder.findViews(layoutsOnly); + } + + private Pair<List<String>,List<String>> findViews(final boolean layoutsOnly) { + final List<String> customViews = new ArrayList<String>(); + final List<String> thirdPartyViews = new ArrayList<String>(); + + ProjectState state = Sdk.getProjectState(mProject); + final List<IProject> libraries = state != null + ? state.getFullLibraryProjects() : Collections.<IProject>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<String> customViews, Collection<String> 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<String>, List<String>> 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<String> customViews = + Collections.unmodifiableCollection(mCustomViews); + Collection<String> 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 753010f..6d1c25b 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 9da4af9..86e33be 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 d29544d..277c194 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 b08e616..3c1bd6a 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 89e02df..0353d1f 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<ViewElementDescriptor> 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<ViewElementDescriptor> 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<String> 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<String> customViews, + Collection<String> 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 1e9eebe..01b9314 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 e34ecbf..be17b68 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 16d8f43..8624cd3 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<CanvasViewInfo> mInvisibleParents = new ArrayList<CanvasViewInfo>(); @@ -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 96d8408..1372006 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<String>,List<String>> result = - WrapInWizard.findViews(mProject, false); + CustomViewFinder.findViews(mProject, false); List<String> customViews = result.getFirst(); List<String> 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 d9e746c..69df9a1 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.<String,ViewElementDescriptor>of(null, null)); } - Pair<List<String>,List<String>> result = findViews(project, true); + Pair<List<String>,List<String>> result = CustomViewFinder.findViews(project, true); List<String> customViews = result.getFirst(); List<String> 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<String>,List<String>> findViews(IProject project, boolean layoutsOnly) { - final List<String> customViews = new ArrayList<String>(); - final List<String> thirdPartyViews = new ArrayList<String>(); - - 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 bc0f36f..580fbaa 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")); + } } |