don't use property foldings if user unset collapse by default
[fedora-idea.git] / plugins / java-i18n / src / com / intellij / codeInspection / i18n / folding / PropertyFoldingBuilder.java
blob8c0f7ca0976b950ccb6c323be0e13c7c5eecdbef
1 package com.intellij.codeInspection.i18n.folding;
3 import com.intellij.codeInsight.AnnotationUtil;
4 import com.intellij.codeInsight.folding.JavaCodeFoldingSettings;
5 import com.intellij.codeInspection.i18n.JavaI18nUtil;
6 import com.intellij.lang.ASTNode;
7 import com.intellij.lang.StdLanguages;
8 import com.intellij.lang.folding.FoldingBuilderEx;
9 import com.intellij.lang.folding.FoldingDescriptor;
10 import com.intellij.lang.properties.psi.Property;
11 import com.intellij.openapi.editor.Document;
12 import com.intellij.psi.*;
13 import com.intellij.psi.impl.JavaConstantExpressionEvaluator;
14 import com.intellij.psi.impl.source.SourceTreeToPsiMap;
15 import com.intellij.util.containers.ContainerUtil;
16 import org.jetbrains.annotations.NotNull;
18 import java.util.*;
20 /**
21 * @author Konstantin Bulenkov
23 public class PropertyFoldingBuilder extends FoldingBuilderEx {
25 @NotNull
26 public FoldingDescriptor[] buildFoldRegions(@NotNull PsiElement element, @NotNull Document document, boolean quick) {
27 if (!(element instanceof PsiJavaFile) || quick || !isFoldingsOn()) {
28 return FoldingDescriptor.EMPTY;
30 final PsiJavaFile file = (PsiJavaFile) element;
31 final List<FoldingDescriptor> result = new ArrayList<FoldingDescriptor>();
32 boolean hasJsp = ContainerUtil.intersects(Arrays.asList(StdLanguages.JSP, StdLanguages.JSPX), file.getViewProvider().getLanguages());
33 //hack here because JspFile PSI elements are not threaded correctly via nextSibling/prevSibling
34 file.accept(hasJsp ? new JavaRecursiveElementVisitor() {
35 @Override
36 public void visitLiteralExpression(PsiLiteralExpression expression) {
37 checkLiteral(expression, result);
39 } : new JavaRecursiveElementWalkingVisitor() {
40 @Override
41 public void visitLiteralExpression(PsiLiteralExpression expression) {
42 checkLiteral(expression, result);
44 });
46 return result.toArray(new FoldingDescriptor[result.size()]);
49 private static boolean isFoldingsOn() {
50 return JavaCodeFoldingSettings.getInstance().isCollapseI18nMessages();
53 private static void checkLiteral(PsiLiteralExpression expression, List<FoldingDescriptor> result) {
54 if (isI18nProperty(expression)) {
55 final String msg = getI18nMessage(expression);
57 final PsiElement parent = expression.getParent();
58 if (!msg.equals(expression.getText()) &&
59 parent instanceof PsiExpressionList &&
60 ((PsiExpressionList)parent).getExpressions()[0] == expression) {
61 final PsiExpressionList expressions = (PsiExpressionList)parent;
62 final int count = JavaI18nUtil.getPropertyValueParamsMaxCount(expression);
63 final PsiExpression[] args = expressions.getExpressions();
64 if (args.length == 1 + count && parent.getParent() instanceof PsiMethodCallExpression) {
65 boolean ok = true;
66 for (int i = 1; i < count + 1; i++) {
67 Object value = JavaConstantExpressionEvaluator.computeConstantExpression(args[i], false);
68 if (value == null) {
69 if (!(args[i] instanceof PsiReferenceExpression)) {
70 ok = false;
71 break;
75 if (ok) {
76 result.add(new FoldingDescriptor(parent.getParent(), parent.getParent().getTextRange()));
77 return;
82 result.add(new FoldingDescriptor(expression, expression.getTextRange()));
87 public String getPlaceholderText(@NotNull ASTNode node) {
88 final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(node);
89 if (element instanceof PsiLiteralExpression) {
90 return getI18nMessage((PsiLiteralExpression)element);
91 } else if (element instanceof PsiMethodCallExpression) {
92 return formatMethodCallExpression((PsiMethodCallExpression)element);
94 return element.getText();
97 private static String formatMethodCallExpression(PsiMethodCallExpression methodCallExpression) {
98 final PsiExpression[] args = methodCallExpression.getArgumentList().getExpressions();
99 if (args.length > 0
100 && args[0] instanceof PsiLiteralExpression
101 && isI18nProperty((PsiLiteralExpression)args[0])) {
102 final int count = JavaI18nUtil.getPropertyValueParamsMaxCount((PsiLiteralExpression)args[0]);
103 if (args.length == 1 + count) {
104 String text = getI18nMessage((PsiLiteralExpression)args[0]);
105 for (int i = 1; i < count + 1; i++) {
106 Object value = JavaConstantExpressionEvaluator.computeConstantExpression(args[i], false);
107 if (value == null) {
108 if (args[i] instanceof PsiReferenceExpression) {
109 value = "{" + args[i].getText() + "}";
111 else {
112 text = null;
113 break;
116 text = text.replace("{" + (i - 1) + "}", value.toString());
118 if (text != null) {
119 if (!text.equals(methodCallExpression.getText())) {
120 text = text.replace("''", "'");
122 return text;
127 return methodCallExpression.getText();
130 private static String getI18nMessage(PsiLiteralExpression literal) {
131 if (isI18nProperty(literal)) {
132 final PsiReference[] references = literal.getReferences();
133 for (PsiReference reference : references) {
134 if (reference instanceof PsiPolyVariantReference) {
135 final ResolveResult[] results = ((PsiPolyVariantReference)reference).multiResolve(false);
136 for (ResolveResult result : results) {
137 final PsiElement element = result.getElement();
138 if (element instanceof Property) {
139 return "\"" + ((Property)element).getValue() + "\"";
142 } else {
143 final PsiElement element = reference.resolve();
144 if (element instanceof Property) {
145 return "\"" + ((Property)element).getValue() + "\"";
150 return literal.getText();
153 public boolean isCollapsedByDefault(@NotNull ASTNode node) {
154 return isFoldingsOn();
158 public static boolean isI18nProperty(PsiLiteralExpression expr) {
159 if (! isStringLiteral(expr)) return false;
161 final Map<String, Object> annotationParams = new HashMap<String, Object>();
162 annotationParams.put(AnnotationUtil.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER, null);
163 return JavaI18nUtil.mustBePropertyKey(expr, annotationParams);
166 private static boolean isStringLiteral(PsiLiteralExpression expr) {
167 final String text;
168 if (expr == null || (text = expr.getText()) == null) return false;
169 return text.startsWith("\"") && text.endsWith("\"") && text.length() > 2;