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
);
53 e
.getPresentation().setEnabled(active
);
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) {
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
,
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;
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
);
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;
159 handler
.checkApplicability(psiFile
, editor
);
161 catch (IncorrectOperationException ex
) {
162 CommonRefactoringUtil
.showErrorHint(project
, editor
, ex
.getMessage(), CodeInsightBundle
.message("i18nize.error.title"), null);
166 final JavaI18nizeQuickFixDialog dialog
= handler
.createDialog(project
, editor
, psiFile
);
167 if (dialog
== null) return;
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(){
179 CommandProcessor
.getInstance().executeCommand(project
, new Runnable(){
182 handler
.performI18nization(psiFile
, editor
, dialog
.getLiteralExpression(), propertiesFiles
, dialog
.getKey(), dialog
.getValue(),
183 dialog
.getI18nizedText(), dialog
.getParameters(),
184 dialog
.getPropertyCreationHandler());
186 catch (IncorrectOperationException 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
;