diff options
author | Tor Norbye <tnorbye@google.com> | 2011-05-13 13:25:15 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2011-05-13 13:31:49 -0700 |
commit | ec22f92d53f4bb74313b91aa491acbfbbb6dc9ce (patch) | |
tree | c599becdac246961adc3361a4f90bcbbb9f42875 | |
parent | ddc754e4650a4b48a82a96f4d38bdeb468059f29 (diff) | |
download | sdk-ec22f92d53f4bb74313b91aa491acbfbbb6dc9ce.zip sdk-ec22f92d53f4bb74313b91aa491acbfbbb6dc9ce.tar.gz sdk-ec22f92d53f4bb74313b91aa491acbfbbb6dc9ce.tar.bz2 |
Custom View handling improvements
First and foremost, allow custom views to accept children such that
you can drag & drop children into the custom view in the outline.
Second, prevent an NPE which can occur if you drag into a layout where
the root element is a custom view.
Third, handle <view> (not <View>) better: provide a custom icon, and
inline the view class name in the outline label.
Fourth, allow double clicks (in addition to ctrl-click which is already
supported) on the custom views in the palette to allow jumping to the
custom view code.
Change-Id: I13c2bf2f4169185c9fcc893ce487f2abdac46802
9 files changed, 67 insertions, 12 deletions
diff --git a/eclipse/dictionary.txt b/eclipse/dictionary.txt index 9291f47..ba17783 100644 --- a/eclipse/dictionary.txt +++ b/eclipse/dictionary.txt @@ -67,6 +67,7 @@ diff diffs dir dirs +discoverable ditto docs dpi diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/view.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/view.png Binary files differnew file mode 100644 index 0000000..35c4d8f --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/icons/view.png diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ViewRule.java index 470b6a4..a7b23ab 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ViewRule.java @@ -24,7 +24,7 @@ import com.android.ide.common.api.IViewRule; * apply. * <p/> * There is no customization here, everything that is common to all views is - * simply implemented in BaseView. + * simply implemented in BaseViewRule. */ public class ViewRule extends BaseViewRule { 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 db72ac6..be9fe34 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 @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.internal.editors.layout.descriptors; +import static com.android.sdklib.SdkConstants.CLASS_VIEWGROUP; + 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; @@ -164,7 +166,8 @@ public final class CustomViewDescriptorService { String name = DescriptorsUtils.getBasename(fqcn); ViewElementDescriptor descriptor = new CustomViewDescriptor(name, fqcn, - getAttributeDescriptor(type, parentDescriptor)); + getAttributeDescriptor(type, parentDescriptor), + parentDescriptor.hasChildren()); descriptor.setSuperClass(parentDescriptor); synchronized (mCustomDescriptorMap) { @@ -241,8 +244,14 @@ public final class CustomViewDescriptorService { // parent class is a valid View class with a descriptor, so we create one // for this class. String name = DescriptorsUtils.getBasename(fqcn); + // A custom view accepts children if its parent descriptor also does. + // The only exception to this is ViewGroup, which accepts children even though + // its parent does not. + boolean isViewGroup = fqcn.equals(CLASS_VIEWGROUP); + boolean hasChildren = isViewGroup || parentDescriptor.hasChildren(); ViewElementDescriptor descriptor = new CustomViewDescriptor(name, fqcn, - getAttributeDescriptor(type, parentDescriptor)); + getAttributeDescriptor(type, parentDescriptor), + hasChildren); descriptor.setSuperClass(parentDescriptor); // add it to the map @@ -283,7 +292,10 @@ public final class CustomViewDescriptorService { } private class CustomViewDescriptor extends ViewElementDescriptor { - public CustomViewDescriptor(String name, String fqcn, AttributeDescriptor[] attributes) { + private boolean mHasChildren; + + public CustomViewDescriptor(String name, String fqcn, AttributeDescriptor[] attributes, + boolean hasChildren) { super( fqcn, // xml name name, // ui name @@ -295,8 +307,21 @@ public final class CustomViewDescriptorService { null, // children false // mandatory ); + mHasChildren = hasChildren; + } + + /** + * {@inheritDoc} + * <p> + * Custom views can accept children even if we have no information about + * allowed children. + */ + @Override + public boolean hasChildren() { + return mHasChildren; } + @Override public Image getGenericIcon() { // Java source file icon. We could use the Java class icon here diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java index 4613492..24aea33 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java @@ -63,6 +63,15 @@ public final class LayoutDescriptors implements IDescriptorProvider { public static final String REQUEST_FOCUS = "requestFocus";//$NON-NLS-1$ /** + * The XML name of the special {@code <view>} layout tag. This is used to add generic + * views with a class attribute to specify the view. + * <p> + * TODO: We should add a synthetic descriptor for this, similar to our descriptors for + * include, merge and requestFocus. + */ + public static final String VIEW_VIEWTAG = "view"; //$NON-NLS-1$ + + /** * The attribute name of the include tag's url naming the resource to be inserted * <p> * <b>NOTE</b>: The layout attribute is NOT in the Android namespace! @@ -353,7 +362,7 @@ public final class LayoutDescriptors implements IDescriptorProvider { } /** - * Creates and return a new {@code <merge>} descriptor. + * Creates and returns a new {@code <merge>} descriptor. * @param knownLayouts A list of all known layout view descriptors, used to find the * FrameLayout descriptor and extract its layout attributes. */ @@ -379,9 +388,7 @@ public final class LayoutDescriptors implements IDescriptorProvider { } /** - * Creates and return a new {@code <requestFocus>} descriptor. - * @param knownLayouts A list of all known layout view descriptors, used to find the - * FrameLayout descriptor and extract its layout attributes. + * Creates and returns a new {@code <requestFocus>} descriptor. */ private ViewElementDescriptor createRequestFocus() { String xml_name = REQUEST_FOCUS; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java index a2cdbe6..a56eb16 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java @@ -674,7 +674,7 @@ public class MoveGesture extends DropGesture { // Update outline to show the target node there OutlinePage outline = mCanvas.getOutlinePage(); TreeSelection newSelection = TreeSelection.EMPTY; - if (mCurrentView != null) { + if (mCurrentView != null && mTargetNode != null) { // Find the view corresponding to the target node. The current view can be a leaf // view whereas the target node is always a parent layout. if (mCurrentView.getUiViewNode() != mTargetNode.getNode()) { 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 2227531..4b4bf96 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 @@ -23,14 +23,14 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_TEXT; import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT; import com.android.ide.common.api.InsertType; -import com.android.ide.common.api.MenuAction.Toggle; import com.android.ide.common.api.Rect; +import com.android.ide.common.api.MenuAction.Toggle; import com.android.ide.common.rendering.LayoutLibrary; import com.android.ide.common.rendering.api.Capability; import com.android.ide.common.rendering.api.LayoutLog; import com.android.ide.common.rendering.api.RenderSession; -import com.android.ide.common.rendering.api.SessionParams.RenderingMode; import com.android.ide.common.rendering.api.ViewInfo; +import com.android.ide.common.rendering.api.SessionParams.RenderingMode; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.IconFactory; import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils; @@ -572,10 +572,16 @@ public class PaletteControl extends Composite { Control item = createItem(parent, desc); // Add control-click listener on custom view items to you can warp to + // (and double click listener too -- the more discoverable, the better.) if (item instanceof IconTextItem) { IconTextItem it = (IconTextItem) item; it.addMouseListener(new MouseAdapter() { @Override + public void mouseDoubleClick(MouseEvent e) { + AdtPlugin.openJavaClass(mEditor.getProject(), fqcn); + } + + @Override public void mouseDown(MouseEvent e) { if ((e.stateMask & SWT.MOD1) != 0) { AdtPlugin.openJavaClass(mEditor.getProject(), fqcn); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepository.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepository.java index cf6acba..42b4a16 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepository.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepository.java @@ -343,13 +343,17 @@ public class ViewMetadataRepository { String fqcn = view.getFcqn(); ViewElementDescriptor descriptor = fqcnToDescriptor.get(fqcn); if (descriptor != null) { + remaining.remove(descriptor); + if (view.getSkip()) { + continue; + } + if (view.getDisplayName() != null || view.getInitString().length() > 0) { categoryItems.add(new PaletteMetadataDescriptor(descriptor, view.getDisplayName(), view.getInitString(), view.getIconName())); } else { categoryItems.add(descriptor); } - remaining.remove(descriptor); if (view.hasVariations()) { for (ViewData variation : view.getVariations()) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java index 93b6baf..e2b6ccf 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java @@ -17,6 +17,7 @@ package com.android.ide.eclipse.adt.internal.editors.uimodel; import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME; +import static com.android.ide.common.layout.LayoutConstants.ATTR_CLASS; import static com.android.ide.common.layout.LayoutConstants.ID_PREFIX; import static com.android.ide.common.layout.LayoutConstants.NEW_ID_PREFIX; import static com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor.XMLNS; @@ -288,6 +289,17 @@ public class UiElementNode implements IPropertySource { public StyledString getStyledDescription() { String uiName = mDescriptor.getUiName(); + // Special case: for <view>, show the class attribute value instead. + // This is done here rather than in the descriptor since this depends on + // node instance data. + if (LayoutDescriptors.VIEW_VIEWTAG.equals(uiName) && mXmlNode instanceof Element) { + Element element = (Element) mXmlNode; + String cls = element.getAttribute(ATTR_CLASS); + if (cls != null) { + uiName = cls.substring(cls.lastIndexOf('.') + 1); + } + } + StyledString styledString = new StyledString(); String attr = getDescAttribute(); if (attr != null) { |