2 * Copyright 2000-2010 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
.codeInspection
.i18n
.folding
;
18 import com
.intellij
.codeInsight
.AnnotationUtil
;
19 import com
.intellij
.codeInsight
.folding
.JavaCodeFoldingSettings
;
20 import com
.intellij
.codeInspection
.i18n
.JavaI18nUtil
;
21 import com
.intellij
.lang
.ASTNode
;
22 import com
.intellij
.lang
.StdLanguages
;
23 import com
.intellij
.lang
.folding
.FoldingBuilderEx
;
24 import com
.intellij
.lang
.folding
.FoldingDescriptor
;
25 import com
.intellij
.lang
.properties
.psi
.Property
;
26 import com
.intellij
.openapi
.editor
.Document
;
27 import com
.intellij
.psi
.*;
28 import com
.intellij
.psi
.impl
.JavaConstantExpressionEvaluator
;
29 import com
.intellij
.psi
.impl
.source
.SourceTreeToPsiMap
;
30 import com
.intellij
.util
.containers
.ContainerUtil
;
31 import org
.jetbrains
.annotations
.NotNull
;
36 * @author Konstantin Bulenkov
38 public class PropertyFoldingBuilder
extends FoldingBuilderEx
{
39 private static final int FOLD_MAX_LENGTH
= 50;
42 public FoldingDescriptor
[] buildFoldRegions(@NotNull PsiElement element
, @NotNull Document document
, boolean quick
) {
43 if (!(element
instanceof PsiJavaFile
) || quick
|| !isFoldingsOn()) {
44 return FoldingDescriptor
.EMPTY
;
46 final PsiJavaFile file
= (PsiJavaFile
) element
;
47 final List
<FoldingDescriptor
> result
= new ArrayList
<FoldingDescriptor
>();
48 boolean hasJsp
= ContainerUtil
.intersects(Arrays
.asList(StdLanguages
.JSP
, StdLanguages
.JSPX
), file
.getViewProvider().getLanguages());
49 //hack here because JspFile PSI elements are not threaded correctly via nextSibling/prevSibling
50 file
.accept(hasJsp ?
new JavaRecursiveElementVisitor() {
52 public void visitLiteralExpression(PsiLiteralExpression expression
) {
53 checkLiteral(expression
, result
);
55 } : new JavaRecursiveElementWalkingVisitor() {
57 public void visitLiteralExpression(PsiLiteralExpression expression
) {
58 checkLiteral(expression
, result
);
62 return result
.toArray(new FoldingDescriptor
[result
.size()]);
65 private static boolean isFoldingsOn() {
66 return JavaCodeFoldingSettings
.getInstance().isCollapseI18nMessages();
69 private static void checkLiteral(PsiLiteralExpression expression
, List
<FoldingDescriptor
> result
) {
70 if (isI18nProperty(expression
)) {
71 final String msg
= getI18nMessage(expression
);
73 final PsiElement parent
= expression
.getParent();
74 if (!msg
.equals(expression
.getText()) &&
75 parent
instanceof PsiExpressionList
&&
76 ((PsiExpressionList
)parent
).getExpressions()[0] == expression
) {
77 final PsiExpressionList expressions
= (PsiExpressionList
)parent
;
78 final int count
= JavaI18nUtil
.getPropertyValueParamsMaxCount(expression
);
79 final PsiExpression
[] args
= expressions
.getExpressions();
80 if (args
.length
== 1 + count
&& parent
.getParent() instanceof PsiMethodCallExpression
) {
82 for (int i
= 1; i
< count
+ 1; i
++) {
83 Object value
= JavaConstantExpressionEvaluator
.computeConstantExpression(args
[i
], false);
85 if (!(args
[i
] instanceof PsiReferenceExpression
)) {
92 result
.add(new FoldingDescriptor(parent
.getParent(), parent
.getParent().getTextRange()));
98 result
.add(new FoldingDescriptor(expression
, expression
.getTextRange()));
103 public String
getPlaceholderText(@NotNull ASTNode node
) {
104 final PsiElement element
= SourceTreeToPsiMap
.treeElementToPsi(node
);
105 if (element
instanceof PsiLiteralExpression
) {
106 return getI18nMessage((PsiLiteralExpression
)element
);
107 } else if (element
instanceof PsiMethodCallExpression
) {
108 return formatMethodCallExpression((PsiMethodCallExpression
)element
);
110 return element
.getText();
113 private static String
formatMethodCallExpression(PsiMethodCallExpression methodCallExpression
) {
114 final PsiExpression
[] args
= methodCallExpression
.getArgumentList().getExpressions();
116 && args
[0] instanceof PsiLiteralExpression
117 && isI18nProperty((PsiLiteralExpression
)args
[0])) {
118 final int count
= JavaI18nUtil
.getPropertyValueParamsMaxCount((PsiLiteralExpression
)args
[0]);
119 if (args
.length
== 1 + count
) {
120 String text
= getI18nMessage((PsiLiteralExpression
)args
[0]);
121 for (int i
= 1; i
< count
+ 1; i
++) {
122 Object value
= JavaConstantExpressionEvaluator
.computeConstantExpression(args
[i
], false);
124 if (args
[i
] instanceof PsiReferenceExpression
) {
125 value
= "{" + args
[i
].getText() + "}";
132 text
= text
.replace("{" + (i
- 1) + "}", value
.toString());
135 if (!text
.equals(methodCallExpression
.getText())) {
136 text
= text
.replace("''", "'");
138 return text
.length() > FOLD_MAX_LENGTH ? text
.substring(0, FOLD_MAX_LENGTH
- 3) + "..." : text
;
143 return methodCallExpression
.getText();
146 private static String
getI18nMessage(PsiLiteralExpression literal
) {
147 if (isI18nProperty(literal
)) {
148 final PsiReference
[] references
= literal
.getReferences();
149 for (PsiReference reference
: references
) {
150 if (reference
instanceof PsiPolyVariantReference
) {
151 final ResolveResult
[] results
= ((PsiPolyVariantReference
)reference
).multiResolve(false);
152 for (ResolveResult result
: results
) {
153 final PsiElement element
= result
.getElement();
154 if (element
instanceof Property
) {
155 return "\"" + ((Property
)element
).getValue() + "\"";
159 final PsiElement element
= reference
.resolve();
160 if (element
instanceof Property
) {
161 return "\"" + ((Property
)element
).getValue() + "\"";
166 return literal
.getText();
169 public boolean isCollapsedByDefault(@NotNull ASTNode node
) {
170 return isFoldingsOn();
174 public static boolean isI18nProperty(PsiLiteralExpression expr
) {
175 if (! isStringLiteral(expr
)) return false;
177 final Map
<String
, Object
> annotationParams
= new HashMap
<String
, Object
>();
178 annotationParams
.put(AnnotationUtil
.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER
, null);
179 return JavaI18nUtil
.mustBePropertyKey(expr
, annotationParams
);
182 private static boolean isStringLiteral(PsiLiteralExpression expr
) {
184 if (expr
== null || (text
= expr
.getText()) == null) return false;
185 return text
.startsWith("\"") && text
.endsWith("\"") && text
.length() > 2;