com.intellij.refactoring.util.duplicates.DuplicatesImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.refactoring.util.duplicates.DuplicatesImpl.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.
 */
package com.intellij.refactoring.util.duplicates;

import com.intellij.CommonBundle;
import com.intellij.codeInsight.folding.CodeFoldingManager;
import com.intellij.codeInsight.highlighting.HighlightManager;
import com.intellij.find.FindManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.FoldRegion;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.ui.ReplacePromptDialog;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;

/**
 * @author dsl
 */
public class DuplicatesImpl {
    private static final Logger LOG = Logger
            .getInstance("#com.intellij.refactoring.util.duplicates.DuplicatesImpl");

    private DuplicatesImpl() {
    }

    public static void invoke(@NotNull final Project project, @NotNull Editor editor,
            @NotNull MatchProvider provider) {
        final List<Match> duplicates = provider.getDuplicates();
        int idx = 0;
        final Ref<Boolean> showAll = new Ref<Boolean>();
        final String confirmDuplicatePrompt = getConfirmationPrompt(provider, duplicates);
        for (final Match match : duplicates) {
            if (!match.getMatchStart().isValid() || !match.getMatchEnd().isValid())
                continue;
            if (replaceMatch(project, provider, match, editor, ++idx, duplicates.size(), showAll,
                    confirmDuplicatePrompt, true))
                return;
        }
    }

    public static void invoke(final Project project, final MatchProvider provider) {
        final List<Match> duplicates = provider.getDuplicates();
        int idx = 0;
        final Ref<Boolean> showAll = new Ref<Boolean>();
        final String confirmDuplicatePrompt = getConfirmationPrompt(provider, duplicates);
        for (final Match match : duplicates) {
            final PsiFile file = match.getFile();
            final VirtualFile virtualFile = file.getVirtualFile();
            if (virtualFile == null || !virtualFile.isValid())
                return;
            if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file))
                return;
            final Editor editor = FileEditorManager.getInstance(project)
                    .openTextEditor(new OpenFileDescriptor(project, virtualFile), false);
            LOG.assertTrue(editor != null);
            if (!match.getMatchStart().isValid() || !match.getMatchEnd().isValid())
                continue;
            if (replaceMatch(project, provider, match, editor, ++idx, duplicates.size(), showAll,
                    confirmDuplicatePrompt, false))
                return;
        }
    }

    @Nullable
    private static String getConfirmationPrompt(MatchProvider provider, List<Match> duplicates) {
        String confirmDuplicatePrompt = null;
        for (Match duplicate : duplicates) {
            confirmDuplicatePrompt = provider.getConfirmDuplicatePrompt(duplicate);
            if (confirmDuplicatePrompt != null) {
                break;
            }
        }
        return confirmDuplicatePrompt;
    }

    private static boolean replaceMatch(final Project project, final MatchProvider provider, final Match match,
            @NotNull final Editor editor, final int idx, final int size, Ref<Boolean> showAll,
            final String confirmDuplicatePrompt, boolean skipPromptWhenOne) {
        final ArrayList<RangeHighlighter> highlighters = previewMatch(project, match, editor);
        if (!ApplicationManager.getApplication().isUnitTestMode()) {
            if ((!skipPromptWhenOne || size > 1) && (showAll.get() == null || !showAll.get())) {
                final String prompt = provider.getConfirmDuplicatePrompt(match);
                final ReplacePromptDialog promptDialog = new ReplacePromptDialog(false,
                        provider.getReplaceDuplicatesTitle(idx, size), project) {
                    @Override
                    protected String getMessage() {
                        final String message = super.getMessage();
                        return prompt != null ? message + prompt : message;
                    }
                };
                promptDialog.show();
                final boolean allChosen = promptDialog.getExitCode() == FindManager.PromptResult.ALL;
                showAll.set(allChosen);
                if (allChosen && confirmDuplicatePrompt != null && prompt == null) {
                    if (Messages.showOkCancelDialog(project,
                            "In order to replace all occurrences method signature will be changed. Proceed?",
                            CommonBundle.getWarningTitle(),
                            Messages.getWarningIcon()) != DialogWrapper.OK_EXIT_CODE)
                        return true;
                }
                if (promptDialog.getExitCode() == FindManager.PromptResult.SKIP)
                    return false;
                if (promptDialog.getExitCode() == FindManager.PromptResult.CANCEL)
                    return true;
            }
        }
        HighlightManager.getInstance(project).removeSegmentHighlighter(editor, highlighters.get(0));

        new WriteCommandAction(project, MethodDuplicatesHandler.REFACTORING_NAME) {
            @Override
            protected void run(Result result) throws Throwable {
                try {
                    provider.processMatch(match);
                } catch (IncorrectOperationException e) {
                    LOG.error(e);
                }
            }
        }.execute();

        return false;
    }

    public static ArrayList<RangeHighlighter> previewMatch(Project project, Match match, Editor editor) {
        final ArrayList<RangeHighlighter> highlighters = new ArrayList<RangeHighlighter>();
        highlightMatch(project, editor, match, highlighters);
        final TextRange textRange = match.getTextRange();
        final LogicalPosition logicalPosition = editor.offsetToLogicalPosition(textRange.getStartOffset());
        expandAllRegionsCoveringRange(project, editor, textRange);
        editor.getScrollingModel().scrollTo(logicalPosition, ScrollType.MAKE_VISIBLE);
        return highlighters;
    }

    private static void expandAllRegionsCoveringRange(final Project project, Editor editor,
            final TextRange textRange) {
        final FoldRegion[] foldRegions = CodeFoldingManager.getInstance(project).getFoldRegionsAtOffset(editor,
                textRange.getStartOffset());
        boolean anyCollapsed = false;
        for (final FoldRegion foldRegion : foldRegions) {
            if (!foldRegion.isExpanded()) {
                anyCollapsed = true;
                break;
            }
        }
        if (anyCollapsed) {
            editor.getFoldingModel().runBatchFoldingOperation(new Runnable() {
                public void run() {
                    for (final FoldRegion foldRegion : foldRegions) {
                        if (!foldRegion.isExpanded()) {
                            foldRegion.setExpanded(true);
                        }
                    }
                }
            });
        }
    }

    public static void highlightMatch(final Project project, Editor editor, final Match match,
            final ArrayList<RangeHighlighter> highlighters) {
        EditorColorsManager colorsManager = EditorColorsManager.getInstance();
        TextAttributes attributes = colorsManager.getGlobalScheme()
                .getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
        HighlightManager.getInstance(project).addRangeHighlight(editor, match.getTextRange().getStartOffset(),
                match.getTextRange().getEndOffset(), attributes, true, highlighters);
    }

    public static void processDuplicates(@NotNull MatchProvider provider, @NotNull Project project,
            @NotNull Editor editor) {
        boolean hasDuplicates = provider.hasDuplicates();
        if (hasDuplicates) {
            List<Match> duplicates = provider.getDuplicates();
            if (duplicates.size() == 1) {
                previewMatch(project, duplicates.get(0), editor);
            }
            final int answer = ApplicationManager.getApplication().isUnitTestMode() ? 0
                    : Messages.showYesNoDialog(project, RefactoringBundle.message(
                            "0.has.detected.1.code.fragments.in.this.file.that.can.be.replaced.with.a.call.to.extracted.method",
                            ApplicationNamesInfo.getInstance().getProductName(), duplicates.size()),
                            "Process Duplicates", Messages.getQuestionIcon());
            if (answer == 0) {
                invoke(project, editor, provider);
            }
        }
    }
}