package org.jetbrains.android.formatter; import com.intellij.formatting.FormattingDocumentModel; import com.intellij.formatting.WrapType; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.formatter.FormatterUtil; import com.intellij.psi.formatter.xml.XmlPolicy; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlTag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * @author Eugene.Kudelevsky */ public class AndroidXmlPolicy extends XmlPolicy { private final AndroidXmlCodeStyleSettings.MySettings myCustomSettings; public AndroidXmlPolicy(CodeStyleSettings settings, AndroidXmlCodeStyleSettings.MySettings customSettings, FormattingDocumentModel documentModel) { super(settings, documentModel); myCustomSettings = customSettings; } @Override public WrapType getWrappingTypeForTagBegin(XmlTag tag) { final PsiElement element = getNextSiblingElement(tag); if (element instanceof XmlTag && insertLineBreakBeforeTag((XmlTag)element)) { return WrapType.NORMAL; } return super.getWrappingTypeForTagBegin(tag); } @Override public int getAttributesWrap() { return myCustomSettings.WRAP_ATTRIBUTES; } @Override public boolean insertLineBreakBeforeFirstAttribute(XmlAttribute attribute) { if (!myCustomSettings.INSERT_LINE_BREAK_BEFORE_FIRST_ATTRIBUTE || attribute.isNamespaceDeclaration()) { return false; } return attribute.getParent().getAttributes().length > 1; } @Override public boolean insertLineBreakAfterLastAttribute(XmlAttribute attribute) { if (!myCustomSettings.INSERT_LINE_BREAK_AFTER_LAST_ATTRIBUTE) { return false; } return attribute.getParent().getAttributes().length > 1; } @Nullable protected static PsiElement getPrevSiblingElement(@NotNull PsiElement element) { final PsiElement prev = element.getPrevSibling(); ASTNode prevNode = SourceTreeToPsiMap.psiElementToTree(prev); while (prevNode != null && FormatterUtil.containsWhiteSpacesOnly(prevNode)) { prevNode = prevNode.getTreePrev(); } return SourceTreeToPsiMap.treeElementToPsi(prevNode); } @Nullable protected static PsiElement getNextSiblingElement(@NotNull PsiElement element) { final PsiElement next = element.getNextSibling(); ASTNode nextNode = SourceTreeToPsiMap.psiElementToTree(next); while (nextNode != null && FormatterUtil.containsWhiteSpacesOnly(nextNode)) { nextNode = nextNode.getTreeNext(); } return SourceTreeToPsiMap.treeElementToPsi(nextNode); } }