diff --git a/plugins/android/src/META-INF/plugin.xml b/plugins/android/src/META-INF/plugin.xml index 06ad04e58436..0df38f44a99f 100644 --- a/plugins/android/src/META-INF/plugin.xml +++ b/plugins/android/src/META-INF/plugin.xml @@ -96,6 +96,7 @@ + diff --git a/plugins/android/src/org/jetbrains/android/AndroidCompletionContributor.java b/plugins/android/src/org/jetbrains/android/AndroidCompletionContributor.java index d6d5cf08bf23..266e64dc4085 100644 --- a/plugins/android/src/org/jetbrains/android/AndroidCompletionContributor.java +++ b/plugins/android/src/org/jetbrains/android/AndroidCompletionContributor.java @@ -27,6 +27,8 @@ import com.intellij.psi.xml.XmlTag; import org.jetbrains.android.dom.AndroidDomExtender; import org.jetbrains.android.dom.animation.AndroidAnimationUtils; import org.jetbrains.android.dom.animation.AnimationDomFileDescription; +import org.jetbrains.android.dom.animator.AndroidAnimatorUtil; +import org.jetbrains.android.dom.animator.AnimatorDomFileDescription; import org.jetbrains.android.dom.color.ColorDomFileDescription; import org.jetbrains.android.dom.drawable.AndroidDrawableDomUtil; import org.jetbrains.android.dom.drawable.DrawableStateListDomFileDescription; @@ -81,6 +83,10 @@ public class AndroidCompletionContributor extends CompletionContributor { addAll(AndroidAnimationUtils.getPossibleChildren(facet), resultSet); return false; } + else if (AnimatorDomFileDescription.isAnimatorFile(xmlFile)) { + addAll(AndroidAnimatorUtil.getPossibleChildren(), resultSet); + return false; + } else if (XmlResourceDomFileDescription.isXmlResourceFile(xmlFile)) { addAll(AndroidXmlResourcesUtil.getPossibleRoots(facet), resultSet); return false; diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateResourceDialog.java b/plugins/android/src/org/jetbrains/android/actions/CreateResourceDialog.java index 59f30e3c70db..f0d4c9163102 100644 --- a/plugins/android/src/org/jetbrains/android/actions/CreateResourceDialog.java +++ b/plugins/android/src/org/jetbrains/android/actions/CreateResourceDialog.java @@ -33,7 +33,9 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.Arrays; import java.util.Collection; +import java.util.Comparator; import java.util.Map; /** @@ -63,6 +65,14 @@ public abstract class CreateResourceDialog extends DialogWrapper { myResourceTypeCombo.registerUpDownHint(myFileNameField); myUpDownHint.setIcon(PlatformIcons.UP_DOWN_ARROWS); CreateTypedResourceFileAction[] actionArray = actions.toArray(new CreateTypedResourceFileAction[actions.size()]); + + Arrays.sort(actionArray, new Comparator() { + @Override + public int compare(CreateTypedResourceFileAction a1, CreateTypedResourceFileAction a2) { + return a1.toString().compareTo(a2.toString()); + } + }); + for (CreateTypedResourceFileAction action : actionArray) { String resType = action.getResourceType(); assert !myResType2ActionMap.containsKey(resType); diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileActionGroup.java b/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileActionGroup.java index 105469459c98..21666f9d9c58 100644 --- a/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileActionGroup.java +++ b/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileActionGroup.java @@ -38,6 +38,7 @@ public class CreateResourceFileActionGroup extends DefaultActionGroup { a.add(new CreateTypedResourceFileAction("Values", "values", "resources", true, false)); a.add(new CreateTypedResourceFileAction("Menu", "menu", "menu", false, false)); a.add(new CreateTypedResourceFileAction("Animation", "anim", "set")); + a.add(new CreateTypedResourceFileAction("Animator", "animator", "set")); myMajorAction = a; add(a); for (CreateTypedResourceFileAction subaction : a.getSubactions()) { diff --git a/plugins/android/src/org/jetbrains/android/dom/AndroidDomExtender.java b/plugins/android/src/org/jetbrains/android/dom/AndroidDomExtender.java index 8670c98e1517..69d91a089f86 100644 --- a/plugins/android/src/org/jetbrains/android/dom/AndroidDomExtender.java +++ b/plugins/android/src/org/jetbrains/android/dom/AndroidDomExtender.java @@ -33,6 +33,8 @@ import com.intellij.util.xml.reflect.DomExtension; import com.intellij.util.xml.reflect.DomExtensionsRegistrar; import org.jetbrains.android.dom.animation.AndroidAnimationUtils; import org.jetbrains.android.dom.animation.AnimationElement; +import org.jetbrains.android.dom.animator.AndroidAnimatorUtil; +import org.jetbrains.android.dom.animator.AnimatorElement; import org.jetbrains.android.dom.attrs.AttributeDefinition; import org.jetbrains.android.dom.attrs.AttributeDefinitions; import org.jetbrains.android.dom.attrs.AttributeFormat; @@ -359,6 +361,24 @@ public class AndroidDomExtender extends DomExtender { } } + public static void registerExtensionsForAnimator(final AndroidFacet facet, + String tagName, + AnimatorElement element, + DomExtensionsRegistrar registrar, + Set registeredSubtags) { + if (tagName.equals("set")) { + for (String subtagName : AndroidAnimatorUtil.getPossibleChildren()) { + registerSubtags(subtagName, AnimatorElement.class, registrar, registeredSubtags); + } + } + registerAttributes(facet, element, "Animator", SYSTEM_RESOURCE_PACKAGE, registrar); + final String styleableName = AndroidAnimatorUtil.getStyleableNameByTagName(tagName); + + if (styleableName != null) { + registerAttributes(facet, element, styleableName, SYSTEM_RESOURCE_PACKAGE, registrar); + } + } + public static Map getViewClassMap(@NotNull AndroidFacet facet) { return facet.getClassMap(AndroidUtils.VIEW_CLASS_NAME, SimpleClassMapConstructor.getInstance()); } @@ -531,6 +551,9 @@ public class AndroidDomExtender extends DomExtender { else if (element instanceof AnimationElement) { registerExtensionsForAnimation(facet, tagName, (AnimationElement)element, registrar, registeredSubtags); } + else if (element instanceof AnimatorElement) { + registerExtensionsForAnimator(facet, tagName, (AnimatorElement)element, registrar, registeredSubtags); + } else if (element instanceof MenuElement) { String styleableName = StringUtil.capitalize(tagName); if (!styleableName.equals("Menu")) { diff --git a/plugins/android/src/org/jetbrains/android/dom/animator/AndroidAnimatorUtil.java b/plugins/android/src/org/jetbrains/android/dom/animator/AndroidAnimatorUtil.java new file mode 100644 index 000000000000..265acf57cd67 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/dom/animator/AndroidAnimatorUtil.java @@ -0,0 +1,29 @@ +package org.jetbrains.android.dom.animator; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidAnimatorUtil { + private static final String[] TAG_NAMES = {"set", "objectAnimator", "animator"}; + + public static List getPossibleChildren() { + return Arrays.asList(TAG_NAMES); + } + + @Nullable + public static String getStyleableNameByTagName(@NotNull String tagName) { + if (tagName.equals("set")) { + return "AnimatorSet"; + } + else if (tagName.equals("objectAnimator")) { + return "PropertyAnimator"; + } + return null; + } +} diff --git a/plugins/android/src/org/jetbrains/android/dom/animator/AnimatorDomFileDescription.java b/plugins/android/src/org/jetbrains/android/dom/animator/AnimatorDomFileDescription.java new file mode 100644 index 000000000000..184b3e537474 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/dom/animator/AnimatorDomFileDescription.java @@ -0,0 +1,30 @@ +package org.jetbrains.android.dom.animator; + +import com.android.resources.ResourceFolderType; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.Computable; +import com.intellij.psi.xml.XmlFile; +import org.jetbrains.android.dom.AndroidResourceDomFileDescription; +import org.jetbrains.annotations.NotNull; + +/** + * @author Eugene.Kudelevsky + */ +public class AnimatorDomFileDescription extends AndroidResourceDomFileDescription { + public AnimatorDomFileDescription() { + super(AnimatorElement.class, "set", ResourceFolderType.ANIMATOR.getName()); + } + + @Override + public boolean acceptsOtherRootTagNames() { + return true; + } + + public static boolean isAnimatorFile(@NotNull final XmlFile file) { + return ApplicationManager.getApplication().runReadAction(new Computable() { + public Boolean compute() { + return new AnimatorDomFileDescription().isMyFile(file, null); + } + }); + } +} diff --git a/plugins/android/src/org/jetbrains/android/dom/animator/AnimatorElement.java b/plugins/android/src/org/jetbrains/android/dom/animator/AnimatorElement.java new file mode 100644 index 000000000000..b4cb686d5bde --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/dom/animator/AnimatorElement.java @@ -0,0 +1,11 @@ +package org.jetbrains.android.dom.animator; + +import com.intellij.util.xml.DefinesXml; +import org.jetbrains.android.dom.AndroidDomElement; + +/** + * @author Eugene.Kudelevsky + */ +@DefinesXml +public interface AnimatorElement extends AndroidDomElement { +} diff --git a/plugins/android/src/org/jetbrains/android/dom/converters/ResourceReferenceConverter.java b/plugins/android/src/org/jetbrains/android/dom/converters/ResourceReferenceConverter.java index c24a9576749f..d02dcee87ddd 100644 --- a/plugins/android/src/org/jetbrains/android/dom/converters/ResourceReferenceConverter.java +++ b/plugins/android/src/org/jetbrains/android/dom/converters/ResourceReferenceConverter.java @@ -55,8 +55,10 @@ import static org.jetbrains.android.util.AndroidUtils.SYSTEM_RESOURCE_PACKAGE; * @author yole */ public class ResourceReferenceConverter extends ResolvingConverter implements CustomReferenceConverter { - private static final Set XML_FILE_RESOURCE_TYPES = - EnumSet.of(ResourceType.ANIM, ResourceType.LAYOUT, ResourceType.MENU, ResourceType.XML, ResourceType.COLOR, ResourceType.DRAWABLE); + private static final Set XML_FILE_RESOURCE_TYPES = EnumSet.of(ResourceType.ANIM, ResourceType.ANIMATOR, + ResourceType.INTERPOLATOR, ResourceType.LAYOUT, + ResourceType.MENU, ResourceType.XML, ResourceType.COLOR, + ResourceType.DRAWABLE); private final List myResourceTypes; private ResolvingConverter myAdditionalConverter; diff --git a/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java b/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java index f74c20bb8b35..3542d6aaf825 100644 --- a/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java +++ b/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java @@ -464,7 +464,8 @@ public class AndroidResourceUtil { public static boolean isResourceSubdirectory(@NotNull PsiDirectory directory, @Nullable String resourceType) { PsiDirectory dir = directory; - if (resourceType != null && !dir.getName().startsWith(resourceType)) { + final String dirName = dir.getName(); + if (resourceType != null && !dirName.equals(resourceType) && !dirName.startsWith(resourceType + '-')) { return false; } dir = dir.getParent(); diff --git a/plugins/android/testData/dom/animator/an1.xml b/plugins/android/testData/dom/animator/an1.xml new file mode 100644 index 000000000000..63efe551c2ec --- /dev/null +++ b/plugins/android/testData/dom/animator/an1.xml @@ -0,0 +1,3 @@ + + + diff --git a/plugins/android/testData/dom/animator/an1_after.xml b/plugins/android/testData/dom/animator/an1_after.xml new file mode 100644 index 000000000000..351b5bd22cb2 --- /dev/null +++ b/plugins/android/testData/dom/animator/an1_after.xml @@ -0,0 +1,3 @@ + + diff --git a/plugins/android/testData/dom/animator/an2.xml b/plugins/android/testData/dom/animator/an2.xml new file mode 100644 index 000000000000..faa942fa7aa2 --- /dev/null +++ b/plugins/android/testData/dom/animator/an2.xml @@ -0,0 +1,2 @@ +> + diff --git a/plugins/android/testData/dom/animator/an2_after.xml b/plugins/android/testData/dom/animator/an2_after.xml new file mode 100644 index 000000000000..90ab7398bb71 --- /dev/null +++ b/plugins/android/testData/dom/animator/an2_after.xml @@ -0,0 +1,2 @@ + + diff --git a/plugins/android/testData/dom/animator/av.xml b/plugins/android/testData/dom/animator/av.xml new file mode 100644 index 000000000000..528c20c37b67 --- /dev/null +++ b/plugins/android/testData/dom/animator/av.xml @@ -0,0 +1,2 @@ + + diff --git a/plugins/android/testData/dom/animator/av_after.xml b/plugins/android/testData/dom/animator/av_after.xml new file mode 100644 index 000000000000..6b78451bd38b --- /dev/null +++ b/plugins/android/testData/dom/animator/av_after.xml @@ -0,0 +1,2 @@ + + diff --git a/plugins/android/testData/dom/animator/hl.xml b/plugins/android/testData/dom/animator/hl.xml new file mode 100644 index 000000000000..6be71be8139f --- /dev/null +++ b/plugins/android/testData/dom/animator/hl.xml @@ -0,0 +1,14 @@ + + + + diff --git a/plugins/android/testData/dom/animator/root.xml b/plugins/android/testData/dom/animator/root.xml new file mode 100644 index 000000000000..01c0f68a758e --- /dev/null +++ b/plugins/android/testData/dom/animator/root.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/plugins/android/testData/dom/animator/root_after.xml b/plugins/android/testData/dom/animator/root_after.xml new file mode 100644 index 000000000000..9516a50b5eb3 --- /dev/null +++ b/plugins/android/testData/dom/animator/root_after.xml @@ -0,0 +1 @@ + + + \ No newline at end of file diff --git a/plugins/android/testData/dom/animator/tn_after.xml b/plugins/android/testData/dom/animator/tn_after.xml new file mode 100644 index 000000000000..fc3a90601664 --- /dev/null +++ b/plugins/android/testData/dom/animator/tn_after.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/plugins/android/testData/sdk1.5/platforms/android-1.5/data/res/interpolator/platformInterpolator.xml b/plugins/android/testData/sdk1.5/platforms/android-1.5/data/res/interpolator/platformInterpolator.xml new file mode 100644 index 000000000000..bb7c3a96ebbf --- /dev/null +++ b/plugins/android/testData/sdk1.5/platforms/android-1.5/data/res/interpolator/platformInterpolator.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidAnimatorDomTest.java b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidAnimatorDomTest.java new file mode 100644 index 000000000000..a74fc7bc66c6 --- /dev/null +++ b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidAnimatorDomTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 org.jetbrains.android.dom; + +import com.android.sdklib.SdkConstants; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidAnimatorDomTest extends AndroidDomTest { + public AndroidAnimatorDomTest() { + super(false, "dom/animator"); + } + + @Override + protected String getPathToCopy(String testFileName) { + return "res/animator/" + testFileName; + } + + @Override + public void setUp() throws Exception { + super.setUp(); + myFixture.copyFileToProject(SdkConstants.FN_ANDROID_MANIFEST_XML, SdkConstants.FN_ANDROID_MANIFEST_XML); + } + + public void testRootCompletion() throws Throwable { + toTestCompletion("root.xml", "root_after.xml"); + } + + public void testHighlighting() throws Throwable { + doTestHighlighting("hl.xml"); + } + + public void testTagNames() throws Throwable { + toTestCompletion("tn.xml", "tn_after.xml"); + } + + public void testAttributeNames() throws Throwable { + toTestCompletion("an1.xml", "an1_after.xml"); + toTestCompletion("an2.xml", "an2_after.xml"); + } + + public void testAttributeValues() throws Throwable { + toTestCompletion("av.xml", "av_after.xml"); + } +}