blob: 44514c9dadf66805356436be272b4b53721423e4 [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author cdr
*/
package com.intellij.codeInspection.i18n;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.lang.properties.psi.PropertyCreationHandler;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public class I18nizeQuickFix implements LocalQuickFix, I18nQuickFixHandler {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.i18n.I18nizeQuickFix");
private TextRange mySelectionRange;
@Override
public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
// do it later because the fix was called inside writeAction
ApplicationManager.getApplication().invokeLater(new Runnable(){
@Override
public void run() {
doFix(descriptor, project);
}
});
}
@Override
@NotNull
public String getName() {
return CodeInsightBundle.message("inspection.i18n.quickfix");
}
@Override
@NotNull
public String getFamilyName() {
return getName();
}
@Override
public void checkApplicability(final PsiFile psiFile, final Editor editor) throws IncorrectOperationException {
PsiLiteralExpression literalExpression = I18nizeAction.getEnclosingStringLiteral(psiFile, editor);
if (literalExpression != null) {
SelectionModel selectionModel = editor.getSelectionModel();
if (!selectionModel.hasSelection()) return;
int start = selectionModel.getSelectionStart();
int end = selectionModel.getSelectionEnd();
TextRange textRange = literalExpression.getTextRange();
if (textRange.contains(start) && textRange.contains(end)) {
mySelectionRange = new TextRange(start, end);
return;
}
}
String message = CodeInsightBundle.message("i18nize.error.message");
throw new IncorrectOperationException(message);
}
@Override
public void performI18nization(final PsiFile psiFile,
final Editor editor,
PsiLiteralExpression literalExpression,
Collection<PropertiesFile> propertiesFiles,
String key, String value, String i18nizedText,
PsiExpression[] parameters,
final PropertyCreationHandler propertyCreationHandler) throws IncorrectOperationException {
Project project = psiFile.getProject();
propertyCreationHandler.createProperty(project, propertiesFiles, key, value, parameters);
try {
final PsiElement newExpression = doReplacementInJava(psiFile, editor,literalExpression, i18nizedText);
reformatAndCorrectReferences(newExpression);
}
catch (IncorrectOperationException e) {
Messages.showErrorDialog(project, CodeInsightBundle.message("inspection.i18n.expression.is.invalid.error.message"),
CodeInsightBundle.message("inspection.error.dialog.title"));
}
}
@Override
public JavaI18nizeQuickFixDialog createDialog(Project project, Editor editor, PsiFile psiFile) {
final PsiLiteralExpression literalExpression = I18nizeAction.getEnclosingStringLiteral(psiFile, editor);
return createDialog(project, psiFile, literalExpression);
}
private void doFix(final ProblemDescriptor descriptor, final Project project) {
final PsiLiteralExpression literalExpression = (PsiLiteralExpression)descriptor.getPsiElement();
final PsiFile psiFile = literalExpression.getContainingFile();
if (!JavaI18nizeQuickFixDialog.isAvailable(psiFile)) {
return;
}
final JavaI18nizeQuickFixDialog dialog = createDialog(project, psiFile, literalExpression);
dialog.show();
if (!dialog.isOK()) return;
final Collection<PropertiesFile> propertiesFiles = dialog.getAllPropertiesFiles();
if (!FileModificationService.getInstance().preparePsiElementForWrite(literalExpression)) return;
for (PropertiesFile file : propertiesFiles) {
if (file.findPropertyByKey(dialog.getKey()) == null &&
!FileModificationService.getInstance().prepareFileForWrite(file.getContainingFile())) return;
}
CommandProcessor.getInstance().executeCommand(project, new Runnable(){
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable(){
@Override
public void run() {
try {
performI18nization(psiFile, PsiUtilBase.findEditor(psiFile), dialog.getLiteralExpression(), propertiesFiles, dialog.getKey(),
dialog.getValue(), dialog.getI18nizedText(), dialog.getParameters(),
dialog.getPropertyCreationHandler());
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
});
}
}, CodeInsightBundle.message("quickfix.i18n.command.name"),project);
}
protected PsiElement doReplacementInJava(@NotNull final PsiFile psiFile,
final Editor editor,
final PsiLiteralExpression literalExpression,
String i18nizedText) throws IncorrectOperationException {
return replaceStringLiteral(literalExpression, i18nizedText);
}
private static void reformatAndCorrectReferences(PsiElement newExpression) throws IncorrectOperationException {
final Project project = newExpression.getProject();
newExpression = JavaCodeStyleManager.getInstance(project).shortenClassReferences(newExpression);
CodeStyleManager.getInstance(project).reformat(newExpression);
}
protected JavaI18nizeQuickFixDialog createDialog(final Project project, final PsiFile context, final PsiLiteralExpression literalExpression) {
String value = (String)literalExpression.getValue();
if (mySelectionRange != null) {
TextRange literalRange = literalExpression.getTextRange();
TextRange intersection = literalRange.intersection(mySelectionRange);
value = literalExpression.getText().substring(intersection.getStartOffset() - literalRange.getStartOffset(), intersection.getEndOffset() - literalRange.getStartOffset());
}
value = StringUtil.escapeStringCharacters(value);
return new JavaI18nizeQuickFixDialog(project, context, literalExpression, value, null, true, true);
}
@Nullable
private static PsiBinaryExpression breakStringLiteral(PsiLiteralExpression literalExpression, int offset) throws IncorrectOperationException {
TextRange literalRange = literalExpression.getTextRange();
PsiElementFactory factory = JavaPsiFacade.getInstance(literalExpression.getProject()).getElementFactory();
if (literalRange.getStartOffset()+1 < offset && offset < literalRange.getEndOffset()-1) {
PsiBinaryExpression expression = (PsiBinaryExpression)factory.createExpressionFromText("a + b", literalExpression);
String value = (String)literalExpression.getValue();
int breakIndex = offset - literalRange.getStartOffset()-1;
String lsubstring = value.substring(0, breakIndex);
expression.getLOperand().replace(factory.createExpressionFromText("\""+lsubstring+"\"", literalExpression));
String rsubstring = value.substring(breakIndex);
expression.getROperand().replace(factory.createExpressionFromText("\""+rsubstring+"\"", literalExpression));
return (PsiBinaryExpression)literalExpression.replace(expression);
}
return null;
}
private PsiElement replaceStringLiteral(PsiLiteralExpression literalExpression, String i18nizedText) throws IncorrectOperationException {
PsiElementFactory factory = JavaPsiFacade.getInstance(literalExpression.getProject()).getElementFactory();
if (mySelectionRange != null) {
try {
PsiBinaryExpression binaryExpression = breakStringLiteral(literalExpression, mySelectionRange.getEndOffset());
if (binaryExpression != null) {
literalExpression = (PsiLiteralExpression)binaryExpression.getLOperand();
}
binaryExpression = breakStringLiteral(literalExpression, mySelectionRange.getStartOffset());
if (binaryExpression != null) {
literalExpression = (PsiLiteralExpression)binaryExpression.getROperand();
}
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
PsiExpression expression = factory.createExpressionFromText(i18nizedText, literalExpression);
return literalExpression.replace(expression);
}
}