diff options
Diffstat (limited to 'eclipse')
58 files changed, 2340 insertions, 57 deletions
diff --git a/eclipse/dictionary.txt b/eclipse/dictionary.txt index 3369ca1ad..9291f472f 100644 --- a/eclipse/dictionary.txt +++ b/eclipse/dictionary.txt @@ -17,6 +17,7 @@ app apps arg async +attr attrs avd avds @@ -64,8 +65,10 @@ dex dexified diff diffs +dir dirs ditto +docs dpi drawable drawables @@ -81,6 +84,7 @@ foreach fqcn framelayout gen +git groovy guava hardcoded @@ -101,6 +105,8 @@ inline instanceof instantiatable int +interpolator +interpolators iterable javac javadoc @@ -124,6 +130,7 @@ malformed marquee metadata min +mipmap monte ms msg @@ -148,6 +155,7 @@ precompiler pref prefs preload +preloaded preloads primordial printf @@ -156,12 +164,14 @@ programmatically proguard proxies proxy +quickfix recompilation rect redo refactor refactoring regexp +regexps registry reindent remap @@ -192,6 +202,8 @@ stderr stdout stretchiness struct +styleable +styleables subclassing submenu supertype diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml index 36d9c7125..a16a76650 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml +++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml @@ -533,6 +533,30 @@ name="Android Xml Resources Editor"> </editor> <editor + class="com.android.ide.eclipse.adt.internal.editors.animator.AnimationEditor" + default="false" + extensions="xml" + icon="icons/android_file.png" + id="com.android.ide.eclipse.editors.animator.AnimationEditor" + name="Android Animation Editor"> + </editor> + <editor + class="com.android.ide.eclipse.adt.internal.editors.drawable.DrawableEditor" + default="false" + extensions="xml" + icon="icons/android_file.png" + id="com.android.ide.eclipse.editors.drawable.DrawableEditor" + name="Android Drawable Editor"> + </editor> + <editor + class="com.android.ide.eclipse.adt.internal.editors.color.ColorEditor" + default="false" + extensions="xml" + icon="icons/android_file.png" + id="com.android.ide.eclipse.editors.color.ColorEditor" + name="Android Color Editor"> + </editor> + <editor class="com.android.ide.eclipse.adt.internal.editors.binaryxml.BinaryXMLMultiPageEditorPart" contributorClass="org.eclipse.wst.xml.ui.internal.tabletree.XMLMultiPageEditorActionBarContributor" icon="$nl$/icons/android_file.png" @@ -577,6 +601,18 @@ class="com.android.ide.eclipse.adt.internal.editors.xml.XmlSourceViewerConfig" target="com.android.ide.eclipse.editors.xml.XmlEditor"> </sourceViewerConfiguration> + <sourceViewerConfiguration + class="com.android.ide.eclipse.adt.internal.editors.animator.AnimationSourceViewerConfig" + target="com.android.ide.eclipse.editors.animator.AnimationEditor"> + </sourceViewerConfiguration> + <sourceViewerConfiguration + class="com.android.ide.eclipse.adt.internal.editors.drawable.DrawableSourceViewerConfig" + target="com.android.ide.eclipse.editors.drawable.DrawableEditor"> + </sourceViewerConfiguration> + <sourceViewerConfiguration + class="com.android.ide.eclipse.adt.internal.editors.color.ColorSourceViewerConfig" + target="com.android.ide.eclipse.editors.color.ColorEditor"> + </sourceViewerConfiguration> <provisionalConfiguration type="org.eclipse.jface.text.quickassist.IQuickAssistProcessor" class="com.android.ide.eclipse.adt.internal.build.AaptQuickFix" 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) { diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFixTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFixTest.java index 07c0fe1bc..78f16a21a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFixTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFixTest.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.adt.internal.build; +import static com.android.AndroidConstants.FD_RES_COLOR; import static com.android.AndroidConstants.FD_RES_LAYOUT; import static com.android.sdklib.SdkConstants.FD_RES; @@ -58,22 +59,28 @@ public class AaptQuickFixTest extends AdtProjectTest { public void testQuickFix1() throws Exception { // Test adding a value into an existing file (res/values/strings.xml) - checkFixes("quickfix1.xml", "android:text=\"@string/firs^tstring\"", + checkResourceFix("quickfix1.xml", "android:text=\"@string/firs^tstring\"", "res/values/strings.xml"); } public void testQuickFix2() throws Exception { // Test adding a value into a new file (res/values/dimens.xml, will be created) - checkFixes("quickfix1.xml", "android:layout_width=\"@dimen/^testdimen\"", + checkResourceFix("quickfix1.xml", "android:layout_width=\"@dimen/^testdimen\"", "res/values/dimens.xml"); } public void testQuickFix3() throws Exception { // Test adding a file based resource (uses new file wizard machinery) - checkFixes("quickfix1.xml", "layout=\"@layout/^testlayout\"", "res/layout/testlayout.xml"); + checkResourceFix("quickfix1.xml", "layout=\"@layout/^testlayout\"", + "res/layout/testlayout.xml"); } - private void checkFixes(String name, String caretLocation, String expectedNewPath) + public void testQuickFix4() throws Exception { + // Test adding a value into a new file (res/values/dimens.xml, will be created) + checkNamespaceFix("quickfix2.xml", "<c^olor"); + } + + private void checkResourceFix(String name, String caretLocation, String expectedNewPath) throws Exception { IProject project = getProject(); IFile file = getTestDataFile(project, name, FD_RES + "/" + FD_RES_LAYOUT + "/" + name); @@ -82,6 +89,10 @@ public class AaptQuickFixTest extends AdtProjectTest { final int offset = getCaretOffset(file, caretLocation); + String osRoot = project.getLocation().toOSString(); + List<String> errors = new ArrayList<String>(); + String fileRelativePath = file.getProjectRelativePath().toPortableString(); + String filePath = osRoot + File.separator + fileRelativePath; // Run AaptParser such that markers are added... // When debugging these tests, the project gets a chance to build itself so // the real aapt errors are there. But when the test is run directly, aapt has @@ -90,10 +101,6 @@ public class AaptQuickFixTest extends AdtProjectTest { // etc) so instead this test just hardcodes the aapt errors that should be // observed on quickfix1.xml. assertEquals("Unit test is hardcoded to errors for quickfix1.xml", "quickfix1.xml", name); - String osRoot = project.getLocation().toOSString(); - List<String> errors = new ArrayList<String>(); - String fileRelativePath = file.getProjectRelativePath().toPortableString(); - String filePath = osRoot + File.separator + fileRelativePath; errors.add(filePath + ":7: error: Error: No resource found that matches the given name" + " (at 'text' with value '@string/firststring')."); errors.add(filePath + ":7: error: Error: No resource found that matches the given name" @@ -192,4 +199,85 @@ public class AaptQuickFixTest extends AdtProjectTest { assertEqualsGolden(name, newFileWithCaret); } + + private void checkNamespaceFix(String name, String caretLocation) + throws Exception { + IProject project = getProject(); + IFile file = getTestDataFile(project, name, FD_RES + "/" + FD_RES_COLOR + "/" + name); + + // Determine the offset + final int offset = getCaretOffset(file, caretLocation); + + String osRoot = project.getLocation().toOSString(); + List<String> errors = new ArrayList<String>(); + String fileRelativePath = file.getProjectRelativePath().toPortableString(); + String filePath = osRoot + File.separator + fileRelativePath; + assertEquals("Unit test is hardcoded to errors for quickfix2.xml", "quickfix2.xml", name); + errors.add(filePath + ":5: error: Error parsing XML: unbound prefix"); + AaptParser.parseOutput(errors, project); + + AaptQuickFix aaptQuickFix = new AaptQuickFix(); + + // Open file + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + assertNotNull(page); + IEditorPart editor = IDE.openEditor(page, file); + assertTrue(editor instanceof AndroidXmlEditor); + AndroidXmlEditor layoutEditor = (AndroidXmlEditor) editor; + final ISourceViewer viewer = layoutEditor.getStructuredSourceViewer(); + + // Test marker resolution. + IMarker[] markers = file.findMarkers(AdtConstants.MARKER_AAPT_COMPILE, true, + IResource.DEPTH_ZERO); + assertEquals(1, markers.length); + IMarker marker = markers[0]; + // Found the target marker. Now check the marker resolution of it. + assertTrue(aaptQuickFix.hasResolutions(marker)); + IMarkerResolution[] resolutions = aaptQuickFix.getResolutions(marker); + assertNotNull(resolutions); + assertEquals(1, resolutions.length); + IMarkerResolution resolution = resolutions[0]; + assertNotNull(resolution); + assertTrue(resolution.getLabel().contains("Insert namespace")); + + // Next test quick assist. + + IQuickAssistInvocationContext invocationContext = new IQuickAssistInvocationContext() { + public int getLength() { + return 0; + } + + public int getOffset() { + return offset; + } + + public ISourceViewer getSourceViewer() { + return viewer; + } + }; + ICompletionProposal[] proposals = aaptQuickFix + .computeQuickAssistProposals(invocationContext); + assertNotNull(proposals); + assertTrue(proposals.length == 1); + ICompletionProposal proposal = proposals[0]; + + assertNotNull(proposal.getAdditionalProposalInfo()); + assertNotNull(proposal.getImage()); + assertTrue(proposal.getDisplayString().contains("Insert namespace")); + + // Open the file to ensure we can get an XML model with getExistingModelForEdit: + AdtPlugin.openFile(file, null); + IEditorPart newEditor = Hyperlinks.getEditor(); + assertTrue(newEditor instanceof AndroidXmlEditor); + + AndroidXmlEditor xmlEditor = (AndroidXmlEditor) newEditor; + IDocument document = xmlEditor.getStructuredSourceViewer().getDocument(); + + // Apply quick fix + String before = document.get(); + proposal.apply(document); + String after = document.get(); + String diff = getDiff(before, after); + assertEqualsGolden(name, diff); + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java index 6cff2f294..c7a452e40 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java @@ -16,7 +16,16 @@ */ package com.android.ide.eclipse.adt.internal.editors; +import static com.android.AndroidConstants.FD_RES_ANIM; +import static com.android.AndroidConstants.FD_RES_ANIMATOR; +import static com.android.AndroidConstants.FD_RES_COLOR; +import static com.android.AndroidConstants.FD_RES_DRAWABLE; +import static com.android.sdklib.SdkConstants.FD_RES; + import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.editors.animator.AnimationContentAssist; +import com.android.ide.eclipse.adt.internal.editors.color.ColorContentAssist; +import com.android.ide.eclipse.adt.internal.editors.drawable.DrawableContentAssist; import com.android.ide.eclipse.adt.internal.editors.layout.LayoutContentAssist; import com.android.ide.eclipse.adt.internal.editors.layout.refactoring.AdtProjectTest; import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestContentAssist; @@ -316,8 +325,101 @@ public class AndroidContentAssistTest extends AdtProjectTest { checkLayoutCompletion("completion8.xml", "android:layo^ut_width=\"fill_parent\""); } + public void testCompletion45() throws Exception { + // Test top level elements in colors + checkColorCompletion("color1.xml", "^<selector"); + } + + public void testCompletion46a() throws Exception { + // Test children of selector: should offer item + checkColorCompletion("color1.xml", "^<item android"); + } + + public void testCompletion46b() throws Exception { + // Test attribute matching in color files + checkColorCompletion("color1.xml", "<item ^android:state_focused=\"true\"/>"); + } + + public void testCompletion47() throws Exception { + // Check root completion in drawables: should list all drawable root elements + checkDrawableCompletion("drawable1.xml", "^<layer-list"); + } + + public void testCompletion48() throws Exception { + // Check attributes of the layer list + checkDrawableCompletion("drawable1.xml", "^xmlns:android"); + } + + public void testCompletion49() throws Exception { + // Check attributes of the <item> element inside a <layer-list> + checkDrawableCompletion("drawable1.xml", "<item ^></item>"); + } + + public void testCompletion50() throws Exception { + // Check elements nested inside the <item> in a layer list: can use any drawable again + checkDrawableCompletion("drawable1.xml", "<item >^</item>"); + } + + public void testCompletion51() throws Exception { + // Check attributes of <shape> element + checkDrawableCompletion("drawable2.xml", "^android:innerRadiusRatio=\"2\""); + } + + public void testCompletion52() throws Exception { + // Check list of available elements inside a shape + checkDrawableCompletion("drawable2.xml", "^<gradient"); + } + + public void testCompletion53() throws Exception { + // Check list of root anim elements + checkAnimCompletion("anim1.xml", "^<set xmlns"); + } + + public void testCompletion54() throws Exception { + // Check that we can nest inside <set>'s + checkAnimCompletion("anim1.xml", "^<translate android:id="); + } + + public void testCompletion55() throws Exception { + // translate properties + checkAnimCompletion("anim1.xml", "android:^fromXDelta="); + } + + public void testCompletion56() throws Exception { + // alpha properties + checkAnimCompletion("anim1.xml", "android:^fromAlpha="); + } + + public void testCompletion57() throws Exception { + // Fractional properties + checkAnimCompletion("anim1.xml", "android:fromXDelta=\"100^%p\""); + } + + public void testCompletion58() throws Exception { + // Top level animator elements + checkAnimatorCompletion("animator1.xml", "^<set xmlns"); + } + + public void testCompletion59() throws Exception { + // objectAnimator properties + checkAnimatorCompletion("animator1.xml", "android:^duration=\"2000\""); + } + + public void testCompletion60() throws Exception { + // propertyName completion + checkAnimatorCompletion("animator1.xml", "android:propertyName=\"scal^eX\"/>"); + } + + public void testCompletion61() throws Exception { + // Interpolator completion + checkAnimatorCompletion("animator1.xml", + "android:interpolator=\"^@android:anim/bounce_interpolator\""); + } + // ---- Test *applying* code completion ---- + + // The following tests check -applying- a specific code completion // match - this verifies that the document is updated correctly, the // caret is moved appropriately, etc. @@ -593,6 +695,34 @@ public class AndroidContentAssistTest extends AdtProjectTest { new LayoutContentAssist()); } + private void checkColorCompletion(String name, String caretLocation) throws Exception { + IFile file = getTestDataFile(getProject(), name, + FD_RES + "/" + FD_RES_COLOR + "/" + name); + checkCompletion(name, file, caretLocation, + new ColorContentAssist()); + } + private void checkAnimCompletion(String name, String caretLocation) throws Exception { + IFile file = getTestDataFile(getProject(), name, + FD_RES + "/" + FD_RES_ANIM + "/" + name); + checkCompletion(name, file, caretLocation, + new AnimationContentAssist()); + } + + private void checkAnimatorCompletion(String name, String caretLocation) throws Exception { + IFile file = getTestDataFile(getProject(), name, + FD_RES + "/" + FD_RES_ANIMATOR + "/" + name); + checkCompletion(name, file, caretLocation, + new AnimationContentAssist()); + } + + + private void checkDrawableCompletion(String name, String caretLocation) throws Exception { + IFile file = getTestDataFile(getProject(), name, + FD_RES + "/" + FD_RES_DRAWABLE + "/" + name); + checkCompletion(name, file, caretLocation, + new DrawableContentAssist()); + } + private void checkManifestCompletion(String name, String caretLocation) throws Exception { // Manifest files must be named AndroidManifest.xml. Must overwrite to replace // the default manifest created in the test project. diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/AdtProjectTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/AdtProjectTest.java index ead55f91d..3b83bd793 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/AdtProjectTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/AdtProjectTest.java @@ -66,6 +66,7 @@ import java.util.Map; @SuppressWarnings("restriction") public class AdtProjectTest extends SdkTestCase { + private static final int TARGET_API_LEVEL = 11; /** Update golden files if different from the actual results */ private static final boolean UPDATE_DIFFERENT_FILES = false; /** Create golden files if missing */ @@ -112,6 +113,16 @@ public class AdtProjectTest extends SdkTestCase { return false; } + @Override + protected boolean validateSdk(IAndroidTarget target) { + // Not quite working yet. When enabled will make tests run faster. + //if (target.getVersion().getApiLevel() < TARGET_API_LEVEL) { + // return false; + //} + + return true; + } + /** Returns a name to use for the project used in this test. Subclasses do not need to * override this if they can share a project with others - which is the case if they do * not modify the project in a way that does not affect other tests. For example @@ -207,7 +218,7 @@ public class AdtProjectTest extends SdkTestCase { IAndroidTarget[] targets = getSdk().getTargets(); for (IAndroidTarget t : targets) { - if (t.getVersion().getApiLevel() >= 11) { + if (t.getVersion().getApiLevel() >= TARGET_API_LEVEL) { target = t; break; } @@ -232,7 +243,7 @@ public class AdtProjectTest extends SdkTestCase { IAndroidTarget[] targets = getSdk().getTargets(); for (IAndroidTarget t : targets) { - if (t.getVersion().getApiLevel() >= 11) { + if (t.getVersion().getApiLevel() >= TARGET_API_LEVEL) { target = t; break; } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion53.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion53.txt new file mode 100644 index 000000000..3e44918d9 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion53.txt @@ -0,0 +1,6 @@ +Code completion in anim1.xml for ^<set xmlns: +<alpha /> +<rotate /> +<scale /> +<set ></set> +<translate /> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion54.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion54.txt new file mode 100644 index 000000000..f5e5cba69 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion54.txt @@ -0,0 +1,6 @@ +Code completion in anim1.xml for ^<translate android:id=: +<alpha /> +<rotate /> +<scale /> +<set ></set> +<translate /> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion55.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion55.txt new file mode 100644 index 000000000..28b15d3c7 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion55.txt @@ -0,0 +1,16 @@ +Code completion in anim1.xml for android:^fromXDelta=: +android:fromXDelta : [float, fraction] +android:toXDelta : [float, fraction] +android:fromYDelta : [float, fraction] +android:toYDelta : [float, fraction] +android:interpolator : Defines the interpolator used to smooth the animation movement in time. [reference] +android:fillEnabled : When set to true, fillAfter is taken into account. [boolean] +android:fillBefore : When set to true, the animation transformation is applied before the animation has started. [boolean] +android:fillAfter : When set to true, the animation transformation is applied after the animation is over. [boolean] +android:duration : Amount of time (in milliseconds) for the animation to run. [integer] +android:startOffset : Delay in milliseconds before the animation runs, once start time is reached. [integer] +android:repeatCount : Defines how many times the animation should repeat. [integer, enum] +android:repeatMode : Defines the animation behavior when it reaches the end and the repeat count is greater than 0 or infinite. [enum] +android:zAdjustment : Allows for an adjustment of the Z ordering of the content being animated for the duration of the animation. [enum] +android:background : Special background behind animation. [reference, color] +android:detachWallpaper : Special option for window animations: if this window is on top of a wallpaper, don't animate the wallpaper with it. [boolean] diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion56.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion56.txt new file mode 100644 index 000000000..632a9c549 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion56.txt @@ -0,0 +1,14 @@ +Code completion in anim1.xml for android:^fromAlpha=: +android:fromAlpha : [float] +android:toAlpha : [float] +android:interpolator : Defines the interpolator used to smooth the animation movement in time. [reference] +android:fillEnabled : When set to true, fillAfter is taken into account. [boolean] +android:fillBefore : When set to true, the animation transformation is applied before the animation has started. [boolean] +android:fillAfter : When set to true, the animation transformation is applied after the animation is over. [boolean] +android:duration : Amount of time (in milliseconds) for the animation to run. [integer] +android:startOffset : Delay in milliseconds before the animation runs, once start time is reached. [integer] +android:repeatCount : Defines how many times the animation should repeat. [integer, enum] +android:repeatMode : Defines the animation behavior when it reaches the end and the repeat count is greater than 0 or infinite. [enum] +android:zAdjustment : Allows for an adjustment of the Z ordering of the content being animated for the duration of the animation. [enum] +android:background : Special background behind animation. [reference, color] +android:detachWallpaper : Special option for window animations: if this window is on top of a wallpaper, don't animate the wallpaper with it. [boolean] diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion57.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion57.txt new file mode 100644 index 000000000..9225dac46 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1-expected-completion57.txt @@ -0,0 +1,3 @@ +Code completion in anim1.xml for android:fromXDelta="100^%p": +100% : <b>Fraction</b> - a percentage of the base size +100%p : <b>Fraction</b> - a percentage relative to parent container diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1.xml new file mode 100644 index 000000000..48fefc2ba --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/anim1.xml @@ -0,0 +1,20 @@ +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <translate android:id="@+id/test1" + android:fromXDelta="100%p" + android:pivotY="60%p" + android:toXDelta="40%p" + android:toYDelta="33%p" + android:fillBefore="true" + android:fillAfter="true" + android:startOffset="1000" + android:duration="1000" /> + <alpha + android:id="@+id/test2" + android:fromAlpha="1.0" + android:toAlpha="0.0" + android:startOffset="3000" + android:duration="250" + android:fillBefore="true" + android:fillAfter="false" + /> +</set> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1-expected-completion58.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1-expected-completion58.txt new file mode 100644 index 000000000..075941502 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1-expected-completion58.txt @@ -0,0 +1,4 @@ +Code completion in animator1.xml for ^<set xmlns: +<animator ></animator> +<objectAnimator ></objectAnimator> +<set ></set> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1-expected-completion59.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1-expected-completion59.txt new file mode 100644 index 000000000..070271268 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1-expected-completion59.txt @@ -0,0 +1,10 @@ +Code completion in animator1.xml for android:^duration="2000": +android:propertyName : Name of the property being animated. [string] +android:interpolator : Defines the interpolator used to smooth the animation movement in time. [reference] +android:duration : Amount of time (in milliseconds) for the animation to run. [integer] +android:startOffset : Delay in milliseconds before the animation runs, once start time is reached. [integer] +android:repeatCount : Defines how many times the animation should repeat. [integer, enum] +android:repeatMode : Defines the animation behavior when it reaches the end and the repeat count is greater than 0 or infinite. [enum] +android:valueFrom : Value the animation starts from. [integer, float, color, dimension] +android:valueTo : Value the animation animates to. [integer, float, color, dimension] +android:valueType : The type of valueFrom and valueTo. [enum] diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1-expected-completion60.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1-expected-completion60.txt new file mode 100644 index 000000000..3e5e6b127 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1-expected-completion60.txt @@ -0,0 +1,3 @@ +Code completion in animator1.xml for android:propertyName="scal^eX"/>: +scaleX : scale of the view in the x direction. +scaleY : scale of the view in the y direction. diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1-expected-completion61.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1-expected-completion61.txt new file mode 100644 index 000000000..d4618c2cc --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1-expected-completion61.txt @@ -0,0 +1,18 @@ +Code completion in animator1.xml for android:interpolator="^@android:anim/bounce_interpolator": +@android:anim/accelerate_decelerate_interpolator +@android:anim/accelerate_interpolator +@android:anim/decelerate_interpolator +@android:anim/anticipate_interpolator +@android:anim/overshoot_interpolator +@android:anim/anticipate_overshoot_interpolator +@android:anim/bounce_interpolator +@android:anim/linear_interpolator +@android:anim/cycle_interpolator +@android: +@anim/ +@animator/ +@color/ +@drawable/ +@layout/ +@string/ +@style/ diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1.xml new file mode 100644 index 000000000..bdf10dced --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/animator1.xml @@ -0,0 +1,27 @@ +<!-- Simple bounce animation --> +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:ordering="sequentially"> + <set> + <objectAnimator + android:duration="2000" + android:valueTo="310" + android:propertyName="x"/> + <objectAnimator + android:duration="2000" + android:valueTo="130" + android:propertyName="y" + android:interpolator="@android:anim/bounce_interpolator"/> + <objectAnimator + android:duration="2000" + android:valueTo=".4" + android:propertyName="scaleX"/> + <objectAnimator + android:duration="2000" + android:valueTo=".4" + android:propertyName="scaleY"/> + </set> + <objectAnimator + android:duration="500" + android:valueTo="0" + android:propertyName="alpha"/> +</set> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/color1-expected-completion45.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/color1-expected-completion45.txt new file mode 100644 index 000000000..c799b8094 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/color1-expected-completion45.txt @@ -0,0 +1,2 @@ +Code completion in color1.xml for ^<selector: +<selector ></selector> : Required. This must be the root element. Contains one or more <item> elements. diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/color1-expected-completion46a.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/color1-expected-completion46a.txt new file mode 100644 index 000000000..32f0066b6 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/color1-expected-completion46a.txt @@ -0,0 +1,2 @@ +Code completion in color1.xml for ^<item android: +<item /> : Drawable states. diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/color1-expected-completion46b.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/color1-expected-completion46b.txt new file mode 100644 index 000000000..7fcc5a923 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/color1-expected-completion46b.txt @@ -0,0 +1,16 @@ +Code completion in color1.xml for <item ^android:state_focused="true"/>: +android:state_focused : State value for StateListDrawable, set when a view has input focus. [boolean] +android:state_window_focused : State value for StateListDrawable, set when a view's window has input focus. [boolean] +android:state_enabled : State value for StateListDrawable, set when a view is enabled. [boolean] +android:state_checkable : State identifier indicating that the object <var>may</var> display a check mark. [boolean] +android:state_checked : State identifier indicating that the object is currently checked. [boolean] +android:state_selected : State value for StateListDrawable, set when a view (or one of its parents) is currently selected. [boolean] +android:state_pressed : State value for StateListDrawable, set when the user is pressing down in a view. [boolean] +android:state_activated : State value for StateListDrawable, set when a view or its parent has been "activated" meaning the user has currently marked it as being of interest. [boolean] +android:state_active : State value for StateListDrawable. [boolean] +android:state_single : State value for StateListDrawable. [boolean] +android:state_first : State value for StateListDrawable. [boolean] +android:state_middle : State value for StateListDrawable. [boolean] +android:state_last : State value for StateListDrawable. [boolean] +android:state_accelerated : State value for StateListDrawable, indicating that the Drawable is in a view that is hardware accelerated. [boolean] +android:color : Hexadeximal color. Required. The color is specified with an RGB value and optional alpha channel. The value always begins with a pound (#) character and then followed by the Alpha-Red-Green-Blue information in one of the following formats: * RGB * ARGB * RRGGBB * AARRGGBB diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/color1.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/color1.xml new file mode 100644 index 000000000..a8482abac --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/color1.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_focused="true"/> + <item /> +</selector> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1-expected-completion47.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1-expected-completion47.txt new file mode 100644 index 000000000..edf4892fa --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1-expected-completion47.txt @@ -0,0 +1,13 @@ +Code completion in drawable1.xml for ^<layer-list: +<animated-rotate /> +<animation-list /> : Drawable used to render several animated frames. +<bitmap /> : Drawable used to draw bitmaps. +<clip /> +<color /> : Drawable used to draw a single color. +<inset /> +<layer-list ></layer-list> : Drawable used to render several drawables stacked on top of each other. +<nine-patch /> : Drawable used to draw 9-patches. +<rotate /> : Drawable used to rotate another drawable. +<scale /> +<selector ></selector> : Drawable used to render several states. +<shape ></shape> : Drawable used to render a geometric shape, with a gradient or a solid color. diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1-expected-completion48.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1-expected-completion48.txt new file mode 100644 index 000000000..f98bb4c20 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1-expected-completion48.txt @@ -0,0 +1,3 @@ +Code completion in drawable1.xml for ^xmlns:android: +android:opacity : Indicates the opacity of the layer. [enum] +xmlns:android diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1-expected-completion49.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1-expected-completion49.txt new file mode 100644 index 000000000..4d3dfe370 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1-expected-completion49.txt @@ -0,0 +1,7 @@ +Code completion in drawable1.xml for <item ^></item>: +android:left : Left coordinate of the layer. [dimension] +android:top : Top coordinate of the layer. [dimension] +android:right : Right coordinate of the layer. [dimension] +android:bottom : Bottom coordinate of the layer. [dimension] +android:drawable : Drawable used to render the layer. [reference] +android:id : Identifier of the layer. [reference] diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1-expected-completion50.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1-expected-completion50.txt new file mode 100644 index 000000000..90eab1089 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1-expected-completion50.txt @@ -0,0 +1,13 @@ +Code completion in drawable1.xml for <item >^</item>: +<animated-rotate /> +<animation-list /> : Drawable used to render several animated frames. +<bitmap /> : Drawable used to draw bitmaps. +<clip /> +<color /> : Drawable used to draw a single color. +<inset /> +<layer-list ></layer-list> : Drawable used to render several drawables stacked on top of each other. +<nine-patch /> : Drawable used to draw 9-patches. +<rotate /> : Drawable used to rotate another drawable. +<scale /> +<selector ></selector> : Drawable used to render several states. +<shape ></shape> : Drawable used to render a geometric shape, with a gradient or a solid color. diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1.xml new file mode 100644 index 000000000..9513f1709 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable1.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list + xmlns:android="http://schemas.android.com/apk/res/android"> + <item ></item> +</layer-list> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable2-expected-completion51.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable2-expected-completion51.txt new file mode 100644 index 000000000..147184597 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable2-expected-completion51.txt @@ -0,0 +1,10 @@ +Code completion in drawable2.xml for ^android:innerRadiusRatio="2": +android:visible : Indicates whether the drawable should intially be visible. [boolean] +android:dither : Enables or disables dithering. [boolean] +android:shape : Indicates what shape to fill with a gradient. [enum] +android:innerRadiusRatio : Inner radius of the ring expressed as a ratio of the ring's width. [float] +android:thicknessRatio : Thickness of the ring expressed as a ratio of the ring's width. [float] +android:innerRadius : Inner radius of the ring. [dimension] +android:thickness : Thickness of the ring. [dimension] +android:useLevel : Indicates whether the drawable's level affects the way the gradient is drawn. +xmlns:android diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable2-expected-completion52.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable2-expected-completion52.txt new file mode 100644 index 000000000..2a2853363 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable2-expected-completion52.txt @@ -0,0 +1,7 @@ +Code completion in drawable2.xml for ^<gradient: +<corners /> : Describes the corners for the rectangle shape of a GradientDrawable. +<gradient /> : Used to describe the gradient used to fill the shape of a GradientDrawable. +<padding /> : Used to specify the optional padding of a GradientDrawable. +<size /> : Used to specify the size of the shape for GradientDrawable. +<solid /> : Used to fill the shape of GradientDrawable with a solid color. +<stroke /> : Used to describe the optional stroke of a GradientDrawable. diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable2.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable2.xml new file mode 100644 index 000000000..c6a672fd8 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/drawable2.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:innerRadiusRatio="2"> + <gradient /> +</shape> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/quickfix2-expected-quickFix4.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/quickfix2-expected-quickFix4.xml new file mode 100644 index 000000000..025fa0a67 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/quickfix2-expected-quickFix4.xml @@ -0,0 +1,3 @@ +< <color android:color="#0000000"/> +--- +> <color android:color="#0000000" xmlns:android="http://schemas.android.com/apk/res/android"/> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/quickfix2.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/quickfix2.xml new file mode 100644 index 000000000..4f2a925a5 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/quickfix2.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> + <!-- + Random comment here + --> +<color android:color="#0000000"/> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/SdkTestCase.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/SdkTestCase.java index d0998c9f1..d8692ae1c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/SdkTestCase.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/SdkTestCase.java @@ -93,6 +93,10 @@ public abstract class SdkTestCase extends TestCase { return sdk; } + protected boolean validateSdk(IAndroidTarget target) { + return true; + } + /** * Checks that the provided sdk contains one or more valid targets. * @param sdk the {@link Sdk} to validate. @@ -100,6 +104,9 @@ public abstract class SdkTestCase extends TestCase { private void validateSdk(Sdk sdk) { assertTrue("sdk has no targets", sdk.getTargets().length > 0); for (IAndroidTarget target : sdk.getTargets()) { + if (!validateSdk(target)) { + continue; + } IStatus status = new AndroidTargetParser(target).run(new NullProgressMonitor()); if (status.getCode() != IStatus.OK) { fail("Failed to parse targets data"); diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/resources/ResourceHelperTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/resources/ResourceHelperTest.java index a653ae280..078e7cb71 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/resources/ResourceHelperTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/resources/ResourceHelperTest.java @@ -165,7 +165,6 @@ public class ResourceHelperTest extends TestCase { assertFalse(ResourceHelper.canCreateResource("@typo/foo")); // nonexistent type assertFalse(ResourceHelper.canCreateResource("@layout/foo bar")); // space assertFalse(ResourceHelper.canCreateResource("@layout/new")); // keyword - assertFalse(ResourceHelper.canCreateResource("@animator/foo")); // unsupported file type assertFalse(ResourceHelper.canCreateResource("@android:string/foo")); // framework assertFalse(ResourceHelper.canCreateResource("@android:dimen/foo")); assertFalse(ResourceHelper.canCreateResource("@android:color/foo")); |