ComponentWithBrowseButton - optional remove listener on hide
[fedora-idea.git] / plugins / java-i18n / src / com / intellij / codeInspection / i18n / folding / PropertyFoldingBuilder.java
blob8fe59ac0221bd8287355684adbb1a9706f3c85f9
1 /*
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;
33 import java.util.*;
35 /**
36 * @author Konstantin Bulenkov
38 public class PropertyFoldingBuilder extends FoldingBuilderEx {
39 private static final int FOLD_MAX_LENGTH = 50;
41 @NotNull
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() {
51 @Override
52 public void visitLiteralExpression(PsiLiteralExpression expression) {
53 checkLiteral(expression, result);
55 } : new JavaRecursiveElementWalkingVisitor() {
56 @Override
57 public void visitLiteralExpression(PsiLiteralExpression expression) {
58 checkLiteral(expression, result);
60 });
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) {
81 boolean ok = true;
82 for (int i = 1; i < count + 1; i++) {
83 Object value = JavaConstantExpressionEvaluator.computeConstantExpression(args[i], false);
84 if (value == null) {
85 if (!(args[i] instanceof PsiReferenceExpression)) {
86 ok = false;
87 break;
91 if (ok) {
92 result.add(new FoldingDescriptor(parent.getParent(), parent.getParent().getTextRange()));
93 return;
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();
115 if (args.length > 0
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);
123 if (value == null) {
124 if (args[i] instanceof PsiReferenceExpression) {
125 value = "{" + args[i].getText() + "}";
127 else {
128 text = null;
129 break;
132 text = text.replace("{" + (i - 1) + "}", value.toString());
134 if (text != null) {
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() + "\"";
158 } else {
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) {
183 final String text;
184 if (expr == null || (text = expr.getText()) == null) return false;
185 return text.startsWith("\"") && text.endsWith("\"") && text.length() > 2;