c3f43d374928e26a8d40908a6d6a8e2cc40eac93
[idea/community.git] / platform / lang-impl / src / com / intellij / formatting / templateLanguages / TemplateLanguageBlock.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.formatting.templateLanguages;
17
18 import com.intellij.formatting.*;
19 import com.intellij.lang.ASTNode;
20 import com.intellij.openapi.util.TextRange;
21 import com.intellij.psi.codeStyle.CodeStyleSettings;
22 import com.intellij.psi.formatter.FormatterUtil;
23 import com.intellij.psi.formatter.common.AbstractBlock;
24 import com.intellij.psi.tree.IElementType;
25 import org.jetbrains.annotations.NotNull;
26 import org.jetbrains.annotations.Nullable;
27
28 import java.util.ArrayList;
29 import java.util.List;
30
31 /**
32  * @author Alexey Chmutov
33  *         Date: Jun 26, 2009
34  *         Time: 4:05:40 PM
35  */
36 public abstract class TemplateLanguageBlock extends AbstractBlock implements BlockWithParent {
37   private final TemplateLanguageBlockFactory myBlockFactory;
38   private final CodeStyleSettings mySettings;
39   private List<DataLanguageBlockWrapper> myForeignChildren;
40   private boolean myChildrenBuilt = false;
41   private BlockWithParent myParent;
42
43   protected TemplateLanguageBlock(@NotNull TemplateLanguageBlockFactory blockFactory, @NotNull CodeStyleSettings settings, 
44                                   @NotNull ASTNode node, @Nullable List<DataLanguageBlockWrapper> foreignChildren) {
45     this(node, null, null, blockFactory, settings, foreignChildren);
46   }
47   
48   protected TemplateLanguageBlock(@NotNull ASTNode node, @Nullable Wrap wrap, @Nullable Alignment alignment, 
49                                   @NotNull TemplateLanguageBlockFactory blockFactory,
50                                   @NotNull CodeStyleSettings settings,
51                                   @Nullable List<DataLanguageBlockWrapper> foreignChildren) {
52     super(node, wrap, alignment);
53     myBlockFactory = blockFactory;
54     myForeignChildren = foreignChildren;
55     mySettings = settings;
56   }
57
58   protected List<Block> buildChildren() {
59     myChildrenBuilt = true;
60     if (isLeaf()) {
61       return EMPTY;
62     }
63     final ArrayList<TemplateLanguageBlock> tlChildren = new ArrayList<TemplateLanguageBlock>(5);
64     for (ASTNode childNode = getNode().getFirstChildNode(); childNode != null; childNode = childNode.getTreeNext()) {
65       if (FormatterUtil.containsWhiteSpacesOnly(childNode)) continue;
66       if (shouldBuildBlockFor(childNode)) {
67         final TemplateLanguageBlock childBlock = myBlockFactory
68           .createTemplateLanguageBlock(childNode, createChildWrap(childNode), createChildAlignment(childNode), null, mySettings);
69         childBlock.setParent(this);
70         tlChildren.add(childBlock);
71       }
72     }
73     final List<Block> children = (List<Block>)(myForeignChildren == null ? tlChildren : BlockUtil.mergeBlocks(tlChildren, myForeignChildren));
74     //BlockUtil.printBlocks(getTextRange(), children);
75     return BlockUtil.setParent(children, this);
76   }
77
78   protected boolean shouldBuildBlockFor(ASTNode childNode) {
79     return childNode.getElementType() != getTemplateTextElementType() || noForeignChildren();
80   }
81
82   private boolean noForeignChildren() {
83     return (myForeignChildren == null || myForeignChildren.isEmpty());
84   }
85
86   void addForeignChild(@NotNull DataLanguageBlockWrapper foreignChild) {
87     initForeignChildren();
88     myForeignChildren.add(foreignChild);
89   }
90
91   void addForeignChildren(List<DataLanguageBlockWrapper> foreignChildren) {
92     initForeignChildren();
93     myForeignChildren.addAll(foreignChildren);
94   }
95
96   private void initForeignChildren() {
97     assert !myChildrenBuilt;
98     if (myForeignChildren == null) {
99       myForeignChildren = new ArrayList<DataLanguageBlockWrapper>(5);
100     }
101   }
102
103   @Nullable
104   public Spacing getSpacing(Block child1, Block child2) {
105     if (child1 instanceof DataLanguageBlockWrapper && child2 instanceof DataLanguageBlockWrapper) {
106       return ((DataLanguageBlockWrapper)child1).getRightHandSpacing((DataLanguageBlockWrapper)child2);
107     }
108     return null;
109   }
110
111   public boolean isLeaf() {
112     return noForeignChildren() && getNode().getFirstChildNode() == null;
113   }
114
115   protected abstract IElementType getTemplateTextElementType();
116
117   public BlockWithParent getParent() {
118     return myParent;
119   }
120
121   public void setParent(BlockWithParent newParent) {
122     myParent = newParent;
123   }
124
125   /**
126    * Checks if DataLanguageBlockFragmentWrapper must be created for the given text range.
127    * @param range The range to check.
128    * @return True by default.
129    */
130   public boolean isRequiredRange(TextRange range) {
131     return true;
132   }
133
134   protected Wrap createChildWrap(ASTNode child) {
135     return Wrap.createWrap(Wrap.NONE, false);
136   }
137
138   protected Alignment createChildAlignment(ASTNode child) {
139     return null;
140   }
141
142   public CodeStyleSettings getSettings() {
143     return mySettings;
144   }
145 }
146