com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler.java

Source

/*
 * Copyright 2000-2013 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.copy;

import com.intellij.CommonBundle;
import com.intellij.ide.CopyPasteDelegator;
import com.intellij.ide.util.EditorHelper;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.encoding.EncodingRegistry;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.psi.*;
import com.intellij.psi.impl.file.PsiPackageHelper;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

public class CopyFilesOrDirectoriesHandler extends CopyHandlerDelegateBase {
    @Override
    public boolean canCopy(PsiElement[] elements, boolean fromUpdate) {
        Set<String> names = new HashSet<String>();
        for (PsiElement element : elements) {
            if (!(element instanceof PsiFileSystemItem))
                return false;
            if (!element.isValid())
                return false;
            if (element instanceof PsiCompiledFile)
                return false;

            String name = ((PsiFileSystemItem) element).getName();
            if (names.contains(name)) {
                return false;
            }
            names.add(name);
        }

        PsiElement[] filteredElements = PsiTreeUtil.filterAncestors(elements);
        return filteredElements.length == elements.length;
    }

    @Override
    public void doCopy(final PsiElement[] elements, PsiDirectory defaultTargetDirectory) {
        if (defaultTargetDirectory == null) {
            defaultTargetDirectory = getCommonParentDirectory(elements);
        }
        Project project = defaultTargetDirectory != null ? defaultTargetDirectory.getProject()
                : elements[0].getProject();
        if (defaultTargetDirectory != null) {
            defaultTargetDirectory = resolveDirectory(defaultTargetDirectory);
            if (defaultTargetDirectory == null)
                return;
        }

        copyAsFiles(elements, defaultTargetDirectory, project);
    }

    public static void copyAsFiles(PsiElement[] elements, PsiDirectory defaultTargetDirectory, Project project) {
        PsiDirectory targetDirectory = null;
        String newName = null;
        boolean openInEditor = true;

        if (ApplicationManager.getApplication().isUnitTestMode()) {
            targetDirectory = defaultTargetDirectory;
        } else {
            CopyFilesOrDirectoriesDialog dialog = new CopyFilesOrDirectoriesDialog(elements, defaultTargetDirectory,
                    project, false);
            dialog.show();
            if (dialog.isOK()) {
                newName = elements.length == 1 ? dialog.getNewName() : null;
                targetDirectory = dialog.getTargetDirectory();
                openInEditor = dialog.openInEditor();
            }
        }

        if (targetDirectory != null) {
            try {
                for (PsiElement element : elements) {
                    PsiFileSystemItem psiElement = (PsiFileSystemItem) element;
                    if (psiElement.isDirectory()) {
                        MoveFilesOrDirectoriesUtil.checkIfMoveIntoSelf(psiElement, targetDirectory);
                    }
                }
            } catch (IncorrectOperationException e) {
                CommonRefactoringUtil.showErrorHint(project, null, e.getMessage(), CommonBundle.getErrorTitle(),
                        null);
                return;
            }

            copyImpl(elements, newName, targetDirectory, false, openInEditor);
        }
    }

    @Override
    public void doClone(final PsiElement element) {
        doCloneFile(element);
    }

    public static void doCloneFile(PsiElement element) {
        PsiDirectory targetDirectory;
        if (element instanceof PsiDirectory) {
            targetDirectory = ((PsiDirectory) element).getParentDirectory();
            assert targetDirectory != null : element;
        } else {
            targetDirectory = ((PsiFile) element).getContainingDirectory();
        }

        PsiElement[] elements = { element };
        CopyFilesOrDirectoriesDialog dialog = new CopyFilesOrDirectoriesDialog(elements, null, element.getProject(),
                true);
        dialog.show();
        if (dialog.isOK()) {
            String newName = dialog.getNewName();
            copyImpl(elements, newName, targetDirectory, true, true);
        }
    }

    @Nullable
    private static PsiDirectory getCommonParentDirectory(PsiElement[] elements) {
        PsiDirectory result = null;

        for (PsiElement element : elements) {
            PsiDirectory directory;

            if (element instanceof PsiDirectory) {
                directory = (PsiDirectory) element;
                directory = directory.getParentDirectory();
            } else if (element instanceof PsiFile) {
                directory = ((PsiFile) element).getContainingDirectory();
            } else {
                throw new IllegalArgumentException("unexpected element " + element);
            }

            if (directory == null)
                continue;

            if (result == null) {
                result = directory;
            } else {
                if (PsiTreeUtil.isAncestor(directory, result, true)) {
                    result = directory;
                }
            }
        }

        return result;
    }

    /**
     * @param elements
     * @param newName can be not null only if elements.length == 1
     * @param targetDirectory
     * @param openInEditor
     */
    private static void copyImpl(@NotNull final PsiElement[] elements, @Nullable final String newName,
            @NotNull final PsiDirectory targetDirectory, final boolean doClone, final boolean openInEditor) {
        if (doClone && elements.length != 1) {
            throw new IllegalArgumentException("invalid number of elements to clone:" + elements.length);
        }

        if (newName != null && elements.length != 1) {
            throw new IllegalArgumentException(
                    "no new name should be set; number of elements is: " + elements.length);
        }

        final Project project = targetDirectory.getProject();
        Runnable command = new Runnable() {
            @Override
            public void run() {
                final Runnable action = new Runnable() {
                    @Override
                    public void run() {
                        try {
                            PsiFile firstFile = null;
                            final int[] choice = elements.length > 1 || elements[0] instanceof PsiDirectory
                                    ? new int[] { -1 }
                                    : null;
                            for (PsiElement element : elements) {
                                PsiFile f = copyToDirectory((PsiFileSystemItem) element, newName, targetDirectory,
                                        choice);
                                if (firstFile == null) {
                                    firstFile = f;
                                }
                            }

                            if (firstFile != null) {
                                CopyHandler.updateSelectionInActiveProjectView(firstFile, project, doClone);
                                if (!(firstFile instanceof PsiBinaryFile) && openInEditor) {
                                    EditorHelper.openInEditor(firstFile);
                                    ApplicationManager.getApplication().invokeLater(new Runnable() {
                                        @Override
                                        public void run() {
                                            ToolWindowManager.getInstance(project).activateEditorComponent();
                                        }
                                    });
                                }
                            }
                        } catch (final IncorrectOperationException ex) {
                            ApplicationManager.getApplication().invokeLater(new Runnable() {
                                @Override
                                public void run() {
                                    Messages.showErrorDialog(project, ex.getMessage(),
                                            RefactoringBundle.message("error.title"));
                                }
                            });
                        } catch (final IOException ex) {
                            ApplicationManager.getApplication().invokeLater(new Runnable() {
                                @Override
                                public void run() {
                                    Messages.showErrorDialog(project, ex.getMessage(),
                                            RefactoringBundle.message("error.title"));
                                }
                            });
                        }
                    }
                };
                ApplicationManager.getApplication().runWriteAction(action);
            }
        };

        String title = RefactoringBundle
                .message(doClone ? "copy,handler.clone.files.directories" : "copy.handler.copy.files.directories");
        CommandProcessor.getInstance().executeCommand(project, command, title, null);
    }

    /**
     * @param elementToCopy PsiFile or PsiDirectory
     * @param newName can be not null only if elements.length == 1
     * @return first copied PsiFile (recursively); null if no PsiFiles copied
     */
    @Nullable
    public static PsiFile copyToDirectory(@NotNull PsiFileSystemItem elementToCopy, @Nullable String newName,
            @NotNull PsiDirectory targetDirectory) throws IncorrectOperationException, IOException {
        return copyToDirectory(elementToCopy, newName, targetDirectory, null);
    }

    /**
     * @param elementToCopy PsiFile or PsiDirectory
     * @param newName can be not null only if elements.length == 1
     * @param choice a horrible way to pass/keep user preference
     * @return first copied PsiFile (recursively); null if no PsiFiles copied
     */
    @Nullable
    public static PsiFile copyToDirectory(@NotNull PsiFileSystemItem elementToCopy, @Nullable String newName,
            @NotNull PsiDirectory targetDirectory, @Nullable int[] choice)
            throws IncorrectOperationException, IOException {
        if (elementToCopy instanceof PsiFile) {
            PsiFile file = (PsiFile) elementToCopy;
            String name = newName == null ? file.getName() : newName;
            if (checkFileExist(targetDirectory, choice, file, name, "Copy"))
                return null;
            return targetDirectory.copyFileFrom(name, file);
        } else if (elementToCopy instanceof PsiDirectory) {
            PsiDirectory directory = (PsiDirectory) elementToCopy;
            if (directory.equals(targetDirectory)) {
                return null;
            }
            if (newName == null)
                newName = directory.getName();
            final PsiDirectory existing = targetDirectory.findSubdirectory(newName);
            final PsiDirectory subdirectory = existing == null ? targetDirectory.createSubdirectory(newName)
                    : existing;
            EncodingRegistry.doActionAndRestoreEncoding(directory.getVirtualFile(),
                    new ThrowableComputable<VirtualFile, IOException>() {
                        @Override
                        public VirtualFile compute() {
                            return subdirectory.getVirtualFile();
                        }
                    });

            PsiFile firstFile = null;
            PsiElement[] children = directory.getChildren();
            for (PsiElement child : children) {
                PsiFileSystemItem item = (PsiFileSystemItem) child;
                PsiFile f = copyToDirectory(item, item.getName(), subdirectory, choice);
                if (firstFile == null) {
                    firstFile = f;
                }
            }
            return firstFile;
        } else {
            throw new IllegalArgumentException("unexpected elementToCopy: " + elementToCopy);
        }
    }

    public static boolean checkFileExist(PsiDirectory targetDirectory, int[] choice, PsiFile file, String name,
            String title) {
        final PsiFile existing = targetDirectory.findFile(name);
        if (existing != null && !existing.equals(file)) {
            int selection;
            if (choice == null || choice[0] == -1) {
                String message = String.format("File '%s' already exists in directory '%s'", name,
                        targetDirectory.getVirtualFile().getPath());
                String[] options = choice == null ? new String[] { "Overwrite", "Skip" }
                        : new String[] { "Overwrite", "Skip", "Overwrite for all", "Skip for all" };
                selection = Messages.showDialog(message, title, options, 0, Messages.getQuestionIcon());
            } else {
                selection = choice[0];
            }

            if (choice != null && selection > 1) {
                choice[0] = selection % 2;
                selection = choice[0];
            }

            if (selection == 0 && file != existing) {
                existing.delete();
            } else {
                return true;
            }
        }

        return false;
    }

    @Nullable
    public static PsiDirectory resolveDirectory(@NotNull PsiDirectory defaultTargetDirectory) {
        final Project project = defaultTargetDirectory.getProject();
        final Boolean showDirsChooser = defaultTargetDirectory
                .getCopyableUserData(CopyPasteDelegator.SHOW_CHOOSER_KEY);
        if (showDirsChooser != null && showDirsChooser.booleanValue()) {
            final PsiDirectoryContainer directoryContainer = PsiPackageHelper.getInstance(project)
                    .getDirectoryContainer(defaultTargetDirectory);
            if (directoryContainer == null) {
                return defaultTargetDirectory;
            }
            return MoveFilesOrDirectoriesUtil.resolveToDirectory(project, directoryContainer);
        }
        return defaultTargetDirectory;
    }
}