| /* |
| * 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); |
| } |
| } |
| } |