Inspections - pass onTheFly into ProblemDescriptors & use it to create LAZY refs...
[fedora-idea.git] / plugins / java-i18n / src / com / intellij / codeInspection / i18n / I18nizeAction.java
blobb25c14e7b7325a4675789e8232a2590e59ff4242
1 /*
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.codeInspection.i18n;
18 import com.intellij.codeInsight.CodeInsightBundle;
19 import com.intellij.codeInsight.CodeInsightUtilBase;
20 import com.intellij.codeInsight.intention.impl.ConcatenationToMessageFormatAction;
21 import com.intellij.ide.fileTemplates.JavaTemplateUtil;
22 import com.intellij.lang.StdLanguages;
23 import com.intellij.lang.properties.psi.PropertiesFile;
24 import com.intellij.lang.properties.psi.PropertyCreationHandler;
25 import com.intellij.openapi.actionSystem.*;
26 import com.intellij.openapi.application.ApplicationManager;
27 import com.intellij.openapi.command.CommandProcessor;
28 import com.intellij.openapi.diagnostic.Logger;
29 import com.intellij.openapi.editor.Editor;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.util.Ref;
32 import com.intellij.openapi.util.TextRange;
33 import com.intellij.psi.*;
34 import com.intellij.psi.jsp.JspFile;
35 import com.intellij.psi.templateLanguages.OuterLanguageElement;
36 import com.intellij.psi.util.PsiTreeUtil;
37 import com.intellij.psi.xml.XmlTag;
38 import com.intellij.refactoring.util.CommonRefactoringUtil;
39 import com.intellij.util.IncorrectOperationException;
40 import org.jetbrains.annotations.Nullable;
42 import java.util.Collection;
44 public class I18nizeAction extends AnAction implements I18nQuickFixHandler{
45 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.i18n.I18nizeAction");
47 public void update(AnActionEvent e) {
48 boolean active = getHandler(e) != null;
49 if (ActionPlaces.isPopupPlace(e.getPlace())) {
50 e.getPresentation().setVisible(active);
52 else {
53 e.getPresentation().setEnabled(active);
57 @Nullable
58 public I18nQuickFixHandler getHandler(final AnActionEvent e) {
59 final Editor editor = getEditor(e);
60 if (editor == null) return null;
61 PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE);
62 if (psiFile == null) return null;
63 final PsiLiteralExpression literalExpression = getEnclosingStringLiteral(psiFile, editor);
64 TextRange range = getSelectedRange(getEditor(e), psiFile);
65 PsiElement element = psiFile.findElementAt(editor.getCaretModel().getOffset());
66 if (element == null) return null;
67 if (range != null && ConcatenationToMessageFormatAction.getEnclosingLiteralConcatenation(element) != null) {
68 return new I18nizeConcatenationQuickFix();
70 else if (literalExpression != null && range != null && literalExpression.getTextRange().contains(range)) {
71 return new I18nizeQuickFix();
73 else if (psiFile instanceof JspFile && range != null) {
74 return this;
76 else {
77 return null;
81 public void checkApplicability(final PsiFile psiFile, final Editor editor) throws IncorrectOperationException {
82 if (!canBeExtractedAway((JspFile)psiFile, editor)) {
83 throw new IncorrectOperationException(CodeInsightBundle.message("i18nize.jsp.error"));
87 public void performI18nization(final PsiFile psiFile,
88 final Editor editor,
89 PsiLiteralExpression literalExpression,
90 Collection<PropertiesFile> propertiesFiles,
91 String key, String value, String i18nizedText,
92 PsiExpression[] parameters,
93 final PropertyCreationHandler propertyCreationHandler) throws IncorrectOperationException {
94 Project project = psiFile.getProject();
95 TextRange selectedText = getSelectedRange(editor, psiFile);
96 if (selectedText == null) return;
97 propertyCreationHandler.createProperty(project, propertiesFiles, key, value, parameters);
98 editor.getDocument().replaceString(selectedText.getStartOffset(), selectedText.getEndOffset(), i18nizedText);
101 public static PsiLiteralExpression getEnclosingStringLiteral(final PsiFile psiFile, final Editor editor) {
102 PsiElement psiElement = psiFile.findElementAt(editor.getCaretModel().getOffset());
103 if (psiElement == null) return null;
104 PsiLiteralExpression expression = PsiTreeUtil.getParentOfType(psiElement, PsiLiteralExpression.class);
105 if (expression == null || !(expression.getValue() instanceof String)) return null;
106 return expression;
109 private static boolean canBeExtractedAway(final JspFile jspFile, final Editor editor) {
110 final TextRange selectedRange=getSelectedRange(editor, jspFile);
111 // must contain no or balanced tags only
112 // must not contain scriptlets or custom tags
113 final Ref<Boolean> result = new Ref<Boolean>(Boolean.TRUE);
114 PsiFile root = jspFile.getBaseLanguageRoot();
115 root.accept(new PsiRecursiveElementVisitor(){
116 @Override public void visitElement(PsiElement element) {
117 if (!result.get().booleanValue()) return;
118 TextRange elementRange = element.getTextRange();
119 if (elementRange.intersectsStrict(selectedRange)) {
120 // in JSPX base language root is a Jspx file itself
121 if (jspFile.getLanguage() != StdLanguages.JSPX && element instanceof OuterLanguageElement ||
123 element instanceof XmlTag
124 && !selectedRange.contains(elementRange)
125 && (!elementRange.contains(selectedRange) || !((XmlTag)element).getValue().getTextRange().contains(selectedRange))) {
126 result.set(Boolean.FALSE);
127 return;
130 super.visitElement(element);
133 return result.get().booleanValue();
136 @Nullable private static TextRange getSelectedRange(Editor editor, final PsiFile psiFile) {
137 if (editor == null) return null;
138 String selectedText = editor.getSelectionModel().getSelectedText();
139 if (selectedText != null) {
140 return new TextRange(editor.getSelectionModel().getSelectionStart(), editor.getSelectionModel().getSelectionEnd());
142 PsiElement psiElement = psiFile.findElementAt(editor.getCaretModel().getOffset());
143 if (psiElement==null || psiElement instanceof PsiWhiteSpace) return null;
144 return psiElement.getTextRange();
147 private static Editor getEditor(final AnActionEvent e) {
148 return PlatformDataKeys.EDITOR.getData(e.getDataContext());
151 public void actionPerformed(AnActionEvent e) {
152 final Editor editor = getEditor(e);
153 final Project project = editor.getProject();
154 final PsiFile psiFile = LangDataKeys.PSI_FILE.getData(e.getDataContext());
155 if (psiFile == null) return;
156 final I18nQuickFixHandler handler = getHandler(e);
157 if (handler == null) return;
158 try {
159 handler.checkApplicability(psiFile, editor);
161 catch (IncorrectOperationException ex) {
162 CommonRefactoringUtil.showErrorHint(project, editor, ex.getMessage(), CodeInsightBundle.message("i18nize.error.title"), null);
163 return;
166 final JavaI18nizeQuickFixDialog dialog = handler.createDialog(project, editor, psiFile);
167 if (dialog == null) return;
168 dialog.show();
169 if (!dialog.isOK()) return;
171 if (!CodeInsightUtilBase.prepareFileForWrite(psiFile)) return;
172 final Collection<PropertiesFile> propertiesFiles = dialog.getAllPropertiesFiles();
173 for (PropertiesFile file : propertiesFiles) {
174 if (!CodeInsightUtilBase.prepareFileForWrite(file)) return;
177 ApplicationManager.getApplication().runWriteAction(new Runnable(){
178 public void run() {
179 CommandProcessor.getInstance().executeCommand(project, new Runnable(){
180 public void run() {
181 try {
182 handler.performI18nization(psiFile, editor, dialog.getLiteralExpression(), propertiesFiles, dialog.getKey(), dialog.getValue(),
183 dialog.getI18nizedText(), dialog.getParameters(),
184 dialog.getPropertyCreationHandler());
186 catch (IncorrectOperationException e) {
187 LOG.error(e);
190 }, CodeInsightBundle.message("quickfix.i18n.command.name"),project);
195 public JavaI18nizeQuickFixDialog createDialog(final Project project, final Editor editor, final PsiFile psiFile) {
196 JspFile jspFile = (JspFile)psiFile;
198 TextRange selectedRange = getSelectedRange(editor, psiFile);
199 if (selectedRange == null) return null;
200 String text = selectedRange.substring(editor.getDocument().getText());
201 return new JavaI18nizeQuickFixDialog(project, jspFile, null, text, null, false, true){
202 protected String getTemplateName() {
203 return JavaTemplateUtil.TEMPLATE_I18NIZED_JSP_EXPRESSION;