/* * Copyright 2000-2010 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.SdkConstants; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.meta.PsiPresentableMetaData; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlTag; import com.intellij.util.xml.DomElement; import com.intellij.util.xml.DomManager; import com.intellij.xml.XmlAttributeDescriptor; import com.intellij.xml.XmlElementDescriptor; import com.intellij.xml.XmlElementsGroup; import com.intellij.xml.XmlNSDescriptor; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.SimpleClassMapConstructor; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; /** * Created by IntelliJ IDEA. * User: Eugene.Kudelevsky * Date: Sep 4, 2009 * Time: 7:34:33 PM * To change this template use File | Settings | File Templates. */ public class AndroidXmlTagDescriptor implements XmlElementDescriptor, PsiPresentableMetaData { private final XmlElementDescriptor myParentDescriptor; private final PsiClass myDeclarationClass; private final Icon myIcon; private final String myBaseClassName; public AndroidXmlTagDescriptor(@Nullable PsiClass declarationClass, @NotNull XmlElementDescriptor parentDescriptor, @Nullable String baseClassName, @Nullable Icon icon) { myParentDescriptor = parentDescriptor; myDeclarationClass = declarationClass; myIcon = icon; myBaseClassName = baseClassName; } @Override public String getQualifiedName() { return myParentDescriptor.getQualifiedName(); } @Override public String getDefaultName() { return myParentDescriptor.getDefaultName(); } @Override public XmlElementDescriptor[] getElementsDescriptors(XmlTag context) { final XmlElementDescriptor[] descriptors = myParentDescriptor.getElementsDescriptors(context); if (myBaseClassName == null || context == null) { return descriptors; } final AndroidFacet facet = AndroidFacet.getInstance(context); if (facet == null) { return descriptors; } final XmlElementDescriptor[] androidDescriptors = new XmlElementDescriptor[descriptors.length]; final DomElement domElement = DomManager.getDomManager(context.getProject()).getDomElement(context); final PsiClass baseClass = JavaPsiFacade.getInstance(context.getProject()).findClass( myBaseClassName, facet.getModule().getModuleWithLibrariesScope()); for (int i = 0; i < descriptors.length; i++) { final XmlElementDescriptor descriptor = descriptors[i]; final String tagName = descriptor.getName(); final PsiClass aClass = tagName != null && baseClass != null ? SimpleClassMapConstructor.findClassByTagName(facet, tagName, baseClass) : null; final Icon icon = AndroidDomElementDescriptorProvider.getIconForTag(tagName, domElement); androidDescriptors[i] = new AndroidXmlTagDescriptor(aClass, descriptor, myBaseClassName, icon); } return androidDescriptors; } @Override public XmlElementDescriptor getElementDescriptor(XmlTag childTag, XmlTag contextTag) { final XmlElementDescriptor descriptor = myParentDescriptor.getElementDescriptor(childTag, contextTag); if (descriptor != null) { return descriptor; } final XmlNSDescriptor nsDescriptor = getNSDescriptor(); return nsDescriptor != null ? new AndroidAnyTagDescriptor(nsDescriptor) : null; } @Override public XmlAttributeDescriptor[] getAttributesDescriptors(@Nullable XmlTag context) { final XmlAttributeDescriptor[] descriptors = myParentDescriptor.getAttributesDescriptors(context); int layoutWidthIndex = -1; int layoutHeightIndex = -1; for (int i = 0; i < descriptors.length; i++) { final String name = descriptors[i].getName(); if ("layout_width".equals(name)) { layoutWidthIndex = i; } else if ("layout_height".equals(name)) { layoutHeightIndex = i; } } if (layoutWidthIndex < 0 ||layoutHeightIndex < 0 || layoutWidthIndex < layoutHeightIndex) { return descriptors; } final List<XmlAttributeDescriptor> newDescriptors = new ArrayList<XmlAttributeDescriptor>(Arrays.asList(descriptors)); final XmlAttributeDescriptor layoutWidthDescriptor = newDescriptors.remove(layoutWidthIndex); newDescriptors.add(layoutHeightIndex, layoutWidthDescriptor); return newDescriptors.toArray(new XmlAttributeDescriptor[newDescriptors.size()]); } @Override public XmlAttributeDescriptor getAttributeDescriptor(@NonNls String attributeName, @Nullable XmlTag context) { final XmlAttributeDescriptor descriptor = myParentDescriptor.getAttributeDescriptor(attributeName, context); return descriptor != null ? descriptor : new AndroidAnyAttributeDescriptor(attributeName); } @Override public XmlAttributeDescriptor getAttributeDescriptor(XmlAttribute attribute) { final XmlAttributeDescriptor descriptor = myParentDescriptor.getAttributeDescriptor(attribute); return descriptor != null ? descriptor : new AndroidAnyAttributeDescriptor(attribute.getName()); } @Override public XmlNSDescriptor getNSDescriptor() { return myParentDescriptor.getNSDescriptor(); } @Override public XmlElementsGroup getTopGroup() { return null; } @Override public int getContentType() { if (myDeclarationClass != null) { final GlobalSearchScope scope = myDeclarationClass.getResolveScope(); final JavaPsiFacade facade = JavaPsiFacade.getInstance(myDeclarationClass.getProject()); final PsiClass view = facade.findClass(SdkConstants.CLASS_VIEW, scope); if (view != null && myDeclarationClass.isInheritor(view, true)) { final PsiClass viewGroup = facade.findClass(SdkConstants.CLASS_VIEWGROUP, scope); if (viewGroup != null) { return myDeclarationClass.isInheritor(viewGroup, true) ? CONTENT_TYPE_MIXED : CONTENT_TYPE_EMPTY; } } } return myParentDescriptor.getContentType(); } @Override public String getDefaultValue() { return null; } @Override public PsiElement getDeclaration() { return myDeclarationClass != null ? myDeclarationClass : myParentDescriptor.getDeclaration(); } @Override public String getName(PsiElement context) { return getDefaultName(); } @Override public String getName() { return myParentDescriptor.getName(); } @Override public void init(PsiElement element) { myParentDescriptor.init(element); } @Override public Object[] getDependences() { return myParentDescriptor.getDependences(); } @Override public String getTypeName() { return null; } @Nullable @Override public Icon getIcon() { return myIcon; } }