diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java | 168 |
1 files changed, 168 insertions, 0 deletions
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..8a4cf2384 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java @@ -0,0 +1,168 @@ +/* + * 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.SdkConstants.ANDROID_NS_NAME_PREFIX; +import static com.android.SdkConstants.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.AdtUtils; +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.utils.Pair; + +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.w3c.dom.Node; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +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 = AdtUtils.getParentFolderName(mEditor.getEditorInput()); + ResourceFolderType folderType = ResourceFolderType.getFolderType(folderName); + if (folderType == ResourceFolderType.ANIM) { + return AndroidTargetData.DESCRIPTOR_ANIM; + } else { + return AndroidTargetData.DESCRIPTOR_ANIMATOR; + } + } + + @Override + protected boolean 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); + } + + + return 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)) { + EnumSet<Format> formats = desc.getAttributeInfo().getFormats(); + if (formats.contains(Format.INTEGER) + || formats.contains(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); + } + } + } + } + + 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 false; + } else { + return super.computeAttributeValues(proposals, offset, parentTagName, attributeName, + node, wordPrefix, skipEndTag, replaceLength); + } + } +} |