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
.java
;
18 import com
.intellij
.formatting
.*;
19 import com
.intellij
.lang
.ASTNode
;
20 import com
.intellij
.psi
.codeStyle
.CodeStyleSettings
;
21 import com
.intellij
.psi
.formatter
.FormatterUtil
;
22 import com
.intellij
.psi
.impl
.source
.tree
.ElementType
;
23 import com
.intellij
.psi
.impl
.source
.tree
.JavaDocElementType
;
24 import com
.intellij
.psi
.impl
.source
.tree
.StdTokenSets
;
25 import com
.intellij
.psi
.tree
.IElementType
;
26 import org
.jetbrains
.annotations
.NotNull
;
28 import java
.util
.ArrayList
;
29 import java
.util
.List
;
31 public class BlockContainingJavaBlock
extends AbstractJavaBlock
{
33 private final static int BEFORE_FIRST
= 0;
34 private final static int BEFORE_BLOCK
= 1;
35 private final static int AFTER_ELSE
= 2;
37 private final List
<Indent
> myIndentsBefore
= new ArrayList
<Indent
>();
39 public BlockContainingJavaBlock(final ASTNode node
, final Wrap wrap
, final Alignment alignment
, final Indent indent
, CodeStyleSettings settings
) {
40 super(node
, wrap
, alignment
, indent
, settings
);
42 protected List
<Block
> buildChildren() {
43 final ArrayList
<Block
> result
= new ArrayList
<Block
>();
44 Alignment childAlignment
= createChildAlignment();
45 Wrap childWrap
= createChildWrap();
47 buildChildren(result
, childAlignment
, childWrap
);
53 private void buildChildren(final ArrayList
<Block
> result
, final Alignment childAlignment
, final Wrap childWrap
) {
54 ASTNode child
= myNode
.getFirstChildNode();
56 int state
= BEFORE_FIRST
;
58 while (child
!= null) {
59 if (!FormatterUtil
.containsWhiteSpacesOnly(child
) && child
.getTextLength() > 0){
60 final Indent indent
= calcIndent(child
, state
);
61 myIndentsBefore
.add(calcIndentBefore(child
, state
));
62 state
= calcNewState(child
, state
);
63 child
= processChild(result
, child
, childAlignment
, childWrap
, indent
);
64 for (int i
= myIndentsBefore
.size(); i
< result
.size(); i
++) {
65 myIndentsBefore
.add(Indent
.getContinuationIndent());
69 child
= child
.getTreeNext();
74 private int calcNewState(final ASTNode child
, final int state
) {
75 if (state
== BEFORE_FIRST
) {
76 if (child
.getElementType() == ElementType
.ELSE_KEYWORD
) {
79 if (StdTokenSets
.COMMENT_BIT_SET
.contains(child
.getElementType())) {
82 if (child
.getElementType() == ElementType
.CATCH_SECTION
) {
85 } else if (state
== BEFORE_BLOCK
){
86 if (child
.getElementType() == ElementType
.ELSE_KEYWORD
) {
89 if (child
.getElementType() == ElementType
.BLOCK_STATEMENT
) {
92 if (child
.getElementType() == ElementType
.CODE_BLOCK
) {
100 private Indent
calcIndent(final ASTNode child
, final int state
) {
101 if (state
== AFTER_ELSE
&& child
.getElementType() == ElementType
.IF_STATEMENT
) {
102 if (!mySettings
.SPECIAL_ELSE_IF_TREATMENT
) {
103 return getCodeBlockInternalIndent(1);
105 return getCodeBlockExternalIndent();
108 if (isSimpleStatement(child
)){
109 return createNormalIndent(1);
111 if (child
.getElementType() == ElementType
.ELSE_KEYWORD
)
112 return Indent
.getNoneIndent();
113 if (state
== BEFORE_FIRST
) {
114 return Indent
.getNoneIndent();
116 else if (child
.getElementType() == ElementType
.WHILE_KEYWORD
) {
117 return Indent
.getNoneIndent();
120 if (isPartOfCodeBlock(child
)) {
121 return getCodeBlockExternalIndent();
123 else if (isSimpleStatement(child
)){
124 return getCodeBlockInternalIndent(1);
126 else if (StdTokenSets
.COMMENT_BIT_SET
.contains(child
.getElementType())) {
127 return getCodeBlockInternalIndent(1);
130 return Indent
.getContinuationIndent();
135 private Indent
calcIndentBefore(final ASTNode child
, final int state
) {
136 if (state
== AFTER_ELSE
) {
137 if (!mySettings
.SPECIAL_ELSE_IF_TREATMENT
) {
138 return getCodeBlockInternalIndent(1);
140 return getCodeBlockExternalIndent();
143 if (state
== BEFORE_BLOCK
&& (isSimpleStatement(child
) || child
.getElementType() == ElementType
.BLOCK_STATEMENT
)){
144 return getCodeBlockInternalIndent(0);
146 if (state
== BEFORE_FIRST
) {
147 return getCodeBlockExternalIndent();
149 if (child
.getElementType() == ElementType
.ELSE_KEYWORD
)
150 return getCodeBlockExternalIndent();
152 return Indent
.getContinuationIndent();
155 private boolean isSimpleStatement(final ASTNode child
) {
156 if (child
.getElementType() == ElementType
.BLOCK_STATEMENT
) return false;
157 if (!ElementType
.STATEMENT_BIT_SET
.contains(child
.getElementType())) return false;
158 return isStatement(child
, child
.getTreeParent());
161 private boolean isPartOfCodeBlock(final ASTNode child
) {
162 if (child
== null) return false;
163 if (child
.getElementType() == ElementType
.BLOCK_STATEMENT
) return true;
164 if (child
.getElementType() == ElementType
.CODE_BLOCK
) return true;
166 if (FormatterUtil
.containsWhiteSpacesOnly(child
)) return isPartOfCodeBlock(child
.getTreeNext());
167 if (child
.getElementType() == ElementType
.END_OF_LINE_COMMENT
) return isPartOfCodeBlock(child
.getTreeNext());
168 return child
.getElementType() == JavaDocElementType
.DOC_COMMENT
;
171 protected Wrap
getReservedWrap(final IElementType elementType
) {
175 protected void setReservedWrap(final Wrap reservedWrap
, final IElementType operationType
) {
179 public ChildAttributes
getChildAttributes(final int newChildIndex
) {
180 if (isAfter(newChildIndex
, new IElementType
[]{JavaDocElementType
.DOC_COMMENT
})) {
181 return new ChildAttributes(Indent
.getNoneIndent(), null);
184 if (myNode
.getElementType() == ElementType
.FOR_STATEMENT
&& mySettings
.ALIGN_MULTILINE_FOR
&& isInsideForParens(newChildIndex
)) {
185 Alignment prev
= getUsedAlignment(newChildIndex
);
187 return new ChildAttributes(null, prev
);
191 if (newChildIndex
== 0) {
192 return new ChildAttributes(getCodeBlockExternalIndent(), null);
195 if (newChildIndex
== getSubBlocks().size()) {
196 return new ChildAttributes(getCodeBlockChildExternalIndent(newChildIndex
), null);
199 return new ChildAttributes(myIndentsBefore
.get(newChildIndex
), null);
203 private boolean isInsideForParens(final int newChildIndex
) {
204 final List
<Block
> subBlocks
= getSubBlocks();
205 for (int i
= 0; i
< newChildIndex
; i
++) {
206 if (i
>= subBlocks
.size()) return false;
207 final Block block
= subBlocks
.get(i
);
208 if (block
instanceof LeafBlock
) {
209 if (((LeafBlock
)block
).getTreeNode().getElementType() == ElementType
.RPARENTH
) return false;