diff options
author | Tor Norbye <tnorbye@google.com> | 2011-03-11 13:50:10 -0800 |
---|---|---|
committer | Android Code Review <code-review@android.com> | 2011-03-11 13:50:10 -0800 |
commit | 50c0ec0406ba748fbe805c3399517d6b4b23398a (patch) | |
tree | b96b08cdfffabaee96bc415c5aebd42cb7156377 | |
parent | 97f1fba009d8643fb100433a3e63b1fc51497b1a (diff) | |
parent | adee9788a5ac646a39b516abe4cdd1022911a3f5 (diff) | |
download | sdk-50c0ec0406ba748fbe805c3399517d6b4b23398a.zip sdk-50c0ec0406ba748fbe805c3399517d6b4b23398a.tar.gz sdk-50c0ec0406ba748fbe805c3399517d6b4b23398a.tar.bz2 |
Merge "Add drop-support for include tags"
28 files changed, 331 insertions, 53 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java index efd8086..e849340 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java @@ -133,5 +133,15 @@ public interface IClientRulesEngine { * right, top and bottom margins respectively */ String[] displayMarginInput(String all, String left, String right, String top, String bottom); + + /** + * Displays an input dialog tailored for inputing the source of an {@code <include>} + * layout tag. This is similar to {@link #displayResourceInput} for resource type + * "layout", but should also attempt to filter out layout resources that cannot be + * included from the current context (because it would result in a cyclic dependency). + * + * @return the layout resource to include + */ + String displayIncludeSourceInput(); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/INode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/INode.java index 8c2bed1..dd64dfa 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/INode.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/INode.java @@ -128,6 +128,15 @@ public interface INode { INode insertChildAt(String viewFqcn, int index); /** + * Removes the given XML element child from this node's list of children. + * <p/> + * This call must be done in the context of editXml(). + * + * @param node The child to be deleted. + */ + void removeChild(INode node); + + /** * Sets an attribute for the underlying XML element. * Attributes are not written immediately -- instead the XML editor batches edits and * then commits them all together at once later. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/InsertType.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/InsertType.java index 15d3a98..c5a4435 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/InsertType.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/InsertType.java @@ -24,6 +24,12 @@ public enum InsertType { /** The view is newly created (by for example a palette drag) */ CREATE, + /** + * Same as {@link #CREATE} but when the views are constructed for previewing, for + * example as part of a palette drag. + */ + CREATE_PREVIEW, + /** The view is being inserted here because it was moved from somewhere else */ MOVE, @@ -32,4 +38,15 @@ public enum InsertType { * (including drags, but not from the palette) */ PASTE; + + /** + * Returns true if this insert type is for a newly created view (for example a by + * palette drag). Note that this includes both normal create events as well as well as + * views created as part of previewing operations. + * + * @return true if this {@link InsertType} is for a newly created view + */ + public boolean isCreate() { + return this == CREATE || this == CREATE_PREVIEW; + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java index d21c43d..1571e03 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java @@ -674,21 +674,4 @@ public class BaseViewRule implements IViewRule { } return value; } - - private static class PropertySettingNodeHandler implements INodeHandler { - private final String mNamespaceUri; - private final String mAttribute; - private final String mValue; - - public PropertySettingNodeHandler(String namespaceUri, String attribute, String value) { - super(); - mNamespaceUri = namespaceUri; - mAttribute = attribute; - mValue = value; - } - - public void handle(INode node) { - node.setAttribute(mNamespaceUri, mAttribute, mValue); - } - } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/DialerFilterRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/DialerFilterRule.java index b3cf5ce..9aa476e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/DialerFilterRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/DialerFilterRule.java @@ -37,7 +37,7 @@ public class DialerFilterRule extends BaseViewRule { super.onCreate(node, parent, insertType); // A DialerFilter requires a couple of nested EditTexts with fixed ids: - if (insertType == InsertType.CREATE) { + if (insertType.isCreate()) { String fillParent = getFillParentValueName(); INode hint = node.appendChild(FQCN_EDIT_TEXT); hint.setAttribute(ANDROID_URI, ATTR_TEXT, "Hint"); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/HorizontalScrollViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/HorizontalScrollViewRule.java index 71bd704..f73c114 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/HorizontalScrollViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/HorizontalScrollViewRule.java @@ -46,7 +46,7 @@ public class HorizontalScrollViewRule extends FrameLayoutRule { public void onCreate(INode node, INode parent, InsertType insertType) { super.onCreate(node, parent, insertType); - if (insertType == InsertType.CREATE) { + if (insertType.isCreate()) { // Insert a horizontal linear layout which is commonly used with horizontal scrollbars // as described by the documentation for HorizontalScrollbars. INode linearLayout = node.appendChild(FQCN_LINEAR_LAYOUT); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageButtonRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageButtonRule.java index 4338a9a..fe2e346 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageButtonRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageButtonRule.java @@ -32,7 +32,7 @@ public class ImageButtonRule extends BaseViewRule { public void onCreate(INode node, INode parent, InsertType insertType) { super.onCreate(node, parent, insertType); - if (insertType == InsertType.CREATE) { + if (insertType.isCreate()) { node.setAttribute(ANDROID_URI, ATTR_SRC, getSampleImageSrc()); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageViewRule.java index 9d26e75..d0f4da7 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageViewRule.java @@ -32,7 +32,7 @@ public class ImageViewRule extends BaseViewRule { public void onCreate(INode node, INode parent, InsertType insertType) { super.onCreate(node, parent, insertType); - if (insertType == InsertType.CREATE) { + if (insertType.isCreate()) { node.setAttribute(ANDROID_URI, ATTR_SRC, getSampleImageSrc()); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/IncludeRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/IncludeRule.java new file mode 100644 index 0000000..5b1830e --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/IncludeRule.java @@ -0,0 +1,43 @@ +/* + * 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.common.layout; + +import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.ATTR_LAYOUT; + +import com.android.ide.common.api.INode; +import com.android.ide.common.api.IViewRule; +import com.android.ide.common.api.InsertType; + +/** + * An {@link IViewRule} for the special XML {@code <include>} tag. + */ +public class IncludeRule extends BaseViewRule { + @Override + public void onCreate(INode node, INode parent, InsertType insertType) { + // When dropping an include tag, ask the user which layout to include. + if (insertType == InsertType.CREATE) { // NOT InsertType.CREATE_PREVIEW + String include = mRulesEngine.displayIncludeSourceInput(); + if (include != null) { + node.editXml("Include Layout", + // Note -- the layout attribute is NOT in the Android namespace! + new PropertySettingNodeHandler(null, ATTR_LAYOUT, include)); + } else { + // Remove the view; the insertion was canceled + parent.removeChild(node); + } + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MapViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MapViewRule.java index 301385a..eb1cf47 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MapViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MapViewRule.java @@ -34,7 +34,7 @@ public class MapViewRule extends BaseViewRule { public void onCreate(INode node, INode parent, InsertType insertType) { super.onCreate(node, parent, insertType); - if (insertType == InsertType.CREATE) { + if (insertType.isCreate()) { node.setAttribute(ANDROID_URI, "android:apiKey", //$NON-NLS-1$ "Your API key: see " + //$NON-NLS-1$ "http://code.google.com/android/add-ons/google-apis/mapkey.html"); //$NON-NLS-1$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertySettingNodeHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertySettingNodeHandler.java new file mode 100644 index 0000000..8c57da8 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertySettingNodeHandler.java @@ -0,0 +1,40 @@ +/* + * 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.common.layout; + +import com.android.ide.common.api.INode; +import com.android.ide.common.api.INodeHandler; + +/** + * A convenience implementation of {@link INodeHandler} for setting a given attribute to a + * given value on a particular node. + */ +class PropertySettingNodeHandler implements INodeHandler { + private final String mNamespaceUri; + private final String mAttribute; + private final String mValue; + + PropertySettingNodeHandler(String namespaceUri, String attribute, String value) { + super(); + mNamespaceUri = namespaceUri; + mAttribute = attribute; + mValue = value; + } + + public void handle(INode node) { + node.setAttribute(mNamespaceUri, mAttribute, mValue); + } +}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RadioGroupRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RadioGroupRule.java index 039b495..88cce52 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RadioGroupRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RadioGroupRule.java @@ -33,7 +33,7 @@ public class RadioGroupRule extends LinearLayoutRule { public void onCreate(INode node, INode parent, InsertType insertType) { super.onCreate(node, parent, insertType); - if (insertType == InsertType.CREATE) { + if (insertType.isCreate()) { for (int i = 0; i < 3; i++) { INode handle = node.appendChild(LayoutConstants.FQCN_RADIO_BUTTON); handle.setAttribute(ANDROID_URI, ATTR_ID, String.format("@+id/radio%d", i)); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ScrollViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ScrollViewRule.java index e3c349a..bf57456 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ScrollViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ScrollViewRule.java @@ -44,7 +44,7 @@ public class ScrollViewRule extends FrameLayoutRule { public void onCreate(INode node, INode parent, InsertType insertType) { super.onCreate(node, parent, insertType); - if (insertType == InsertType.CREATE) { + if (insertType.isCreate()) { // Insert a default linear layout (which will in turn be registered as // a child of this node and the create child method above will set its // fill parent attributes, its id, etc. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/SlidingDrawerRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/SlidingDrawerRule.java index 15c3b4c..4af0ae9 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/SlidingDrawerRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/SlidingDrawerRule.java @@ -37,7 +37,7 @@ public class SlidingDrawerRule extends BaseLayoutRule { public void onCreate(INode node, INode parent, InsertType insertType) { super.onCreate(node, parent, insertType); - if (insertType == InsertType.CREATE) { + if (insertType.isCreate()) { String matchParent = getFillParentValueName(); node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH, matchParent); node.setAttribute(ANDROID_URI, ATTR_LAYOUT_HEIGHT, matchParent); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TabHostRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TabHostRule.java index 92decde..2d7625b 100755..100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TabHostRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TabHostRule.java @@ -43,7 +43,7 @@ public class TabHostRule extends IgnoredLayoutRule { public void onCreate(INode node, INode parent, InsertType insertType) { super.onCreate(node, parent, insertType); - if (insertType == InsertType.CREATE) { + if (insertType.isCreate()) { String fillParent = getFillParentValueName(); // Configure default Table setup as described in the Table tutorial diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/WebViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/WebViewRule.java index 8ec53db..00085c8 100755..100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/WebViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/WebViewRule.java @@ -35,7 +35,7 @@ public class WebViewRule extends IgnoredLayoutRule { public void onCreate(INode node, INode parent, InsertType insertType) { super.onCreate(node, parent, insertType); - if (insertType == InsertType.CREATE) { + if (insertType.isCreate()) { String matchParent = getFillParentValueName(); node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH, matchParent); node.setAttribute(ANDROID_URI, ATTR_LAYOUT_HEIGHT, matchParent); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ZoomButtonRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ZoomButtonRule.java index ca0413e..1200da9 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ZoomButtonRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ZoomButtonRule.java @@ -26,7 +26,7 @@ public class ZoomButtonRule extends BaseViewRule { public void onCreate(INode node, INode parent, InsertType insertType) { super.onCreate(node, parent, insertType); - if (insertType == InsertType.CREATE) { + if (insertType.isCreate()) { node.setAttribute(ANDROID_URI, ATTR_SRC, "@android:drawable/btn_plus"); //$NON-NLS-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 3461d18..3d3cc57 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 @@ -21,7 +21,6 @@ import static com.android.ide.eclipse.adt.AdtConstants.EXT_XML; import static com.android.ide.eclipse.adt.AdtConstants.WS_LAYOUTS; import static com.android.ide.eclipse.adt.AdtConstants.WS_SEP; import static com.android.resources.ResourceType.LAYOUT; - import static org.eclipse.core.resources.IResourceDelta.ADDED; import static org.eclipse.core.resources.IResourceDelta.CHANGED; import static org.eclipse.core.resources.IResourceDelta.CONTENT; @@ -67,6 +66,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -186,7 +186,6 @@ public class IncludeFinder { } } - /** For test suite only -- do not call */ @VisibleForTesting /* package */ List<String> getIncludedBy(String included) { ensureInitialized(); @@ -1001,5 +1000,71 @@ public class IncludeFinder { public static Reference create(IFile file) { return new Reference(file.getProject(), getMapKey(file)); } + + /** + * Returns the resource name of this layout, such as {@code @layout/foo}. + * + * @return the resource name + */ + public String getResourceName() { + return '@' + FD_RES_LAYOUT + '/' + getName(); + } + } + + /** + * Returns a collection of layouts (expressed as resource names, such as + * {@code @layout/foo} which would be invalid includes in the given layout + * (because it would introduce a cycle) + * + * @param layout the layout file to check for cyclic dependencies from + * @return a collection of layout resources which cannot be included from + * the given layout, never null + */ + public Collection<String> getInvalidIncludes(IFile layout) { + IProject project = layout.getProject(); + Reference self = Reference.create(layout); + + // Add anyone who transitively can reach this file via includes. + LinkedList<Reference> queue = new LinkedList<Reference>(); + List<Reference> invalid = new ArrayList<Reference>(); + queue.add(self); + invalid.add(self); + Set<String> seen = new HashSet<String>(); + seen.add(self.getId()); + while (!queue.isEmpty()) { + Reference reference = queue.removeFirst(); + String refId = reference.getId(); + + // Look up both configuration specific includes as well as includes in the + // base versions + List<String> included = getIncludedBy(refId); + if (refId.indexOf('/') != -1) { + List<String> baseIncluded = getIncludedBy(reference.getName()); + if (included == null) { + included = baseIncluded; + } else if (baseIncluded != null) { + included = new ArrayList<String>(included); + included.addAll(baseIncluded); + } + } + + if (included != null && included.size() > 0) { + for (String id : included) { + if (!seen.contains(id)) { + seen.add(id); + Reference ref = new Reference(project, id); + invalid.add(ref); + queue.addLast(ref); + } + } + } + } + + List<String> result = new ArrayList<String>(); + for (Reference reference : invalid) { + result.add(reference.getResourceName()); + } + + return result; } } 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 fcf87d4..78e906c 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 @@ -42,6 +42,7 @@ import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeFactory; import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeProxy; 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.editors.layout.gre.ViewMetadataRepository.RenderMode; import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode; import com.android.ide.eclipse.adt.internal.editors.ui.DecorComposite; import com.android.ide.eclipse.adt.internal.editors.ui.IDecorContent; @@ -770,6 +771,12 @@ public class PaletteControl extends Composite { /** Performs the actual rendering of the descriptor into an image */ private Image renderPreview() { + ViewMetadataRepository repository = ViewMetadataRepository.get(); + RenderMode renderMode = repository.getRenderMode(mDesc.getFullClassName()); + if (renderMode == RenderMode.SKIP) { + return null; + } + // Create blank XML document Document document = null; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); @@ -836,7 +843,7 @@ public class PaletteControl extends Composite { UiViewElementNode childUiNode = (UiViewElementNode) child; NodeProxy childNode = nodeFactory.create(childUiNode); canvas.getRulesEngine().callCreateHooks(layoutEditor, - null, childNode, InsertType.CREATE); + null, childNode, InsertType.CREATE_PREVIEW); } Integer overrideBgColor = null; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java index 59c6e15..bd8e75e 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java @@ -203,6 +203,12 @@ public class NodeProxy implements INode { return insertOrAppend(viewFqcn, index); } + public void removeChild(INode node) { + checkEditOK(); + + ((NodeProxy) node).mNode.deleteXmlNode(); + } + private INode insertOrAppend(String viewFqcn, int index) { checkEditOK(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java index 7a1e06e..dd47986 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java @@ -36,6 +36,7 @@ import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor; import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder; import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SimpleElement; import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode; import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; @@ -63,6 +64,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -874,6 +876,11 @@ public class RulesEngine { } public String displayResourceInput(String resourceTypeName, String currentValue) { + return displayResourceInput(resourceTypeName, currentValue, null); + } + + private String displayResourceInput(String resourceTypeName, String currentValue, + IInputValidator validator) { AndroidXmlEditor editor = mEditor.getLayoutEditor(); IProject project = editor.getProject(); ResourceType type = ResourceType.getEnum(resourceTypeName); @@ -893,6 +900,12 @@ public class RulesEngine { ResourceChooser dlg = new ResourceChooser(project, type, projectRepository, systemRepository, shell); + if (validator != null) { + // Ensure wide enough to accommodate validator error message + dlg.setSize(70, 10); + dlg.setInputValidator(validator); + } + dlg.setCurrentResource(currentValue); if (dlg.open() == Window.OK) { @@ -922,5 +935,29 @@ public class RulesEngine { return null; } + + public String displayIncludeSourceInput() { + AndroidXmlEditor editor = mEditor.getLayoutEditor(); + IProject project = editor.getProject(); + if (project != null) { + IncludeFinder includeFinder = IncludeFinder.get(project); + final Collection<String> invalid = + includeFinder.getInvalidIncludes(editor.getInputFile()); + IInputValidator validator = new IInputValidator() { + public String isValid(String newText) { + if (invalid.contains(newText)) { + return String.format( + "Cyclic include, not valid", + newText); + } + return null; + } + }; + + return displayResourceInput(ResourceType.LAYOUT.getName(), null, validator); + } + + return null; + } } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/extra-view-metadata.xml b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/extra-view-metadata.xml index 96e9a01..f11b862 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/extra-view-metadata.xml +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/extra-view-metadata.xml @@ -156,6 +156,10 @@ fill="opposite" render="skip" /> <view + class="include" + name="Include Other Layout" + render="skip" /> + <view class="android.widget.TableLayout" fill="opposite" render="skip" /> @@ -310,10 +314,6 @@ <view class="android.widget.ZoomControls" /> <view - class="include" - skip="true" - render="skip" /> - <view class="merge" skip="true" render="skip" /> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutWizard.java index b182ea4..6927568 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutWizard.java @@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout.refactoring; import static com.android.ide.common.layout.LayoutConstants.FQCN_RELATIVE_LAYOUT; import static com.android.ide.common.layout.LayoutConstants.RELATIVE_LAYOUT; +import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.VIEW_INCLUDE; import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor; @@ -33,7 +34,9 @@ import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; +import java.util.HashSet; import java.util.List; +import java.util.Set; class ChangeLayoutWizard extends VisualRefactoringWizard { @@ -100,9 +103,12 @@ class ChangeLayoutWizard extends VisualRefactoringWizard { // We don't exclude RelativeLayout even if the current layout is RelativeLayout, // in case you are trying to flatten the hierarchy for a hierarchy that has a // RelativeLayout at the root. + Set<String> exclude = new HashSet<String>(); + exclude.add(VIEW_INCLUDE); boolean oldIsRelativeLayout = mOldType.equals(FQCN_RELATIVE_LAYOUT); - String exclude = oldIsRelativeLayout ? null : mOldType; - + if (oldIsRelativeLayout) { + exclude.add(mOldType); + } mClassNames = WrapInWizard.addLayouts(mProject, mOldType, mTypeCombo, exclude, false); mTypeCombo.select(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 caee8f7..033a657 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 @@ -21,6 +21,7 @@ import static com.android.ide.common.layout.LayoutConstants.FQCN_LINEAR_LAYOUT; 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; @@ -68,7 +69,9 @@ import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import java.util.ArrayList; +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 { @@ -139,7 +142,8 @@ class WrapInWizard extends VisualRefactoringWizard { mUpdateReferences.setText("Update layout references"); mUpdateReferences.addSelectionListener(selectionListener); - mClassNames = addLayouts(mProject, mOldType, mTypeCombo, null, true); + Set<String> exclude = Collections.singleton(VIEW_INCLUDE); + mClassNames = addLayouts(mProject, mOldType, mTypeCombo, exclude, true); mTypeCombo.select(0); setControl(composite); @@ -194,8 +198,8 @@ class WrapInWizard extends VisualRefactoringWizard { } } - static List<String> addLayouts(IProject project, String oldType, Combo combo, String exclude, - boolean addGestureOverlay) { + static List<String> addLayouts(IProject project, String oldType, Combo combo, + Set<String> exclude, boolean addGestureOverlay) { List<String> classNames = new ArrayList<String>(); if (oldType.equals(FQCN_RADIO_BUTTON)) { @@ -245,7 +249,7 @@ class WrapInWizard extends VisualRefactoringWizard { if (layoutDescriptors != null) { for (ViewElementDescriptor d : layoutDescriptors) { String className = d.getFullClassName(); - if (exclude == null || !exclude.equals(className)) { + if (exclude == null || !exclude.contains(className)) { combo.add(d.getUiName()); classNames.add(className); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java index b57de72..cfa29f8 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java @@ -42,6 +42,7 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IInputValidator; import org.eclipse.jface.window.Window; import org.eclipse.ltk.ui.refactoring.RefactoringWizard; import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation; @@ -77,6 +78,7 @@ import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -96,6 +98,7 @@ public class ResourceChooser extends AbstractElementListSelectionDialog { private Button mNewButton; private String mCurrentResource; private final IProject mProject; + private IInputValidator mInputValidator; /** * Creates a Resource Chooser dialog. @@ -135,6 +138,10 @@ public class ResourceChooser extends AbstractElementListSelectionDialog { return mCurrentResource; } + public void setInputValidator(IInputValidator inputValidator) { + mInputValidator = inputValidator; + } + @Override protected void computeResult() { Object[] elements = getSelectedElements(); @@ -143,6 +150,10 @@ public class ResourceChooser extends AbstractElementListSelectionDialog { mCurrentResource = ResourceHelper.getXmlString(mResourceType, item, mSystemButton.getSelection()); + + if (mInputValidator != null && mInputValidator.isValid(mCurrentResource) != null) { + mCurrentResource = null; + } } } @@ -229,6 +240,27 @@ public class ResourceChooser extends AbstractElementListSelectionDialog { }); } + @Override + protected void handleSelectionChanged() { + super.handleSelectionChanged(); + if (mInputValidator != null) { + Object[] elements = getSelectedElements(); + if (elements.length == 1 && elements[0] instanceof ResourceItem) { + ResourceItem item = (ResourceItem)elements[0]; + String current = ResourceHelper.getXmlString(mResourceType, item, + mSystemButton.getSelection()); + String error = mInputValidator.isValid(current); + IStatus status; + if (error != null) { + status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, error); + } else { + status = new Status(IStatus.OK, AdtPlugin.PLUGIN_ID, null); + } + updateStatus(status); + } + } + } + private String createNewValue(ResourceType type) { // Show a name/value dialog entering the key name and the value Shell shell = AdtPlugin.getDisplay().getActiveShell(); @@ -376,6 +408,10 @@ public class ResourceChooser extends AbstractElementListSelectionDialog { items = mFrameworkResources.getResourceItemsOfType(mResourceType); } + if (items == null) { + items = Collections.emptyList(); + } + ResourceItem[] arrayItems = items.toArray(new ResourceItem[items.size()]); // sort the array @@ -410,19 +446,21 @@ public class ResourceChooser extends AbstractElementListSelectionDialog { boolean isSystem = false; String itemName = null; - // Is this a system resource? - // If not a system resource or if they are not available, this will be a project res. - Matcher m = mSystemResourcePattern.matcher(resourceString); - if (m.matches()) { - itemName = m.group(1); - isSystem = true; - } - - if (!isSystem && itemName == null) { - // Try to match project resource name - m = mProjectResourcePattern.matcher(resourceString); + if (resourceString != null) { + // Is this a system resource? + // If not a system resource or if they are not available, this will be a project res. + Matcher m = mSystemResourcePattern.matcher(resourceString); if (m.matches()) { itemName = m.group(1); + isSystem = true; + } + + if (!isSystem && itemName == null) { + // Try to match project resource name + m = mProjectResourcePattern.matcher(resourceString); + if (m.matches()) { + itemName = m.group(1); + } } } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java index 9c60d33..a7aae04 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java @@ -244,6 +244,11 @@ public class LayoutTestBase extends TestCase { fail("Not supported in tests yet"); return null; } + + public String displayIncludeSourceInput() { + fail("Not supported in tests yet"); + return null; + } } public void testDummy() { diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java index 14430a5..d5f1ae9 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java @@ -154,6 +154,13 @@ public class TestNode implements INode { return child; } + public void removeChild(INode node) { + int index = mChildren.indexOf(node); + if (index != -1) { + removeChild(index); + } + } + public boolean setAttribute(String uri, String localName, String value) { mAttributes.put(uri + localName, new TestAttribute(uri, localName, value)); return true; @@ -164,4 +171,5 @@ public class TestNode implements INode { return "TestNode [fqn=" + mFqcn + ", infos=" + mAttributeInfos + ", attributes=" + mAttributes + ", bounds=" + mBounds + "]"; } + }
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepositoryTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepositoryTest.java index 36f4ccd..5921e85 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepositoryTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepositoryTest.java @@ -50,7 +50,7 @@ public class ViewMetadataRepositoryTest extends TestCase { public void testSkip() throws Exception { ViewMetadataRepository repository = ViewMetadataRepository.get(); - assertTrue(repository.getSkip("include")); + assertTrue(repository.getSkip("merge")); assertFalse(repository.getSkip("android.widget.Button")); } |