diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com')
26 files changed, 1822 insertions, 46 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttrsXmlParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttrsXmlParser.java index bd79e29b6..1e14f9f0e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttrsXmlParser.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttrsXmlParser.java @@ -256,7 +256,7 @@ public final class AttrsXmlParser { if (parents != null) { String[] parentsArray = parseStyleableParents(parents, mStyleMap, unknownParents); - style.setParents(parentsArray); //$NON-NLS-1$ + style.setParents(parentsArray); } mStyleMap.put(name, style); unknownParents.remove(name); @@ -441,9 +441,9 @@ public final class AttrsXmlParser { * </ul> * The format may be one type or two types (e.g. "reference|color"). * An extra format can be implied: "enum" or "flag" are not specified in the "format" attribute, - * they are implicitely stated by the presence of sub-nodes <enum> or <flag>. + * they are implicitly stated by the presence of sub-nodes <enum> or <flag>. * <p/> - * By design, <attr> nodes of the same name MUST have the same type. + * By design, attr nodes of the same name MUST have the same type. * Attribute nodes are thus cached by name and reused as much as possible. * When reusing a node, it is duplicated and its javadoc reassigned. */ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java index 43fd82346..55a5ef8af 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java @@ -25,6 +25,9 @@ import com.android.ide.common.sdk.LoadStatus; import com.android.ide.eclipse.adt.internal.VersionCheck; import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; import com.android.ide.eclipse.adt.internal.editors.IconFactory; +import com.android.ide.eclipse.adt.internal.editors.animator.AnimationEditor; +import com.android.ide.eclipse.adt.internal.editors.color.ColorEditor; +import com.android.ide.eclipse.adt.internal.editors.drawable.DrawableEditor; import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor; import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder; import com.android.ide.eclipse.adt.internal.editors.menu.MenuEditor; @@ -1511,11 +1514,17 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger { AdtPlugin.log(IStatus.INFO, " set default editor id to layout"); } IDE.setDefaultEditor(file, LayoutEditor.ID); - } else if (type == ResourceFolderType.DRAWABLE - || type == ResourceFolderType.VALUES) { + } else if (type == ResourceFolderType.VALUES) { IDE.setDefaultEditor(file, ResourcesEditor.ID); } else if (type == ResourceFolderType.MENU) { IDE.setDefaultEditor(file, MenuEditor.ID); + } else if (type == ResourceFolderType.COLOR) { + IDE.setDefaultEditor(file, ColorEditor.ID); + } else if (type == ResourceFolderType.DRAWABLE) { + IDE.setDefaultEditor(file, DrawableEditor.ID); + } else if (type == ResourceFolderType.ANIMATOR + || type == ResourceFolderType.ANIM) { + IDE.setDefaultEditor(file, AnimationEditor.ID); } else if (type == ResourceFolderType.XML) { if (XmlEditor.canHandleFile(file)) { if (DEBUG_XML_FILE_INIT) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFix.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFix.java index 436fcace9..7d79086a2 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFix.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFix.java @@ -16,9 +16,12 @@ package com.android.ide.eclipse.adt.internal.build; +import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI; + import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor; import com.android.ide.eclipse.adt.internal.resources.ResourceHelper; import com.android.resources.ResourceType; import com.android.util.Pair; @@ -31,6 +34,7 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Region; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext; @@ -45,12 +49,21 @@ import org.eclipse.ui.IMarkerResolutionGenerator2; import org.eclipse.ui.PartInitException; import org.eclipse.ui.editors.text.TextFileDocumentProvider; import org.eclipse.ui.texteditor.IDocumentProvider; +import org.eclipse.wst.sse.core.StructuredModelManager; +import org.eclipse.wst.sse.core.internal.provisional.IModelManager; +import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; +import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; +import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; /** * Shared handler for both quick assist processors (Control key handler) and quick fix * marker resolution (Problem view handling), since there is a lot of overlap between * these two UI handlers. */ +@SuppressWarnings("restriction") // XML model public class AaptQuickFix implements IMarkerResolutionGenerator2, IQuickAssistProcessor { public AaptQuickFix() { @@ -61,6 +74,11 @@ public class AaptQuickFix implements IMarkerResolutionGenerator2, IQuickAssistPr return "No resource found that matches the given name"; } + /** Returns the error message from aapt that signals a missing namespace declaration */ + private static String getUnboundErrorMessage() { + return "Error parsing XML: unbound prefix"; + } + // ---- Implements IMarkerResolution2 ---- public boolean hasResolutions(IMarker marker) { @@ -71,12 +89,24 @@ public class AaptQuickFix implements IMarkerResolutionGenerator2, IQuickAssistPr AdtPlugin.log(e, null); } - return message != null && message.contains(getTargetMarkerErrorMessage()); + return message != null + && (message.contains(getTargetMarkerErrorMessage()) + || message.contains(getUnboundErrorMessage())); } public IMarkerResolution[] getResolutions(IMarker marker) { IResource markerResource = marker.getResource(); IProject project = markerResource.getProject(); + try { + String message = (String) marker.getAttribute(IMarker.MESSAGE); + if (message.contains(getUnboundErrorMessage()) && markerResource instanceof IFile) { + return new IMarkerResolution[] { + new CreateNamespaceFix((IFile) markerResource) + }; + } + } catch (CoreException e1) { + AdtPlugin.log(e1, null); + } int start = marker.getAttribute(IMarker.CHAR_START, 0); int end = marker.getAttribute(IMarker.CHAR_END, 0); @@ -158,6 +188,10 @@ public class AaptQuickFix implements IMarkerResolutionGenerator2, IQuickAssistPr }; } } + } else if (message.contains(getUnboundErrorMessage())) { + return new ICompletionProposal[] { + new CreateNamespaceFix(null) + }; } } } catch (CoreException e) { @@ -174,6 +208,120 @@ public class AaptQuickFix implements IMarkerResolutionGenerator2, IQuickAssistPr return null; } + /** Quick fix to insert namespace binding when missing */ + private final static class CreateNamespaceFix + implements ICompletionProposal, IMarkerResolution2 { + private IFile mFile; + + public CreateNamespaceFix(IFile file) { + mFile = file; + } + + private IndexedRegion perform(IDocument doc) { + IModelManager manager = StructuredModelManager.getModelManager(); + IStructuredModel model = manager.getExistingModelForEdit(doc); + if (model != null) { + try { + perform(model); + } finally { + model.releaseFromEdit(); + } + } + + return null; + } + + private IndexedRegion perform(IFile file) { + IModelManager manager = StructuredModelManager.getModelManager(); + IStructuredModel model; + try { + model = manager.getModelForEdit(file); + if (model != null) { + try { + perform(model); + } finally { + model.releaseFromEdit(); + } + } + } catch (Exception e) { + AdtPlugin.log(e, "Can't look up XML model"); + } + + return null; + } + + private IndexedRegion perform(IStructuredModel model) { + if (model instanceof IDOMModel) { + IDOMModel domModel = (IDOMModel) model; + Document document = domModel.getDocument(); + Element element = document.getDocumentElement(); + Attr attr = document.createAttributeNS(XmlnsAttributeDescriptor.XMLNS_URI, + "xmlns:android"); //$NON-NLS-1$ + attr.setValue(ANDROID_URI); + element.getAttributes().setNamedItemNS(attr); + return (IndexedRegion) attr; + } + + return null; + } + + // ---- Implements ICompletionProposal ---- + + public void apply(IDocument document) { + perform(document); + } + + public String getAdditionalProposalInfo() { + return "Adds an Android namespace declaratiopn to the root element."; + } + + public IContextInformation getContextInformation() { + return null; + } + + public String getDisplayString() { + return "Insert namespace binding"; + } + + public Image getImage() { + return AdtPlugin.getAndroidLogo(); + } + + public Point getSelection(IDocument doc) { + return null; + } + + + // ---- Implements MarkerResolution2 ---- + + public String getLabel() { + return getDisplayString(); + } + + public void run(IMarker marker) { + try { + AdtPlugin.openFile(mFile, null); + } catch (PartInitException e) { + AdtPlugin.log(e, "Can't open file %1$s", mFile.getName()); + } + + IndexedRegion indexedRegion = perform(mFile); + if (indexedRegion != null) { + try { + IRegion region = + new Region(indexedRegion.getStartOffset(), indexedRegion.getLength()); + AdtPlugin.openFile(mFile, region); + } catch (PartInitException e) { + AdtPlugin.log(e, "Can't open file %1$s", mFile.getName()); + } + } + } + + public String getDescription() { + return getAdditionalProposalInfo(); + } + } + private static class CreateResourceProposal implements ICompletionProposal, IMarkerResolution2 { private final IProject mProject; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java index 86ff16e88..17ffe30eb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java @@ -1163,6 +1163,11 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor { return null; } + /** Returns the root descriptor id to use */ + protected int getRootDescriptorId() { + return mDescriptorId; + } + /** * Computes (if needed) and returns the root descriptor. */ @@ -1170,7 +1175,8 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor { if (mRootDescriptor == null) { AndroidTargetData data = mEditor.getTargetData(); if (data != null) { - IDescriptorProvider descriptorProvider = data.getDescriptorProvider(mDescriptorId); + IDescriptorProvider descriptorProvider = + data.getDescriptorProvider(getRootDescriptorId()); if (descriptorProvider != null) { mRootDescriptor = new ElementDescriptor("", //$NON-NLS-1$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimDescriptors.java new file mode 100644 index 000000000..dabab8784 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimDescriptors.java @@ -0,0 +1,124 @@ +/* + * 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.animator; + +import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME; + +import com.android.ide.common.resources.platform.DeclareStyleableInfo; +import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider; +import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor; +import com.android.sdklib.SdkConstants; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** Descriptors for the res/anim resources */ +public class AnimDescriptors implements IDescriptorProvider { + /** The root element descriptor */ + private ElementDescriptor mDescriptor; + /** The root element descriptors */ + private ElementDescriptor[] mRootDescriptors; + private Map<String, ElementDescriptor> nameToDescriptor; + + /** @return the root descriptor. */ + public ElementDescriptor getDescriptor() { + if (mDescriptor == null) { + mDescriptor = new ElementDescriptor("", getRootElementDescriptors()); //$NON-NLS-1$ + } + + return mDescriptor; + } + + public ElementDescriptor[] getRootElementDescriptors() { + return mRootDescriptors; + } + + public ElementDescriptor getElementDescriptor(String mRootTag) { + if (nameToDescriptor == null) { + nameToDescriptor = new HashMap<String, ElementDescriptor>(); + for (ElementDescriptor descriptor : getRootElementDescriptors()) { + nameToDescriptor.put(descriptor.getXmlName(), descriptor); + } + } + + ElementDescriptor descriptor = nameToDescriptor.get(mRootTag); + if (descriptor == null) { + descriptor = getDescriptor(); + } + return descriptor; + } + + public synchronized void updateDescriptors(Map<String, DeclareStyleableInfo> styleMap) { + if (styleMap == null) { + return; + } + + XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(ANDROID_NS_NAME, + SdkConstants.NS_RESOURCES); + + List<ElementDescriptor> descriptors = new ArrayList<ElementDescriptor>(); + + String sdkUrl = + "http://developer.android.com/guide/topics/graphics/view-animation.html"; //$NON-NLS-1$ + ElementDescriptor set = AnimatorDescriptors.addElement(descriptors, styleMap, + "set", "Set", "AnimationSet", "Animation", //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-4$ + "A container that holds other animation elements (<alpha>, <scale>, " + + "<translate>, <rotate>) or other <set> elements. ", + sdkUrl, + xmlns, null, true /*mandatory*/); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "alpha", "Alpha", "AlphaAnimation", "Animation", //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-4$ + "A fade-in or fade-out animation.", + sdkUrl, + xmlns, null, true /*mandatory*/); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "scale", "Scale", "ScaleAnimation", "Animation", //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-4$ + "A resizing animation. You can specify the center point of the image from " + + "which it grows outward (or inward) by specifying pivotX and pivotY. " + + "For example, if these values are 0, 0 (top-left corner), all growth " + + "will be down and to the right.", + sdkUrl, + xmlns, null, true /*mandatory*/); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "rotate", "Rotate", "RotateAnimation", "Animation", //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-4$ + "A rotation animation.", + sdkUrl, + xmlns, null, true /*mandatory*/); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "translate", "Translate", "TranslateAnimation", "Animation", //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-4$ + "A vertical and/or horizontal motion. Supports the following attributes in " + + "any of the following three formats: values from -100 to 100 ending " + + "with \"%\", indicating a percentage relative to itself; values from " + + "-100 to 100 ending in \"%p\", indicating a percentage relative to its " + + "parent; a float value with no suffix, indicating an absolute value.", + sdkUrl, + xmlns, null, true /*mandatory*/); + + mRootDescriptors = descriptors.toArray(new ElementDescriptor[descriptors.size()]); + + // Allow <set> to nest the others (and other sets) + if (set != null) { + set.setChildren(mRootDescriptors); + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java new file mode 100644 index 000000000..ee0c290c7 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2007 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.animator; + +import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME_PREFIX; +import static com.android.ide.eclipse.adt.AdtConstants.ANDROID_PKG; + +import com.android.annotations.VisibleForTesting; +import com.android.ide.common.api.IAttributeInfo.Format; +import com.android.ide.common.resources.ResourceItem; +import com.android.ide.common.resources.ResourceRepository; +import com.android.ide.eclipse.adt.internal.editors.AndroidContentAssist; +import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider; +import com.android.ide.eclipse.adt.internal.editors.descriptors.SeparatorAttributeDescriptor; +import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; +import com.android.resources.ResourceFolderType; +import com.android.resources.ResourceType; +import com.android.util.Pair; + +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.w3c.dom.Node; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Content Assist Processor for /res/drawable XML files + */ +@VisibleForTesting +public final class AnimationContentAssist extends AndroidContentAssist { + private static final String OBJECT_ANIMATOR = "objectAnimator"; //$NON-NLS-1$ + private static final String PROPERTY_NAME = "propertyName"; //$NON-NLS-1$ + private static final String INTERPOLATOR_PROPERTY_NAME = "interpolator"; //$NON-NLS-1$ + private static final String INTERPOLATOR_NAME_SUFFIX = "_interpolator"; //$NON-NLS-1$ + + public AnimationContentAssist() { + super(AndroidTargetData.DESCRIPTOR_ANIMATOR); + } + + @Override + protected int getRootDescriptorId() { + String folderName = mEditor.getInputFile().getParent().getName(); + ResourceFolderType folderType = ResourceFolderType.getFolderType(folderName); + if (folderType == ResourceFolderType.ANIM) { + return AndroidTargetData.DESCRIPTOR_ANIM; + } else { + return AndroidTargetData.DESCRIPTOR_ANIMATOR; + } + } + + @Override + protected void computeAttributeValues(List<ICompletionProposal> proposals, int offset, + String parentTagName, String attributeName, Node node, String wordPrefix, + boolean skipEndTag, int replaceLength) { + + // Add value completion for the interpolator and propertyName attributes + + if (attributeName.endsWith(INTERPOLATOR_PROPERTY_NAME)) { + if (!wordPrefix.startsWith("@android:anim/")) { //$NON-NLS-1$ + // List all framework interpolators with full path first + AndroidTargetData data = mEditor.getTargetData(); + ResourceRepository repository = data.getFrameworkResources(); + List<String> interpolators = new ArrayList<String>(); + String base = '@' + ANDROID_PKG + ':' + ResourceType.ANIM.getName() + '/'; + for (ResourceItem item : repository.getResourceItemsOfType(ResourceType.ANIM)) { + String name = item.getName(); + if (name.endsWith(INTERPOLATOR_NAME_SUFFIX)) { + interpolators.add(base + item.getName()); + } + } + addMatchingProposals(proposals, interpolators.toArray(), offset, node, wordPrefix, + (char) 0 /* needTag */, true /* isAttribute */, false /* isNew */, + skipEndTag /* skipEndTag */, replaceLength); + } + + + super.computeAttributeValues(proposals, offset, parentTagName, attributeName, node, + wordPrefix, skipEndTag, replaceLength); + } else if (parentTagName.equals(OBJECT_ANIMATOR) + && attributeName.endsWith(PROPERTY_NAME)) { + + // Special case: the user is code completing inside + // <objectAnimator propertyName="^"> + // In this case, offer ALL attribute names that make sense for animation + // (e.g. all numeric ones) + + String attributePrefix = wordPrefix; + if (startsWith(attributePrefix, ANDROID_NS_NAME_PREFIX)) { + attributePrefix = attributePrefix.substring(ANDROID_NS_NAME_PREFIX.length()); + } + + AndroidTargetData data = mEditor.getTargetData(); + if (data != null) { + IDescriptorProvider descriptorProvider = + data.getDescriptorProvider(AndroidTargetData.DESCRIPTOR_LAYOUT); + if (descriptorProvider != null) { + ElementDescriptor[] rootElementDescriptors = + descriptorProvider.getRootElementDescriptors(); + Map<String, AttributeDescriptor> matches = + new HashMap<String, AttributeDescriptor>(180); + for (ElementDescriptor elementDesc : rootElementDescriptors) { + for (AttributeDescriptor desc : elementDesc.getAttributes()) { + if (desc instanceof SeparatorAttributeDescriptor) { + continue; + } + String name = desc.getXmlLocalName(); + if (startsWith(name, attributePrefix)) { + for (Format f : desc.getAttributeInfo().getFormats()) { + if (f == Format.INTEGER || f == Format.FLOAT) { + // TODO: Filter out some common properties + // that the user probably isn't trying to + // animate: + // num*, min*, max*, *Index, *Threshold, + // *Duration, *Id, *Limit + + matches.put(name, desc); + break; + } + } + } + } + } + + List<AttributeDescriptor> sorted = + new ArrayList<AttributeDescriptor>(matches.size()); + sorted.addAll(matches.values()); + Collections.sort(sorted); + // Extract just the name+description pairs, since we don't want to + // use the full attribute descriptor (which forces the namespace + // prefix to be included) + List<Pair<String, String>> pairs = + new ArrayList<Pair<String, String>>(sorted.size()); + for (AttributeDescriptor d : sorted) { + pairs.add(Pair.of(d.getXmlLocalName(), d.getAttributeInfo().getJavaDoc())); + } + + addMatchingProposals(proposals, pairs.toArray(), offset, node, wordPrefix, + (char) 0 /* needTag */, true /* isAttribute */, false /* isNew */, + skipEndTag /* skipEndTag */, replaceLength); + return; + } + } + } else { + super.computeAttributeValues(proposals, offset, parentTagName, attributeName, node, + wordPrefix, skipEndTag, replaceLength); + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationEditor.java new file mode 100644 index 000000000..9f6123898 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationEditor.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2007 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.animator; + +import static com.android.ide.eclipse.adt.AdtConstants.EDITORS_NAMESPACE; + +import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; +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.uimodel.UiElementNode; +import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; +import com.android.resources.ResourceFolderType; + +import org.eclipse.core.resources.IFile; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * Editor for /res/animator XML files. + */ +@SuppressWarnings("restriction") +public class AnimationEditor extends AndroidXmlEditor { + public static final String ID = EDITORS_NAMESPACE + ".animator.AnimationEditor"; //$NON-NLS-1$ + + /** Root node of the UI element hierarchy */ + private UiElementNode mUiRootNode; + /** The tag used at the root */ + private String mRootTag; + + public AnimationEditor() { + super(); + } + + @Override + public UiElementNode getUiRootNode() { + return mUiRootNode; + } + + @Override + public boolean isSaveAsAllowed() { + return true; + } + + @Override + protected void createFormPages() { + /* Disabled for now; doesn't work quite right + try { + addPage(new AnimatorTreePage(this)); + } catch (PartInitException e) { + AdtPlugin.log(IStatus.ERROR, "Error creating nested page"); //$NON-NLS-1$ + AdtPlugin.getDefault().getLog().log(e.getStatus()); + } + */ + } + + /* (non-java doc) + * Change the tab/title name to include the project name. + */ + @Override + protected void setInput(IEditorInput input) { + super.setInput(input); + if (input instanceof FileEditorInput) { + FileEditorInput fileInput = (FileEditorInput) input; + IFile file = fileInput.getFile(); + setPartName(String.format("%1$s", + file.getName())); + } + } + + /** + * Processes the new XML Model. + * + * @param xmlDoc The XML document, if available, or null if none exists. + */ + @Override + protected void xmlModelChanged(Document xmlDoc) { + Element rootElement = xmlDoc.getDocumentElement(); + if (rootElement != null) { + mRootTag = rootElement.getTagName(); + } + + // create the ui root node on demand. + initUiRootNode(false /*force*/); + + if (mRootTag != null + && !mRootTag.equals(mUiRootNode.getDescriptor().getXmlLocalName())) { + AndroidTargetData data = getTargetData(); + if (data != null) { + ElementDescriptor descriptor; + if (getFolderType() == ResourceFolderType.ANIM) { + descriptor = data.getAnimDescriptors().getElementDescriptor(mRootTag); + } else { + descriptor = data.getAnimatorDescriptors().getElementDescriptor(mRootTag); + } + // Replace top level node now that we know the actual type + + // Disconnect from old + mUiRootNode.setEditor(null); + mUiRootNode.setXmlDocument(null); + + // Create new + mUiRootNode = descriptor.createUiNode(); + mUiRootNode.setXmlDocument(xmlDoc); + mUiRootNode.setEditor(this); + } + } + + if (mUiRootNode.getDescriptor() instanceof DocumentDescriptor) { + mUiRootNode.loadFromXmlNode(xmlDoc); + } else { + mUiRootNode.loadFromXmlNode(rootElement); + } + + super.xmlModelChanged(xmlDoc); + } + + @Override + protected void initUiRootNode(boolean force) { + // The manifest UI node is always created, even if there's no corresponding XML node. + if (mUiRootNode == null || force) { + ElementDescriptor descriptor; + boolean reload = false; + AndroidTargetData data = getTargetData(); + if (data == null) { + descriptor = new DocumentDescriptor("temp", null /*children*/); + } else { + if (getFolderType() == ResourceFolderType.ANIM) { + descriptor = data.getAnimDescriptors().getElementDescriptor(mRootTag); + } else { + descriptor = data.getAnimatorDescriptors().getElementDescriptor(mRootTag); + } + reload = true; + } + mUiRootNode = descriptor.createUiNode(); + mUiRootNode.setEditor(this); + + if (reload) { + onDescriptorsChanged(); + } + } + } + + private ResourceFolderType getFolderType() { + IFile inputFile = getInputFile(); + if (inputFile != null) { + String folderName = inputFile.getParent().getName(); + return ResourceFolderType.getFolderType(folderName); + } + return ResourceFolderType.ANIMATOR; + } + + private void onDescriptorsChanged() { + IStructuredModel model = getModelForRead(); + if (model != null) { + try { + Node node = getXmlDocument(model).getDocumentElement(); + mUiRootNode.reloadFromXmlNode(node); + } finally { + model.releaseFromRead(); + } + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationSourceViewerConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationSourceViewerConfig.java new file mode 100644 index 000000000..87a145bc7 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationSourceViewerConfig.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2007 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.animator; + + +import com.android.ide.eclipse.adt.internal.editors.AndroidSourceViewerConfig; + +/** + * Source Viewer Configuration for animation files. + */ +public class AnimationSourceViewerConfig extends AndroidSourceViewerConfig { + + public AnimationSourceViewerConfig() { + super(new AnimationContentAssist()); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimatorDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimatorDescriptors.java new file mode 100644 index 000000000..644aebb64 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimatorDescriptors.java @@ -0,0 +1,182 @@ +/* + * 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.animator; + +import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME; + +import com.android.ide.common.resources.platform.DeclareStyleableInfo; +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.editors.descriptors.ElementDescriptor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider; +import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor; +import com.android.sdklib.SdkConstants; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Descriptors for /res/animator XML files. + */ +public class AnimatorDescriptors implements IDescriptorProvider { + /** The root element descriptor */ + private ElementDescriptor mDescriptor; + /** The root element descriptors */ + private ElementDescriptor[] mRootDescriptors; + private Map<String, ElementDescriptor> nameToDescriptor; + + /** @return the root descriptor. */ + public ElementDescriptor getDescriptor() { + if (mDescriptor == null) { + mDescriptor = new ElementDescriptor("", getRootElementDescriptors()); //$NON-NLS-1$ + } + + return mDescriptor; + } + + public ElementDescriptor[] getRootElementDescriptors() { + return mRootDescriptors; + } + + public ElementDescriptor getElementDescriptor(String mRootTag) { + if (nameToDescriptor == null) { + nameToDescriptor = new HashMap<String, ElementDescriptor>(); + for (ElementDescriptor descriptor : getRootElementDescriptors()) { + nameToDescriptor.put(descriptor.getXmlName(), descriptor); + } + } + + ElementDescriptor descriptor = nameToDescriptor.get(mRootTag); + if (descriptor == null) { + descriptor = getDescriptor(); + } + return descriptor; + } + + public synchronized void updateDescriptors(Map<String, DeclareStyleableInfo> styleMap) { + if (styleMap == null) { + return; + } + + XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(ANDROID_NS_NAME, + SdkConstants.NS_RESOURCES); + + List<ElementDescriptor> descriptors = new ArrayList<ElementDescriptor>(); + + String sdkUrl = + "http://developer.android.com/guide/topics/graphics/animation.html"; //$NON-NLS-1$ + + ElementDescriptor set = addElement(descriptors, styleMap, + "set", "Animator Set", "AnimatorSet", null, //$NON-NLS-1$ //$NON-NLS-3$ + null /* tooltip */, sdkUrl, + xmlns, null, true /*mandatory*/); + + ElementDescriptor objectAnimator = addElement(descriptors, styleMap, + "objectAnimator", "Object Animator", //$NON-NLS-1$ + "PropertyAnimator", "Animator", //$NON-NLS-1$ //$NON-NLS-2$ + null /* tooltip */, sdkUrl, + xmlns, null, true /*mandatory*/); + + ElementDescriptor animator = addElement(descriptors, styleMap, + "animator", "Animator", "Animator", null, //$NON-NLS-1$ //$NON-NLS-3$ + null /* tooltip */, sdkUrl, + xmlns, null, true /*mandatory*/); + + mRootDescriptors = descriptors.toArray(new ElementDescriptor[descriptors.size()]); + + // Allow arbitrary nesting: the children of all of these element can include + // any of the others + if (objectAnimator != null) { + objectAnimator.setChildren(mRootDescriptors); + } + if (animator != null) { + animator.setChildren(mRootDescriptors); + } + if (set != null) { + set.setChildren(mRootDescriptors); + } + } + + /** + * Looks up the given style, and if found creates a new {@link ElementDescriptor} + * corresponding to the style. It can optionally take an extra style to merge in + * additional attributes from, and an extra attribute to add in as well. The new + * element, if it exists, can also be optionally added into a list. + * + * @param descriptors an optional list to add the element into, or null + * @param styleMap The map style => attributes from the attrs.xml file + * @param xmlName the XML tag name to use for the element + * @param uiName the UI name to display the element as + * @param styleName the name of the style which must exist for this style + * @param extraStyle an optional extra style to merge in attributes from, or null + * @param tooltip the tooltip or documentation for this element, or null + * @param sdkUrl an optional SDK url to display for the element, or null + * @param extraAttribute an extra attribute to add to the attributes list, or null + * @param childrenElements an array of children allowed by this element, or null + * @param mandatory if true, this element is mandatory + * @return a newly created element, or null if the style does not exist + */ + public static ElementDescriptor addElement( + List<ElementDescriptor> descriptors, + Map<String, DeclareStyleableInfo> styleMap, + String xmlName, String uiName, String styleName, String extraStyle, + String tooltip, String sdkUrl, + AttributeDescriptor extraAttribute, + ElementDescriptor[] childrenElements, + boolean mandatory) { + DeclareStyleableInfo style = styleMap.get(styleName); + if (style == null) { + return null; + } + ElementDescriptor element = new ElementDescriptor(xmlName, uiName, tooltip, sdkUrl, + null, childrenElements, mandatory); + + ArrayList<AttributeDescriptor> descs = new ArrayList<AttributeDescriptor>(); + + DescriptorsUtils.appendAttributes(descs, + null, // elementName + SdkConstants.NS_RESOURCES, + style.getAttributes(), + null, // requiredAttributes + null); // overrides + element.setTooltip(style.getJavaDoc()); + + if (extraStyle != null) { + style = styleMap.get(extraStyle); + if (style != null) { + DescriptorsUtils.appendAttributes(descs, + null, // elementName + SdkConstants.NS_RESOURCES, + style.getAttributes(), + null, // requiredAttributes + null); // overrides + } + } + + if (extraAttribute != null) { + descs.add(extraAttribute); + } + + element.setAttributes(descs.toArray(new AttributeDescriptor[descs.size()])); + if (descriptors != null) { + descriptors.add(element); + } + + return element; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorContentAssist.java new file mode 100644 index 000000000..15704393e --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorContentAssist.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2007 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.color; + +import com.android.annotations.VisibleForTesting; +import com.android.ide.eclipse.adt.internal.editors.AndroidContentAssist; +import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; + +/** + * Content Assist Processor for /res/color XML files + */ +@VisibleForTesting +public final class ColorContentAssist extends AndroidContentAssist { + public ColorContentAssist() { + super(AndroidTargetData.DESCRIPTOR_COLOR); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorDescriptors.java new file mode 100644 index 000000000..f6e50a8ea --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorDescriptors.java @@ -0,0 +1,94 @@ +/* + * 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.color; + +import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME; +import static com.android.sdklib.SdkConstants.NS_RESOURCES; + +import com.android.ide.common.api.IAttributeInfo.Format; +import com.android.ide.common.resources.platform.AttributeInfo; +import com.android.ide.common.resources.platform.DeclareStyleableInfo; +import com.android.ide.eclipse.adt.internal.editors.animator.AnimatorDescriptors; +import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider; +import com.android.ide.eclipse.adt.internal.editors.descriptors.ReferenceAttributeDescriptor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor; +import com.android.resources.ResourceType; +import com.android.sdklib.SdkConstants; + +import java.util.Map; + +/** Descriptors for /res/color XML files */ +public class ColorDescriptors implements IDescriptorProvider { + private static final String SDK_URL = + "http://d.android.com/guide/topics/resources/color-list-resource.html"; //$NON-NLS-1$ + + /** The root element descriptor */ + private ElementDescriptor mDescriptor = new ElementDescriptor( + "selector", "Selector", + "Required. This must be the root element. Contains one or more <item> elements.", + SDK_URL, + new AttributeDescriptor[] { new XmlnsAttributeDescriptor(ANDROID_NS_NAME, + NS_RESOURCES) }, + null /*children: added later*/, true /*mandatory*/); + + /** @return the root descriptor. */ + public ElementDescriptor getDescriptor() { + if (mDescriptor == null) { + mDescriptor = new ElementDescriptor("", getRootElementDescriptors()); //$NON-NLS-1$ + } + + return mDescriptor; + } + + public ElementDescriptor[] getRootElementDescriptors() { + return new ElementDescriptor[] { mDescriptor }; + } + + public synchronized void updateDescriptors(Map<String, DeclareStyleableInfo> styleMap) { + if (styleMap == null) { + return; + } + + // Selector children + ElementDescriptor selectorItem = AnimatorDescriptors.addElement(null, styleMap, + "item", "Item", "DrawableStates", null, //$NON-NLS-1$ //$NON-NLS-3$ + "Defines a drawable to use during certain states, as described by " + + "its attributes. Must be a child of a <selector> element.", + SDK_URL, + new ReferenceAttributeDescriptor( + ResourceType.COLOR, "color", "color", //$NON-NLS-1$ //$NON-NLS-2$ + SdkConstants.NS_RESOURCES, + "Hexadeximal color. Required. The color is specified with an RGB value and " + + "optional alpha channel.\n" + + "The value always begins with a pound (#) character and then " + + "followed by the Alpha-Red-Green-Blue information in one of " + + "the following formats:\n" + + "* RGB\n" + + "* ARGB\n" + + "* RRGGBB\n" + + "* AARRGGBB", + new AttributeInfo("drawable", new Format[] { Format.COLOR })), + null, /* This is wrong -- we can now embed any above drawable + (but without xmlns as extra) */ + false /*mandatory*/); + + if (selectorItem != null) { + mDescriptor.setChildren(new ElementDescriptor[] { selectorItem }); + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorEditor.java new file mode 100644 index 000000000..b0e33271e --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorEditor.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2007 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.color; + +import static com.android.ide.eclipse.adt.AdtConstants.EDITORS_NAMESPACE; + +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.uimodel.UiElementNode; +import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; + +import org.eclipse.core.resources.IFile; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * Editor for /res/color XML files. + */ +@SuppressWarnings("restriction") +public class ColorEditor extends AndroidXmlEditor { + public static final String ID = EDITORS_NAMESPACE + ".color.ColorEditor"; //$NON-NLS-1$ + + /** Root node of the UI element hierarchy */ + private UiElementNode mUiRootNode; + + public ColorEditor() { + super(); + } + + @Override + public UiElementNode getUiRootNode() { + return mUiRootNode; + } + + @Override + public boolean isSaveAsAllowed() { + return true; + } + + @Override + protected void createFormPages() { + /* Disabled for now; doesn't work quite right + try { + addPage(new ColorTreePage(this)); + } catch (PartInitException e) { + AdtPlugin.log(IStatus.ERROR, "Error creating nested page"); //$NON-NLS-1$ + AdtPlugin.getDefault().getLog().log(e.getStatus()); + } + */ + } + + /* (non-java doc) + * Change the tab/title name to include the project name. + */ + @Override + protected void setInput(IEditorInput input) { + super.setInput(input); + if (input instanceof FileEditorInput) { + FileEditorInput fileInput = (FileEditorInput) input; + IFile file = fileInput.getFile(); + setPartName(String.format("%1$s", + file.getName())); + } + } + + @Override + protected void xmlModelChanged(Document xmlDoc) { + // create the ui root node on demand. + initUiRootNode(false /*force*/); + + Element rootElement = xmlDoc.getDocumentElement(); + mUiRootNode.loadFromXmlNode(rootElement); + + super.xmlModelChanged(xmlDoc); + } + + @Override + protected void initUiRootNode(boolean force) { + // The manifest UI node is always created, even if there's no corresponding XML node. + if (mUiRootNode == null || force) { + ElementDescriptor descriptor; + AndroidTargetData data = getTargetData(); + if (data == null) { + descriptor = new ColorDescriptors().getDescriptor(); + } else { + descriptor = data.getColorDescriptors().getDescriptor(); + } + mUiRootNode = descriptor.createUiNode(); + mUiRootNode.setEditor(this); + onDescriptorsChanged(); + } + } + + private void onDescriptorsChanged() { + IStructuredModel model = getModelForRead(); + if (model != null) { + try { + Node node = getXmlDocument(model).getDocumentElement(); + mUiRootNode.reloadFromXmlNode(node); + } finally { + model.releaseFromRead(); + } + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorSourceViewerConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorSourceViewerConfig.java new file mode 100644 index 000000000..4f12ce571 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorSourceViewerConfig.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2007 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.color; + + +import com.android.ide.eclipse.adt.internal.editors.AndroidSourceViewerConfig; + +/** + * Source Viewer Configuration that calls in ColorContentAssist. + */ +public class ColorSourceViewerConfig extends AndroidSourceViewerConfig { + + public ColorSourceViewerConfig() { + super(new ColorContentAssist()); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/BooleanAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/BooleanAttributeDescriptor.java index d0806c583..f1def3977 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/BooleanAttributeDescriptor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/BooleanAttributeDescriptor.java @@ -24,11 +24,11 @@ import com.android.ide.eclipse.adt.internal.editors.uimodel.UiListAttributeNode; * It is displayed by a {@link UiListAttributeNode}. */ public class BooleanAttributeDescriptor extends ListAttributeDescriptor { + private static final String[] VALUES = new String[] { "true", "false" }; //$NON-NLS-1$ //$NON-NLS-2$ public BooleanAttributeDescriptor(String xmlLocalName, String uiName, String nsUri, String tooltip, IAttributeInfo attrInfo) { - super(xmlLocalName, uiName, nsUri, tooltip, attrInfo, - new String[] { "true", "false" }); //$NON-NLS-1$ //$NON-NLS-2$ + super(xmlLocalName, uiName, nsUri, tooltip, attrInfo, VALUES); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableContentAssist.java new file mode 100644 index 000000000..b0bea511d --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableContentAssist.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2007 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.drawable; + +import com.android.annotations.VisibleForTesting; +import com.android.ide.eclipse.adt.internal.editors.AndroidContentAssist; +import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; + +/** + * Content Assist Processor for /res/drawable XML files + */ +@VisibleForTesting +public final class DrawableContentAssist extends AndroidContentAssist { + public DrawableContentAssist() { + super(AndroidTargetData.DESCRIPTOR_DRAWABLE); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableDescriptors.java new file mode 100644 index 000000000..1e71795c4 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableDescriptors.java @@ -0,0 +1,300 @@ +/* + * 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.drawable; + +import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME; + +import com.android.ide.common.api.IAttributeInfo.Format; +import com.android.ide.common.resources.platform.AttributeInfo; +import com.android.ide.common.resources.platform.DeclareStyleableInfo; +import com.android.ide.eclipse.adt.internal.editors.animator.AnimatorDescriptors; +import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider; +import com.android.ide.eclipse.adt.internal.editors.descriptors.ReferenceAttributeDescriptor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor; +import com.android.resources.ResourceType; +import com.android.sdklib.SdkConstants; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Descriptors for /res/drawable files + */ +public class DrawableDescriptors implements IDescriptorProvider { + private static final String SDK_URL_BASE = + "http://d.android.com/guide/topics/resources/"; //$NON-NLS-1$ + + /** The root element descriptor */ + private ElementDescriptor mDescriptor; + /** The root element descriptors */ + private ElementDescriptor[] mRootDescriptors; + private Map<String, ElementDescriptor> nameToDescriptor; + + /** @return the root descriptor. */ + public ElementDescriptor getDescriptor() { + if (mDescriptor == null) { + mDescriptor = new ElementDescriptor("", getRootElementDescriptors()); //$NON-NLS-1$ + } + + return mDescriptor; + } + + public ElementDescriptor[] getRootElementDescriptors() { + return mRootDescriptors; + } + + /** + * Returns a descriptor for the given root tag name + * + * @param tag the tag name to look up a descriptor for + * @return a descriptor with the given tag name + */ + public ElementDescriptor getElementDescriptor(String tag) { + if (nameToDescriptor == null) { + nameToDescriptor = new HashMap<String, ElementDescriptor>(); + for (ElementDescriptor descriptor : getRootElementDescriptors()) { + nameToDescriptor.put(descriptor.getXmlName(), descriptor); + } + } + + ElementDescriptor descriptor = nameToDescriptor.get(tag); + if (descriptor == null) { + descriptor = getDescriptor(); + } + return descriptor; + } + + public synchronized void updateDescriptors(Map<String, DeclareStyleableInfo> styleMap) { + XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(ANDROID_NS_NAME, + SdkConstants.NS_RESOURCES); + Format[] referenceFormat = new Format[] { Format.REFERENCE }; + + List<ElementDescriptor> descriptors = new ArrayList<ElementDescriptor>(); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "animation-list", "Animation List", "AnimationDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ + "An animation defined in XML that shows a sequence of images in " + + "order (like a film)", + SDK_URL_BASE + "animation-resource.html#Frame", + xmlns, null, true /*mandatory*/); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "animated-rotate", "Animated Rotate", "AnimatedRotateDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ + // Need docs + null /* tooltip */, + null /* sdk_url */, + xmlns, null, true /*mandatory*/); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "bitmap", "BitMap", "BitmapDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ + "An XML bitmap is a resource defined in XML that points to a bitmap file. " + + "The effect is an alias for a raw bitmap file. The XML can " + + "specify additional properties for the bitmap such as " + + "dithering and tiling.", + SDK_URL_BASE + "drawable-resource.html#Bitmap", //$NON-NLS-1$ + xmlns, null, true /* mandatory */); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "clip", "Clip", "ClipDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ + "An XML file that defines a drawable that clips another Drawable based on " + + "this Drawable's current level value.", + SDK_URL_BASE + "drawable-resource.html#Clip", //$NON-NLS-1$ + xmlns, null, true /*mandatory*/); + + + AnimatorDescriptors.addElement(descriptors, styleMap, + "color", "Color", "ColorDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ + "XML resource that carries a color value (a hexadecimal color)", + SDK_URL_BASE + "more-resources.html#Color", + xmlns, null, true /*mandatory*/); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "inset", "Inset", "InsetDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ + "An XML file that defines a drawable that insets another drawable by a " + + "specified distance. This is useful when a View needs a background " + + "drawble that is smaller than the View's actual bounds.", + SDK_URL_BASE + "drawable-resource.html#Inset", //$NON-NLS-1$ + xmlns, null, true /*mandatory*/); + + // Layer list + + // An <item> in a <selector> or < + ElementDescriptor layerItem = AnimatorDescriptors.addElement(null, styleMap, + "item", "Item", "LayerDrawableItem", null, //$NON-NLS-1$ //$NON-NLS-3$ + "Defines a drawable to place in the layer drawable, in a position " + + "defined by its attributes. Must be a child of a <selector> " + + "element. Accepts child <bitmap> elements.", + SDK_URL_BASE + "drawable-resource.html#LayerList", //$NON-NLS-1$ + null, /* extra attribute */ + null, /* This is wrong -- we can now embed any above drawable + (but without xmlns as extra) */ + false /*mandatory*/); + ElementDescriptor[] layerChildren = layerItem != null + ? new ElementDescriptor[] { layerItem } : null; + + AnimatorDescriptors.addElement(descriptors, styleMap, + "layer-list", "Layer List", "LayerDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ + "A Drawable that manages an array of other Drawables. These are drawn in " + + "array order, so the element with the largest index is be drawn on top.", + SDK_URL_BASE + "drawable-resource.html#LayerList", //$NON-NLS-1$ + xmlns, + layerChildren, + true /*mandatory*/); + + // Level list children + ElementDescriptor levelListItem = AnimatorDescriptors.addElement(null, styleMap, + "item", "Item", "LevelListDrawableItem", null, //$NON-NLS-1$ //$NON-NLS-3$ + "Defines a drawable to use at a certain level.", + SDK_URL_BASE + "drawable-resource.html#LevelList", //$NON-NLS-1$ + null, /* extra attribute */ + null, /* no further children */ + // TODO: The inflation code seems to show that all drawables can be nested here! + false /*mandatory*/); + AnimatorDescriptors.addElement(descriptors, styleMap, + "level-list", "Level List", "LevelListDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ + "An XML file that defines a drawable that manages a number of alternate " + + "Drawables, each assigned a maximum numerical value", + SDK_URL_BASE + "drawable-resource.html#LevelList", //$NON-NLS-1$ + xmlns, + levelListItem != null ? new ElementDescriptor[] { levelListItem } : null, + true /*mandatory*/); + + // Not yet supported + //addElement(descriptors, styleMap, "mipmap", "Mipmap", "MipmapDrawable", null, + // null /* tooltip */, + // null /* sdk_url */, + // xmlns, null, true /*mandatory*/); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "nine-patch", "Nine Patch", "NinePatchDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ + "A PNG file with stretchable regions to allow image resizing " + + "based on content (.9.png).", + SDK_URL_BASE + "drawable-resource.html#NinePatch", //$NON-NLS-1$ + xmlns, null, true /*mandatory*/); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "rotate", "Rotate", "RotateDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ + // Need docs + null /* tooltip */, + null /* sdk_url */, + xmlns, null, true /*mandatory*/); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "scale", "Shape", "ScaleDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ + "An XML file that defines a drawable that changes the size of another Drawable " + + "based on its current level value.", + SDK_URL_BASE + "drawable-resource.html#Scale", //$NON-NLS-1$ + xmlns, null, true /*mandatory*/); + + // Selector children + ElementDescriptor selectorItem = AnimatorDescriptors.addElement(null, styleMap, + "item", "Item", "DrawableStates", null, //$NON-NLS-1$ //$NON-NLS-3$ + "Defines a drawable to use during certain states, as described by " + + "its attributes. Must be a child of a <selector> element.", + SDK_URL_BASE + "drawable-resource.html#StateList", //$NON-NLS-1$ + new ReferenceAttributeDescriptor( + ResourceType.DRAWABLE, "drawable", "drawable", //$NON-NLS-1$ //$NON-NLS-2$ + SdkConstants.NS_RESOURCES, + "Reference to a drawable resource.", + new AttributeInfo("drawable", referenceFormat)), + null, /* This is wrong -- we can now embed any above drawable + (but without xmlns as extra) */ + false /*mandatory*/); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "selector", "Selector", "StateListDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ + "An XML file that references different bitmap graphics for different states " + + "(for example, to use a different image when a button is pressed).", + SDK_URL_BASE + "drawable-resource.html#StateList", //$NON-NLS-1$ + xmlns, + selectorItem != null ? new ElementDescriptor[] { selectorItem } : null, + true /*mandatory*/); + + // Shape + // Shape children + List<ElementDescriptor> shapeChildren = new ArrayList<ElementDescriptor>(); + // Selector children + AnimatorDescriptors.addElement(shapeChildren, styleMap, + "size", "Size", "GradientDrawableSize", null, //$NON-NLS-1$ //$NON-NLS-3$ + null /* tooltip */, null /* sdk_url */, null /* extra attribute */, + null /* children */, false /* mandatory */); + AnimatorDescriptors.addElement(shapeChildren, styleMap, + "gradient", "Gradient", "GradientDrawableGradient", null, //$NON-NLS-1$ //$NON-NLS-3$ + null /* tooltip */, null /* sdk_url */, null /* extra attribute */, + null /* children */, false /* mandatory */); + AnimatorDescriptors.addElement(shapeChildren, styleMap, + "solid", "Solid", "GradientDrawableSolid", null, //$NON-NLS-1$ //$NON-NLS-3$ + null /* tooltip */, null /* sdk_url */, null /* extra attribute */, + null /* children */, false /* mandatory */); + AnimatorDescriptors.addElement(shapeChildren, styleMap, + "stroke", "Stroke", "GradientDrawableStroke", null, //$NON-NLS-1$ //$NON-NLS-3$ + null /* tooltip */, null /* sdk_url */, null /* extra attribute */, + null /* children */, false /* mandatory */); + AnimatorDescriptors.addElement(shapeChildren, styleMap, + "corners", "Corners", "DrawableCorners", null, //$NON-NLS-1$ //$NON-NLS-3$ + null /* tooltip */, null /* sdk_url */, null /* extra attribute */, + null /* children */, false /* mandatory */); + AnimatorDescriptors.addElement(shapeChildren, styleMap, + "padding", "Padding", "GradientDrawablePadding", null, //$NON-NLS-1$ //$NON-NLS-3$ + null /* tooltip */, null /* sdk_url */, null /* extra attribute */, + null /* children */, false /* mandatory */); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "shape", "Shape", //$NON-NLS-1$ + + // The documentation says that a <shape> element creates a ShapeDrawable, + // but ShapeDrawable isn't finished and the code currently creates + // a GradientDrawable. + //"ShapeDrawable", //$NON-NLS-1$ + "GradientDrawable", //$NON-NLS-1$ + + null, + "An XML file that defines a geometric shape, including colors and gradients.", + SDK_URL_BASE + "drawable-resource.html#Shape", //$NON-NLS-1$ + xmlns, + + // These are the GradientDrawable children, not the ShapeDrawable children + shapeChildren.toArray(new ElementDescriptor[shapeChildren.size()]), + true /*mandatory*/); + + AnimatorDescriptors.addElement(descriptors, styleMap, + "transition", "Transition", "TransitionDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ + "An XML file that defines a drawable that can cross-fade between two " + + "drawable resources. Each drawable is represented by an <item> " + + "element inside a single <transition> element. No more than two " + + "items are supported. To transition forward, call startTransition(). " + + "To transition backward, call reverseTransition().", + SDK_URL_BASE + "drawable-resource.html#Transition", //$NON-NLS-1$ + xmlns, + layerChildren, // children: a TransitionDrawable is a LayerDrawable + true /*mandatory*/); + + mRootDescriptors = descriptors.toArray(new ElementDescriptor[descriptors.size()]); + + // A <selector><item> can contain any of the top level drawables + if (selectorItem != null) { + selectorItem.setChildren(mRootDescriptors); + } + // Docs says it can accept <bitmap> but code comment suggests any is possible; + // test and either use this or just { bitmap } + if (layerItem != null) { + layerItem.setChildren(mRootDescriptors); + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableEditor.java new file mode 100644 index 000000000..aaaeb4b6d --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableEditor.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2007 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.drawable; + +import static com.android.ide.eclipse.adt.AdtConstants.EDITORS_NAMESPACE; + +import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; +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.uimodel.UiElementNode; +import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; + +import org.eclipse.core.resources.IFile; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * Editor for /res/drawable XML files. + */ +@SuppressWarnings("restriction") +public class DrawableEditor extends AndroidXmlEditor { + public static final String ID = EDITORS_NAMESPACE + ".drawable.DrawableEditor"; //$NON-NLS-1$ + + /** Root node of the UI element hierarchy */ + private UiElementNode mUiRootNode; + /** The tag used at the root */ + private String mRootTag; + + /** + * Creates the form editor for resources XML files. + */ + public DrawableEditor() { + super(); + } + + @Override + public UiElementNode getUiRootNode() { + return mUiRootNode; + } + + @Override + public boolean isSaveAsAllowed() { + return true; + } + + @Override + protected void createFormPages() { + /* Disabled for now; doesn't work quite right + try { + addPage(new DrawableTreePage(this)); + } catch (PartInitException e) { + AdtPlugin.log(IStatus.ERROR, "Error creating nested page"); //$NON-NLS-1$ + AdtPlugin.getDefault().getLog().log(e.getStatus()); + } + */ + } + + @Override + protected void setInput(IEditorInput input) { + super.setInput(input); + if (input instanceof FileEditorInput) { + FileEditorInput fileInput = (FileEditorInput) input; + IFile file = fileInput.getFile(); + setPartName(String.format("%1$s", + file.getName())); + } + } + + @Override + protected void xmlModelChanged(Document xmlDoc) { + Element rootElement = xmlDoc.getDocumentElement(); + if (rootElement != null) { + mRootTag = rootElement.getTagName(); + } + + initUiRootNode(false /*force*/); + + if (mRootTag != null + && !mRootTag.equals(mUiRootNode.getDescriptor().getXmlLocalName())) { + AndroidTargetData data = getTargetData(); + if (data != null) { + ElementDescriptor descriptor = + data.getDrawableDescriptors().getElementDescriptor(mRootTag); + // Replace top level node now that we know the actual type + + // Disconnect from old + mUiRootNode.setEditor(null); + mUiRootNode.setXmlDocument(null); + + // Create new + mUiRootNode = descriptor.createUiNode(); + mUiRootNode.setXmlDocument(xmlDoc); + mUiRootNode.setEditor(this); + } + } + + if (mUiRootNode.getDescriptor() instanceof DocumentDescriptor) { + mUiRootNode.loadFromXmlNode(xmlDoc); + } else { + mUiRootNode.loadFromXmlNode(rootElement); + } + + super.xmlModelChanged(xmlDoc); + } + + @Override + protected void initUiRootNode(boolean force) { + // The manifest UI node is always created, even if there's no corresponding XML node. + if (mUiRootNode == null || force) { + ElementDescriptor descriptor; + boolean reload = false; + AndroidTargetData data = getTargetData(); + if (data == null) { + descriptor = new DocumentDescriptor("temp", null /*children*/); + } else { + descriptor = data.getDrawableDescriptors().getElementDescriptor(mRootTag); + reload = true; + } + mUiRootNode = descriptor.createUiNode(); + mUiRootNode.setEditor(this); + + if (reload) { + onDescriptorsChanged(); + } + } + } + + private void onDescriptorsChanged() { + IStructuredModel model = getModelForRead(); + if (model != null) { + try { + Node node = getXmlDocument(model).getDocumentElement(); + mUiRootNode.reloadFromXmlNode(node); + } finally { + model.releaseFromRead(); + } + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableSourceViewerConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableSourceViewerConfig.java new file mode 100644 index 000000000..eef6a9e93 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableSourceViewerConfig.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2007 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.drawable; + + +import com.android.ide.eclipse.adt.internal.editors.AndroidSourceViewerConfig; + +/** + * Source Viewer Configuration for drawable files + */ +public class DrawableSourceViewerConfig extends AndroidSourceViewerConfig { + + public DrawableSourceViewerConfig() { + super(new DrawableContentAssist()); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java index d19c1e69a..38a5e6b19 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java @@ -16,8 +16,8 @@ package com.android.ide.eclipse.adt.internal.editors.manifest; -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.editors.AndroidXmlEditor; import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.AndroidManifestDescriptors; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/descriptors/AndroidManifestDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/descriptors/AndroidManifestDescriptors.java index 7bc36921c..c07b7be57 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/descriptors/AndroidManifestDescriptors.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/descriptors/AndroidManifestDescriptors.java @@ -434,7 +434,7 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider { * <p/> * Capitalizes the first letter and replace non-alphabet by a space followed by a capital. */ - private String getUiName(String xmlName) { + private static String getUiName(String xmlName) { StringBuilder sb = new StringBuilder(); boolean capitalize = true; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesContentAssist.java index 448c27024..166110085 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesContentAssist.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesContentAssist.java @@ -30,6 +30,7 @@ import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescrip 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.IDescriptorProvider; +import com.android.ide.eclipse.adt.internal.editors.descriptors.SeparatorAttributeDescriptor; import com.android.ide.eclipse.adt.internal.editors.uimodel.UiAttributeNode; import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; @@ -106,6 +107,9 @@ public class ResourcesContentAssist extends AndroidContentAssist { new HashMap<String, AttributeDescriptor>(180); for (ElementDescriptor elementDesc : rootElementDescriptors) { for (AttributeDescriptor desc : elementDesc.getAttributes()) { + if (desc instanceof SeparatorAttributeDescriptor) { + continue; + } String name = desc.getXmlLocalName(); if (startsWith(name, attributePrefix)) { matches.put(name, desc); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesEditor.java index 53ea51392..83e2d8c0d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesEditor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesEditor.java @@ -16,8 +16,8 @@ package com.android.ide.eclipse.adt.internal.editors.resources; -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.editors.AndroidXmlEditor; import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; import com.android.ide.eclipse.adt.internal.editors.resources.descriptors.ResourcesDescriptors; @@ -38,7 +38,7 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; /** - * Multi-page form editor for /res/values and /res/drawable XML files. + * Multi-page form editor for /res/values XML files. */ public class ResourcesEditor extends AndroidXmlEditor { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java index c94b6c1fb..2b7f3465c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java @@ -374,6 +374,8 @@ public class UiResourceAttributeNode extends UiTextAttributeNode { type = "style"; //$NON-NLS-1$ } else if (attribute.equals(LayoutDescriptors.ATTR_LAYOUT)) { type = "layout"; //$NON-NLS-1$ + } else if (attribute.equals("drawable")) { //$NON-NLS-1$ + type = "drawable"; //$NON-NLS-1$ } if (type != null) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java index 95e3f984a..69f1267b7 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java @@ -21,7 +21,11 @@ import com.android.ide.common.rendering.api.LayoutLog; import com.android.ide.common.resources.ResourceRepository; import com.android.ide.common.sdk.LoadStatus; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.editors.animator.AnimDescriptors; +import com.android.ide.eclipse.adt.internal.editors.animator.AnimatorDescriptors; +import com.android.ide.eclipse.adt.internal.editors.color.ColorDescriptors; import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider; +import com.android.ide.eclipse.adt.internal.editors.drawable.DrawableDescriptors; import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors; import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.AndroidManifestDescriptors; import com.android.ide.eclipse.adt.internal.editors.menu.descriptors.MenuDescriptors; @@ -51,6 +55,10 @@ public class AndroidTargetData { public final static int DESCRIPTOR_SEARCHABLE = 6; public final static int DESCRIPTOR_PREFERENCES = 7; public final static int DESCRIPTOR_APPWIDGET_PROVIDER = 8; + public final static int DESCRIPTOR_DRAWABLE = 9; + public final static int DESCRIPTOR_ANIMATOR = 10; + public final static int DESCRIPTOR_ANIM = 11; + public final static int DESCRIPTOR_COLOR = 12; private final IAndroidTarget mTarget; @@ -67,6 +75,10 @@ public class AndroidTargetData { private Hashtable<String, String[]> mAttributeValues = new Hashtable<String, String[]>(); private AndroidManifestDescriptors mManifestDescriptors; + private DrawableDescriptors mDrawableDescriptors; + private AnimatorDescriptors mAnimatorDescriptors; + private AnimDescriptors mAnimDescriptors; + private ColorDescriptors mColorDescriptors; private LayoutDescriptors mLayoutDescriptors; private MenuDescriptors mMenuDescriptors; private XmlDescriptors mXmlDescriptors; @@ -84,14 +96,16 @@ public class AndroidTargetData { /** * Creates an AndroidTargetData object. - * @param platformLibraries - * @param optionalLibraries */ void setExtraData( AndroidManifestDescriptors manifestDescriptors, LayoutDescriptors layoutDescriptors, MenuDescriptors menuDescriptors, XmlDescriptors xmlDescriptors, + DrawableDescriptors drawableDescriptors, + AnimatorDescriptors animatorDescriptors, + AnimDescriptors animDescriptors, + ColorDescriptors colorDescriptors, Map<String, Map<String, Integer>> enumValueMap, String[] permissionValues, String[] activityIntentActionValues, @@ -104,6 +118,10 @@ public class AndroidTargetData { LayoutLibrary layoutLibrary) { mManifestDescriptors = manifestDescriptors; + mDrawableDescriptors = drawableDescriptors; + mAnimatorDescriptors = animatorDescriptors; + mAnimDescriptors = animDescriptors; + mColorDescriptors = colorDescriptors; mLayoutDescriptors = layoutDescriptors; mMenuDescriptors = menuDescriptors; mXmlDescriptors = xmlDescriptors; @@ -142,6 +160,14 @@ public class AndroidTargetData { return mXmlDescriptors.getAppWidgetProvider(); case DESCRIPTOR_SEARCHABLE: return mXmlDescriptors.getSearchableProvider(); + case DESCRIPTOR_DRAWABLE: + return mDrawableDescriptors; + case DESCRIPTOR_ANIMATOR: + return mAnimatorDescriptors; + case DESCRIPTOR_ANIM: + return mAnimDescriptors; + case DESCRIPTOR_COLOR: + return mColorDescriptors; default : throw new IllegalArgumentException(); } @@ -155,6 +181,34 @@ public class AndroidTargetData { } /** + * Returns the drawable descriptors + */ + public DrawableDescriptors getDrawableDescriptors() { + return mDrawableDescriptors; + } + + /** + * Returns the animation descriptors + */ + public AnimDescriptors getAnimDescriptors() { + return mAnimDescriptors; + } + + /** + * Returns the color descriptors + */ + public ColorDescriptors getColorDescriptors() { + return mColorDescriptors; + } + + /** + * Returns the animator descriptors + */ + public AnimatorDescriptors getAnimatorDescriptors() { + return mAnimatorDescriptors; + } + + /** * Returns the layout Descriptors. */ public LayoutDescriptors getLayoutDescriptors() { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java index 19562e176..19b2e3d0a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java @@ -22,6 +22,10 @@ import com.android.ide.common.resources.platform.AttrsXmlParser; import com.android.ide.common.resources.platform.DeclareStyleableInfo; import com.android.ide.common.resources.platform.ViewClassInfo; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.editors.animator.AnimDescriptors; +import com.android.ide.eclipse.adt.internal.editors.animator.AnimatorDescriptors; +import com.android.ide.eclipse.adt.internal.editors.color.ColorDescriptors; +import com.android.ide.eclipse.adt.internal.editors.drawable.DrawableDescriptors; import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors; import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.AndroidManifestDescriptors; import com.android.ide.eclipse.adt.internal.editors.menu.descriptors.MenuDescriptors; @@ -83,7 +87,7 @@ public final class AndroidTargetParser { try { SubMonitor progress = SubMonitor.convert(monitor, String.format("Parsing SDK %1$s", mAndroidTarget.getName()), - 12); + 16); AndroidTargetData targetData = new AndroidTargetData(mAndroidTarget); @@ -218,6 +222,39 @@ public final class AndroidTargetParser { preferenceGroupsInfo); progress.worked(1); + if (progress.isCanceled()) { + return Status.CANCEL_STATUS; + } + + DrawableDescriptors drawableDescriptors = new DrawableDescriptors(); + Map<String, DeclareStyleableInfo> map = attrsXmlParser.getDeclareStyleableList(); + drawableDescriptors.updateDescriptors(map); + progress.worked(1); + + if (progress.isCanceled()) { + return Status.CANCEL_STATUS; + } + + AnimatorDescriptors animatorDescriptors = new AnimatorDescriptors(); + animatorDescriptors.updateDescriptors(map); + progress.worked(1); + + if (progress.isCanceled()) { + return Status.CANCEL_STATUS; + } + + AnimDescriptors animDescriptors = new AnimDescriptors(); + animDescriptors.updateDescriptors(map); + progress.worked(1); + + if (progress.isCanceled()) { + return Status.CANCEL_STATUS; + } + + ColorDescriptors colorDescriptors = new ColorDescriptors(); + colorDescriptors.updateDescriptors(map); + progress.worked(1); + // load the framework resources. ResourceRepository frameworkResources = ResourceManager.getInstance().loadFrameworkResources(mAndroidTarget); @@ -236,6 +273,10 @@ public final class AndroidTargetParser { layoutDescriptors, menuDescriptors, xmlDescriptors, + drawableDescriptors, + animatorDescriptors, + animDescriptors, + colorDescriptors, enumValueMap, permissionValues, activity_actions.toArray(new String[activity_actions.size()]), diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java index 583202ace..c4f86a657 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java @@ -27,6 +27,7 @@ import com.android.ide.common.resources.configuration.FolderConfiguration; import com.android.ide.common.resources.configuration.ResourceQualifier; import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; 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.IDescriptorProvider; @@ -72,6 +73,11 @@ import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.FileEditorInput; import java.util.ArrayList; import java.util.Collections; @@ -287,6 +293,15 @@ class NewXmlFileCreationPage extends WizardPage { null, // default attributes 1 // target API level ), + new TypeInfo("Drawable", // UI name + "An XML file that describes a drawable.", // tooltip + ResourceFolderType.DRAWABLE, // folder type + AndroidTargetData.DESCRIPTOR_DRAWABLE, // root seed + null, // default root + SdkConstants.NS_RESOURCES, // xmlns + null, // default attributes + 1 // target API level + ), new TypeInfo("Menu", // UI name "An XML file that describes an menu.", // tooltip ResourceFolderType.MENU, // folder type @@ -296,6 +311,33 @@ class NewXmlFileCreationPage extends WizardPage { null, // default attributes 1 // target API level ), + new TypeInfo("Color List", // UI name + "An XML file that describes a color state list.", // tooltip + ResourceFolderType.COLOR, // folder type + AndroidTargetData.DESCRIPTOR_COLOR, // root seed + null, // default root + SdkConstants.NS_RESOURCES, // xmlns + null, // default attributes + 1 // target API level + ), + new TypeInfo("Animator", // UI name + "An XML file that describes an animator.", // tooltip + ResourceFolderType.ANIMATOR, // folder type + AndroidTargetData.DESCRIPTOR_ANIMATOR, // root seed + "set", // default root + SdkConstants.NS_RESOURCES, // xmlns + null, // default attributes + 11 // target API level + ), + new TypeInfo("Animation", // UI name + "An XML file that describes an animation.", // tooltip + ResourceFolderType.ANIM, // folder type + AndroidTargetData.DESCRIPTOR_ANIM, // root seed + "set", // default root + null, // xmlns + null, // default attributes + 1 // target API level + ), new TypeInfo("AppWidget Provider", // UI name "An XML file that describes a widget provider.", // tooltip ResourceFolderType.XML, // folder type @@ -323,22 +365,6 @@ class NewXmlFileCreationPage extends WizardPage { null, // default attributes 1 // target API level ), - new TypeInfo("Animation", // UI name - "An XML file that describes an animation.", // tooltip - ResourceFolderType.ANIM, // folder type - // TODO reuse constants if we ever make an editor with descriptors for animations - new String[] { // root seed - "set", //$NON-NLS-1$ - "alpha", //$NON-NLS-1$ - "scale", //$NON-NLS-1$ - "translate", //$NON-NLS-1$ - "rotate" //$NON-NLS-1$ - }, - "set", //$NON-NLS-1$ // default root - null, // xmlns - null, // default attributes - 1 // target API level - ), }; /** Number of columns in the grid layout */ @@ -675,7 +701,7 @@ class NewXmlFileCreationPage extends WizardPage { }; int n = sTypes.length; - int num_lines = (n + NUM_COL/2) / NUM_COL; + int num_lines = (n + (NUM_COL - 1)) / NUM_COL; for (int line = 0, k = 0; line < num_lines; line++) { for (int i = 0; i < NUM_COL; i++, k++) { if (k < n) { @@ -837,6 +863,25 @@ class NewXmlFileCreationPage extends WizardPage { } if (targetProject == null) { + // Try to figure out the project from the active editor + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window != null) { + IWorkbenchPage page = window.getActivePage(); + if (page != null) { + IEditorPart activeEditor = page.getActiveEditor(); + if (activeEditor instanceof AndroidXmlEditor) { + Object input = ((AndroidXmlEditor) activeEditor).getEditorInput(); + if (input instanceof FileEditorInput) { + FileEditorInput fileInput = (FileEditorInput) input; + targetScore = 1; + targetProject = fileInput.getFile().getProject(); + } + } + } + } + } + + if (targetProject == null) { // If we didn't find a default project based on the selection, check how many // open Android projects we can find in the current workspace. If there's only // one, we'll just select it by default. @@ -1073,19 +1118,6 @@ class NewXmlFileCreationPage extends WizardPage { } } - // For now, treat a selection of /res/animator as /res/anim/, - // though we need to handle this better - // TODO: Properly support ANIMATOR templates! - if (!selected && folderName.equals(AndroidConstants.FD_RES_ANIMATOR)) { - for (TypeInfo type : sTypes) { - if (type.getResFolderType() == ResourceFolderType.ANIM) { - matches.add(type); - selected |= type.getWidget().getSelection(); - break; - } - } - } - if (matches.size() == 1) { // If there's only one match, select it if it's not already selected if (!selected) { |