public void doClone(PsiElement element) {
    FeatureUsageTracker.getInstance().triggerFeatureUsed("refactoring.copyClass");
    PsiClass[] classes = getTopLevelClasses(element);
    if (classes == null) {
      CopyFilesOrDirectoriesHandler.doCloneFile(element);
      return;
    }
    Project project = element.getProject();

    CopyClassDialog dialog = new CopyClassDialog(classes[0], null, project, true);
    dialog.setTitle(RefactoringBundle.message("copy.handler.clone.class"));
    dialog.show();
    if (dialog.isOK()) {
      String className = dialog.getClassName();
      PsiDirectory targetDirectory = element.getContainingFile().getContainingDirectory();
      copyClassesImpl(
          className,
          project,
          Collections.singletonMap(classes[0].getContainingFile(), classes),
          null,
          targetDirectory,
          targetDirectory,
          RefactoringBundle.message("copy.handler.clone.class"),
          true,
          true);
    }
  }
 private static PsiFile copy(
     @NotNull PsiFile file,
     PsiDirectory directory,
     String name,
     String relativePath,
     int[] choice) {
   final String fileName = getNewFileName(file, name);
   if (relativePath != null && !relativePath.isEmpty()) {
     return buildRelativeDir(directory, relativePath)
         .findOrCreateTargetDirectory()
         .copyFileFrom(fileName, file);
   }
   if (CopyFilesOrDirectoriesHandler.checkFileExist(directory, choice, file, fileName, "Copy"))
     return null;
   return directory.copyFileFrom(fileName, file);
 }
  @Nullable
  public static PsiElement doCopyClasses(
      final Map<PsiFile, PsiClass[]> fileToClasses,
      @Nullable HashMap<PsiFile, String> map,
      final String copyClassName,
      final PsiDirectory targetDirectory,
      final Project project)
      throws IncorrectOperationException {
    PsiElement newElement = null;
    final Map<PsiClass, PsiElement> oldToNewMap = new HashMap<PsiClass, PsiElement>();
    for (final PsiClass[] psiClasses : fileToClasses.values()) {
      if (psiClasses != null) {
        for (PsiClass aClass : psiClasses) {
          if (aClass instanceof SyntheticElement) {
            continue;
          }
          oldToNewMap.put(aClass, null);
        }
      }
    }
    final List<PsiFile> createdFiles = new ArrayList<PsiFile>(fileToClasses.size());
    int[] choice = fileToClasses.size() > 1 ? new int[] {-1} : null;
    List<PsiFile> files = new ArrayList<PsiFile>();
    for (final Map.Entry<PsiFile, PsiClass[]> entry : fileToClasses.entrySet()) {
      final PsiFile psiFile = entry.getKey();
      final PsiClass[] sources = entry.getValue();
      if (psiFile instanceof PsiClassOwner && sources != null) {
        final PsiFile createdFile =
            copy(
                psiFile,
                targetDirectory,
                copyClassName,
                map == null ? null : map.get(psiFile),
                choice);
        if (createdFile == null) return null;
        for (final PsiClass destination : ((PsiClassOwner) createdFile).getClasses()) {
          if (destination instanceof SyntheticElement) {
            continue;
          }
          PsiClass source = findByName(sources, destination.getName());
          if (source != null) {
            final PsiClass copy = copy(source, copyClassName);
            newElement = destination.replace(copy);
            oldToNewMap.put(source, newElement);
          } else {
            destination.delete();
          }
        }
        createdFiles.add(createdFile);
      } else {
        files.add(psiFile);
      }
    }

    for (PsiFile file : files) {
      try {
        PsiDirectory finalTarget = targetDirectory;
        final String relativePath = map != null ? map.get(file) : null;
        if (relativePath != null && !relativePath.isEmpty()) {
          finalTarget =
              buildRelativeDir(targetDirectory, relativePath).findOrCreateTargetDirectory();
        }
        final PsiFile fileCopy =
            CopyFilesOrDirectoriesHandler.copyToDirectory(
                file, getNewFileName(file, copyClassName), finalTarget, choice);
        if (fileCopy != null) {
          createdFiles.add(fileCopy);
        }
      } catch (IOException e) {
        throw new IncorrectOperationException(e.getMessage());
      }
    }

    final Set<PsiElement> rebindExpressions = new HashSet<PsiElement>();
    for (PsiElement element : oldToNewMap.values()) {
      if (element == null) {
        LOG.error(oldToNewMap.keySet());
        continue;
      }
      decodeRefs(element, oldToNewMap, rebindExpressions);
    }

    final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
    for (PsiFile psiFile : createdFiles) {
      if (psiFile instanceof PsiJavaFile) {
        codeStyleManager.removeRedundantImports((PsiJavaFile) psiFile);
      }
    }
    for (PsiElement expression : rebindExpressions) {
      codeStyleManager.shortenClassReferences(expression);
    }
    new OptimizeImportsProcessor(
            project, createdFiles.toArray(new PsiFile[createdFiles.size()]), null)
        .run();
    return newElement != null ? newElement : createdFiles.size() > 0 ? createdFiles.get(0) : null;
  }
 public void doCopy(PsiElement[] elements, PsiDirectory defaultTargetDirectory) {
   FeatureUsageTracker.getInstance().triggerFeatureUsed("refactoring.copyClass");
   final HashMap<PsiFile, String> relativePathsMap = new HashMap<PsiFile, String>();
   final Map<PsiFile, PsiClass[]> classes =
       convertToTopLevelClasses(elements, false, "", relativePathsMap);
   assert classes != null;
   if (defaultTargetDirectory == null) {
     final PsiFile psiFile = classes.keySet().iterator().next();
     defaultTargetDirectory = psiFile.getContainingDirectory();
     LOG.assertTrue(defaultTargetDirectory != null, psiFile);
   } else {
     Project project = defaultTargetDirectory.getProject();
     VirtualFile sourceRootForFile =
         ProjectRootManager.getInstance(project)
             .getFileIndex()
             .getSourceRootForFile(defaultTargetDirectory.getVirtualFile());
     if (sourceRootForFile == null) {
       final List<PsiElement> files = new ArrayList<PsiElement>();
       for (int i = 0, elementsLength = elements.length; i < elementsLength; i++) {
         PsiFile containingFile = elements[i].getContainingFile();
         if (containingFile != null) {
           files.add(containingFile);
         } else if (elements[i] instanceof PsiDirectory) {
           files.add(elements[i]);
         }
       }
       CopyFilesOrDirectoriesHandler.copyAsFiles(
           files.toArray(new PsiElement[files.size()]), defaultTargetDirectory, project);
       return;
     }
   }
   Project project = defaultTargetDirectory.getProject();
   Object targetDirectory = null;
   String className = null;
   boolean openInEditor = true;
   if (copyOneClass(classes)) {
     final String commonPath =
         ArrayUtil.find(elements, classes.values().iterator().next()) == -1
             ? normalizeRelativeMap(relativePathsMap)
             : null;
     CopyClassDialog dialog =
         new CopyClassDialog(
             classes.values().iterator().next()[0], defaultTargetDirectory, project, false) {
           @Override
           protected String getQualifiedName() {
             if (commonPath != null && !commonPath.isEmpty()) {
               return StringUtil.getQualifiedName(
                   super.getQualifiedName(), commonPath.replaceAll("/", "."));
             }
             return super.getQualifiedName();
           }
         };
     dialog.setTitle(RefactoringBundle.message("copy.handler.copy.class"));
     dialog.show();
     if (dialog.isOK()) {
       openInEditor = dialog.openInEditor();
       targetDirectory = dialog.getTargetDirectory();
       className = dialog.getClassName();
       if (className == null || className.length() == 0) return;
     }
   } else {
     if (ApplicationManager.getApplication().isUnitTestMode()) {
       targetDirectory = defaultTargetDirectory;
     } else {
       defaultTargetDirectory =
           CopyFilesOrDirectoriesHandler.resolveDirectory(defaultTargetDirectory);
       if (defaultTargetDirectory == null) return;
       PsiElement[] files = PsiUtilCore.toPsiFileArray(classes.keySet());
       if (classes.keySet().size() == 1) {
         // do not choose a new name for a file when multiple classes exist in one file
         final PsiClass[] psiClasses = classes.values().iterator().next();
         if (psiClasses != null) {
           files = psiClasses;
         }
       }
       final CopyFilesOrDirectoriesDialog dialog =
           new CopyFilesOrDirectoriesDialog(files, defaultTargetDirectory, project, false);
       dialog.show();
       if (dialog.isOK()) {
         targetDirectory = dialog.getTargetDirectory();
         className = dialog.getNewName();
         openInEditor = dialog.openInEditor();
       }
     }
   }
   if (targetDirectory != null) {
     copyClassesImpl(
         className,
         project,
         classes,
         relativePathsMap,
         targetDirectory,
         defaultTargetDirectory,
         RefactoringBundle.message("copy.handler.copy.class"),
         false,
         openInEditor);
   }
 }