2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.psi
.formatter
.xml
;
18 import com
.intellij
.formatting
.*;
19 import com
.intellij
.lang
.ASTNode
;
20 import com
.intellij
.openapi
.diagnostic
.Logger
;
21 import com
.intellij
.openapi
.util
.TextRange
;
22 import com
.intellij
.psi
.formatter
.common
.AbstractBlock
;
23 import com
.intellij
.psi
.impl
.source
.SourceTreeToPsiMap
;
24 import com
.intellij
.psi
.tree
.IElementType
;
25 import com
.intellij
.psi
.xml
.XmlElementType
;
26 import com
.intellij
.psi
.xml
.XmlTag
;
28 import java
.util
.List
;
31 public abstract class AbstractSyntheticBlock
implements Block
{
32 protected final Indent myIndent
;
33 protected final XmlFormattingPolicy myXmlFormattingPolicy
;
34 protected final ASTNode myEndTreeNode
;
35 protected final ASTNode myStartTreeNode
;
36 private final XmlTag myTag
;
38 public AbstractSyntheticBlock(List
<Block
> subBlocks
, Block parent
, XmlFormattingPolicy policy
, Indent indent
) {
39 myEndTreeNode
= getLastNode(subBlocks
);
40 myStartTreeNode
= getFirstNode(subBlocks
);
42 myXmlFormattingPolicy
= policy
;
43 myTag
= ((AbstractXmlBlock
)parent
).getTag();
46 private static final Logger LOG
= Logger
.getInstance("#com.intellij.psi.formatter.xml.AbstractSyntheticBlock");
48 private ASTNode
getFirstNode(final List
<Block
> subBlocks
) {
49 LOG
.assertTrue(!subBlocks
.isEmpty());
50 final Block firstBlock
= subBlocks
.get(0);
51 if (firstBlock
instanceof AbstractBlock
) {
52 return ((AbstractBlock
)firstBlock
).getNode();
54 return getFirstNode(firstBlock
.getSubBlocks());
58 private ASTNode
getLastNode(final List
<Block
> subBlocks
) {
59 LOG
.assertTrue(!subBlocks
.isEmpty());
60 final Block lastBlock
= subBlocks
.get(subBlocks
.size() - 1);
61 if (lastBlock
instanceof AbstractBlock
) {
62 return ((AbstractBlock
)lastBlock
).getNode();
64 return getLastNode(lastBlock
.getSubBlocks());
68 private boolean isEndOfTag() {
69 return myEndTreeNode
.getElementType() == XmlElementType
.XML_TAG_END
;
72 public Wrap
getWrap() {
76 public Indent
getIndent() {
80 public Alignment
getAlignment() {
84 protected static boolean isXmlTagName(final IElementType type1
, final IElementType type2
) {
85 if (type1
== XmlElementType
.XML_NAME
&& type2
== XmlElementType
.XML_TAG_END
) return true;
86 if (type1
== XmlElementType
.XML_NAME
&& type2
== XmlElementType
.XML_EMPTY_ELEMENT_END
) return true;
87 if (type1
== XmlElementType
.XML_ATTRIBUTE
&& type2
== XmlElementType
.XML_EMPTY_ELEMENT_END
) return true;
88 return type1
== XmlElementType
.XML_ATTRIBUTE
&& type2
== XmlElementType
.XML_TAG_END
;
91 public boolean endsWithText() {
92 return myEndTreeNode
.getElementType() == XmlElementType
.XML_TEXT
|| myEndTreeNode
.getElementType() == XmlElementType
.XML_DATA_CHARACTERS
;
95 public boolean isTagDescription() {
96 final ASTNode startTreeNode
= myStartTreeNode
;
97 return isTagDescription(startTreeNode
);
100 private static boolean isTagDescription(final ASTNode startTreeNode
) {
101 return startTreeNode
.getElementType() == XmlElementType
.XML_START_TAG_START
|| startTreeNode
.getElementType() == XmlElementType
.XML_END_TAG_START
;
104 public boolean startsWithText() {
105 return myStartTreeNode
.getElementType() == XmlElementType
.XML_TEXT
|| myStartTreeNode
.getElementType() == XmlElementType
.XML_DATA_CHARACTERS
;
108 public boolean endsWithTextElement() {
109 if (endsWithText()) return true;
110 if (isEndOfTag() && myXmlFormattingPolicy
.isTextElement(getTag())) return true;
111 return isTextTag(myEndTreeNode
);
114 protected XmlTag
getTag() {
118 public boolean startsWithTextElement() {
119 if (startsWithText()) return true;
120 if (isStartOfTag() && myXmlFormattingPolicy
.isTextElement(getTag())) return true;
121 return isTextTag(myStartTreeNode
);
124 private boolean isTextTag(final ASTNode treeNode
) {
125 return isXmlTag(treeNode
) && myXmlFormattingPolicy
.isTextElement((XmlTag
)SourceTreeToPsiMap
.treeElementToPsi(treeNode
));
128 private boolean isXmlTag(final ASTNode treeNode
) {
129 return (treeNode
.getPsi() instanceof XmlTag
);
132 private boolean isStartOfTag() {
133 return isTagDescription(myStartTreeNode
);
136 protected static TextRange
calculateTextRange(final List
<Block
> subBlocks
) {
137 return new TextRange(subBlocks
.get(0).getTextRange().getStartOffset(),
138 subBlocks
.get(subBlocks
.size()- 1).getTextRange().getEndOffset());
141 public boolean isIncomplete() {
142 return getSubBlocks().get(getSubBlocks().size() - 1).isIncomplete();
145 public boolean startsWithTag() {
146 return isXmlTag(myStartTreeNode
);
149 public XmlTag
getStartTag() {
150 return (XmlTag
)myStartTreeNode
.getPsi();
154 public boolean endsWithTag() {
155 return isXmlTag(myEndTreeNode
);
158 public boolean isJspTextBlock() {
162 public boolean isJspxTextBlock() {
166 public boolean isLeaf() {
170 public boolean startsWithCDATA() {
171 return isCDATA(myStartTreeNode
.getFirstChildNode());
174 private boolean isCDATA(final ASTNode node
) {
175 return node
!= null && node
.getElementType() == XmlElementType
.XML_CDATA
;
178 public boolean endsWithCDATA() {
179 return isCDATA(myStartTreeNode
.getLastChildNode());
182 public boolean insertLineFeedAfter() {
183 final List
<Block
> subBlocks
= getSubBlocks();
184 final Block lastBlock
= subBlocks
.get(subBlocks
.size() - 1);
185 if (lastBlock
instanceof XmlTagBlock
) {
186 return insertLineFeedAfter(((XmlTagBlock
)lastBlock
).getTag());
188 if (endsWithText()) {
189 return insertLineFeedAfter(myTag
);
194 protected boolean insertLineFeedAfter(final XmlTag tag
) {
195 return myXmlFormattingPolicy
.getWrappingTypeForTagBegin(tag
) == WrapType
.ALWAYS
;