com.intellij.codeInspection.i18n.I18nizeQuickFix.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.codeInspection.i18n.I18nizeQuickFix.java

Source

/*
 * 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);
    }

}