private Collection<VirtualFile> promptAboutAddition(
     SvnVcs vcs,
     List<VirtualFile> addedVFiles,
     VcsShowConfirmationOption.Value value,
     AbstractVcsHelper vcsHelper) {
   Collection<VirtualFile> filesToProcess;
   if (value == VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY) {
     filesToProcess = addedVFiles;
   } else {
     final String singleFilePrompt;
     if (addedVFiles.size() == 1 && addedVFiles.get(0).isDirectory()) {
       singleFilePrompt = SvnBundle.getString("confirmation.text.add.dir");
     } else {
       singleFilePrompt = SvnBundle.getString("confirmation.text.add.file");
     }
     filesToProcess =
         vcsHelper.selectFilesToProcess(
             addedVFiles,
             SvnBundle.message("confirmation.title.add.multiple.files"),
             null,
             SvnBundle.message("confirmation.title.add.file"),
             singleFilePrompt,
             vcs.getAddConfirmation());
   }
   return filesToProcess;
 }
 @Override
 public void onFrameActivated() {
   final List<VirtualFile> folders = ((ChangeListManagerImpl) myClManager).getLockedFolders();
   if (!folders.isEmpty()) {
     myDirtyScopeManager.filesDirty(null, folders);
   }
 }
  private void refreshFiles(final Project project) {
    final List<VirtualFile> toRefreshFiles = new ArrayList<VirtualFile>();
    final List<VirtualFile> toRefreshDirs = new ArrayList<VirtualFile>();
    for (VirtualFile file : myFilesToRefresh) {
      if (file == null) continue;
      if (file.isDirectory()) {
        toRefreshDirs.add(file);
      } else {
        toRefreshFiles.add(file);
      }
    }
    // if refresh asynchronously, local changes would also be notified that they are dirty
    // asynchronously,
    // and commit could be executed while not all changes are visible
    filterOutInvalid(myFilesToRefresh);
    RefreshQueue.getInstance()
        .refresh(
            true,
            true,
            new Runnable() {
              public void run() {
                if (project.isDisposed()) return;
                filterOutInvalid(toRefreshFiles);
                filterOutInvalid(toRefreshDirs);

                final VcsDirtyScopeManager vcsDirtyScopeManager =
                    VcsDirtyScopeManager.getInstance(project);
                vcsDirtyScopeManager.filesDirty(toRefreshFiles, toRefreshDirs);
              }
            },
            myFilesToRefresh);
    myFilesToRefresh.clear();
  }
  public boolean move(VirtualFile file, VirtualFile toDir) throws IOException {
    File srcFile = getIOFile(file);
    File dstFile = new File(getIOFile(toDir), file.getName());

    final SvnVcs vcs = getVCS(toDir);
    final SvnVcs sourceVcs = getVCS(file);
    if (vcs == null && sourceVcs == null) return false;

    if (vcs == null) {
      return false;
    }

    FileDocumentManager.getInstance().saveAllDocuments();
    if (sourceVcs == null) {
      return createItem(toDir, file.getName(), file.isDirectory(), true);
    }

    if (isPendingAdd(vcs.getProject(), toDir)) {

      myMovedFiles.add(new MovedFileInfo(sourceVcs.getProject(), srcFile, dstFile));
      return true;
    } else {
      final VirtualFile oldParent = file.getParent();
      myFilesToRefresh.add(oldParent);
      myFilesToRefresh.add(toDir);
      return doMove(sourceVcs, srcFile, dstFile);
    }
  }
 private void addToMoveExceptions(@NotNull final Project project, @NotNull final Exception e) {
   List<VcsException> exceptionList = myMoveExceptions.get(project);
   if (exceptionList == null) {
     exceptionList = new ArrayList<VcsException>();
     myMoveExceptions.put(project, exceptionList);
   }
   exceptionList.add(handleMoveException(e));
 }
  public List<VirtualFile> convertRoots(final List<VirtualFile> result) {
    if (ThreadLocalDefendedInvoker.isInside()) return result;

    synchronized (myMonitor) {
      final List<VirtualFile> cachedRoots = myMapping.getUnderVcsRoots();
      final List<VirtualFile> lonelyRoots = myMapping.getLonelyRoots();
      if (!lonelyRoots.isEmpty()) {
        myChecker.reportNoRoots(lonelyRoots);
      }
      if (cachedRoots.isEmpty()) {
        // todo +-
        return result;
      }
      return cachedRoots;
    }
  }
  private void fillAddedFiles(
      Project project,
      SvnVcs vcs,
      List<VirtualFile> addedVFiles,
      Map<VirtualFile, File> copyFromMap,
      Set<VirtualFile> recursiveItems) {
    final Collection<AddedFileInfo> addedFileInfos = myAddedFiles.remove(project);
    final ChangeListManager changeListManager = ChangeListManager.getInstance(project);

    for (AddedFileInfo addedFileInfo : addedFileInfos) {
      final File ioFile = new File(getIOFile(addedFileInfo.myDir), addedFileInfo.myName);
      VirtualFile addedFile = addedFileInfo.myDir.findChild(addedFileInfo.myName);
      if (addedFile == null) {
        addedFile = myLfs.refreshAndFindFileByIoFile(ioFile);
      }
      if (addedFile != null) {
        final SVNStatus fileStatus = getFileStatus(vcs, ioFile);
        if (fileStatus == null || !SvnVcs.svnStatusIs(fileStatus, SVNStatusType.STATUS_IGNORED)) {
          boolean isIgnored = changeListManager.isIgnoredFile(addedFile);
          if (!isIgnored) {
            addedVFiles.add(addedFile);
            copyFromMap.put(addedFile, addedFileInfo.myCopyFrom);
            if (addedFileInfo.myRecursive) {
              recursiveItems.add(addedFile);
            }
          }
        }
      }
    }
  }
  /**
   * Returns real working copies roots - if there is <Project Root> -> Subversion setting, and there
   * is one working copy, will return one root
   */
  public List<WCInfo> getAllWcInfos() {
    final SvnFileUrlMapping urlMapping = getSvnFileUrlMapping();

    final List<RootUrlInfo> infoList = urlMapping.getAllWcInfos();
    final List<WCInfo> infos = new ArrayList<WCInfo>();
    for (RootUrlInfo info : infoList) {
      final File file = info.getIoFile();
      infos.add(
          new WCInfo(
              file.getAbsolutePath(),
              info.getAbsoluteUrlAsUrl(),
              info.getFormat(),
              info.getRepositoryUrl(),
              SvnUtil.isWorkingCopyRoot(file),
              info.getType(),
              SvnUtil.getDepth(this, file)));
    }
    return infos;
  }
  void commandFinished(final Project project) {
    checkOverwrites(project);
    if (myAddedFiles.containsKey(project)) {
      processAddedFiles(project);
    }
    processMovedFiles(project);
    if (myDeletedFiles.containsKey(project)) {
      processDeletedFiles(project);
    }

    final List<VcsException> exceptionList = myMoveExceptions.get(project);
    if (exceptionList != null && !exceptionList.isEmpty()) {
      AbstractVcsHelper.getInstance(project)
          .showErrors(exceptionList, SvnBundle.message("move.files.errors.title"));
    }

    if (!myFilesToRefresh.isEmpty()) {
      refreshFiles(project);
    }
  }
  public boolean rename(VirtualFile file, String newName) throws IOException {
    File srcFile = getIOFile(file);
    File dstFile = new File(srcFile.getParentFile(), newName);
    SvnVcs vcs = getVCS(file);
    if (vcs != null) {
      FileDocumentManager.getInstance().saveAllDocuments();

      myFilesToRefresh.add(file.getParent());
      return doMove(vcs, srcFile, dstFile);
    }
    return false;
  }
    public void detectCopyRoots(final VirtualFile[] roots, final boolean clearState) {
      final Getter<Boolean> cancelGetter =
          new Getter<Boolean>() {
            public Boolean get() {
              return myVcs.getProject().isDisposed();
            }
          };

      for (final VirtualFile vcsRoot : roots) {
        final List<Real> foundRoots =
            ForNestedRootChecker.getAllNestedWorkingCopies(vcsRoot, myVcs, false, cancelGetter);
        if (foundRoots.isEmpty()) {
          myLonelyRoots.add(vcsRoot);
        }
        // filter out bad(?) items
        for (Real foundRoot : foundRoots) {
          final SVNURL repoRoot = foundRoot.getInfo().getRepositoryRootURL();
          if (repoRoot == null) {
            LOG.info(
                "Error: cannot find repository URL for versioned folder: "
                    + foundRoot.getFile().getPath());
          } else {
            myRepositoryRoots.register(repoRoot);
            myTopRoots.add(
                new RootUrlInfo(
                    repoRoot,
                    foundRoot.getInfo().getURL(),
                    SvnFormatSelector.getWorkingCopyFormat(foundRoot.getInfo().getFile()),
                    foundRoot.getFile(),
                    vcsRoot));
          }
        }
      }

      if (!SvnConfiguration.getInstance(myVcs.getProject()).DETECT_NESTED_COPIES) {
        myApplier.apply(myVcs, myTopRoots, myLonelyRoots);
      } else {
        addNestedRoots(clearState);
      }
    }
 private void processAddedFiles(Project project) {
   SvnVcs vcs = SvnVcs.getInstance(project);
   List<VirtualFile> addedVFiles = new ArrayList<VirtualFile>();
   Map<VirtualFile, File> copyFromMap = new HashMap<VirtualFile, File>();
   final Set<VirtualFile> recursiveItems = new HashSet<VirtualFile>();
   fillAddedFiles(project, vcs, addedVFiles, copyFromMap, recursiveItems);
   if (addedVFiles.isEmpty()) return;
   final VcsShowConfirmationOption.Value value = vcs.getAddConfirmation().getValue();
   if (value != VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) {
     final AbstractVcsHelper vcsHelper = AbstractVcsHelper.getInstance(project);
     final Collection<VirtualFile> filesToProcess =
         promptAboutAddition(vcs, addedVFiles, value, vcsHelper);
     if (filesToProcess != null && !filesToProcess.isEmpty()) {
       final List<VcsException> exceptions = new ArrayList<VcsException>();
       runInBackground(
           project,
           "Adding files to Subversion",
           createAdditionRunnable(project, vcs, copyFromMap, filesToProcess, exceptions));
       if (!exceptions.isEmpty()) {
         vcsHelper.showErrors(exceptions, SvnBundle.message("add.files.errors.title"));
       }
     }
   }
 }
  private void processDeletedFiles(Project project) {
    final List<Pair<FilePath, WorkingCopyFormat>> deletedFiles =
        new ArrayList<Pair<FilePath, WorkingCopyFormat>>();
    final Collection<FilePath> filesToProcess = new ArrayList<FilePath>();
    List<VcsException> exceptions = new ArrayList<VcsException>();
    final AbstractVcsHelper vcsHelper = AbstractVcsHelper.getInstance(project);

    try {
      fillDeletedFiles(project, deletedFiles, filesToProcess);
      if (deletedFiles.isEmpty() && filesToProcess.isEmpty() || myUndoingMove) return;
      SvnVcs vcs = SvnVcs.getInstance(project);
      final VcsShowConfirmationOption.Value value = vcs.getDeleteConfirmation().getValue();
      if (value != VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) {
        if (!deletedFiles.isEmpty()) {
          final Collection<FilePath> confirmed =
              promptAboutDeletion(deletedFiles, vcs, value, vcsHelper);
          if (confirmed != null) {
            filesToProcess.addAll(confirmed);
          }
        }
        if (filesToProcess != null && !filesToProcess.isEmpty()) {
          runInBackground(
              project,
              "Deleting files from Subversion",
              createDeleteRunnable(project, vcs, filesToProcess, exceptions));
        }
        final List<FilePath> deletedFilesFiles =
            ObjectsConvertor.convert(
                deletedFiles,
                new Convertor<Pair<FilePath, WorkingCopyFormat>, FilePath>() {
                  @Override
                  public FilePath convert(Pair<FilePath, WorkingCopyFormat> o) {
                    return o.getFirst();
                  }
                });
        for (FilePath file : deletedFilesFiles) {
          final FilePath parent = file.getParentPath();
          if (parent != null) {
            myFilesToRefresh.add(parent.getVirtualFile());
          }
        }
        if (filesToProcess != null) {
          deletedFilesFiles.removeAll(filesToProcess);
        }
        for (FilePath file : deletedFilesFiles) {
          FileUtil.delete(file.getIOFile());
        }
      }
    } catch (SVNException e) {
      exceptions.add(new VcsException(e));
    }
    if (!exceptions.isEmpty()) {
      vcsHelper.showErrors(exceptions, SvnBundle.message("delete.files.errors.title"));
    }
  }
  private void processMovedFiles(final Project project) {
    if (myMovedFiles.isEmpty()) return;

    final Runnable runnable =
        new Runnable() {
          public void run() {
            for (Iterator<MovedFileInfo> iterator = myMovedFiles.iterator(); iterator.hasNext(); ) {
              MovedFileInfo movedFileInfo = iterator.next();
              if (movedFileInfo.myProject == project) {
                doMove(SvnVcs.getInstance(project), movedFileInfo.mySrc, movedFileInfo.myDst);
                iterator.remove();
              }
            }
          }
        };
    runInBackground(project, "Moving files in Subversion", runnable);
  }
  @Override
  public <S> List<S> filterUniqueRoots(
      final List<S> in, final Convertor<S, VirtualFile> convertor) {
    if (in.size() <= 1) return in;

    final List<MyPair<S>> infos = new ArrayList<MyPair<S>>(in.size());
    final SvnFileUrlMappingImpl mapping = (SvnFileUrlMappingImpl) getSvnFileUrlMapping();
    final List<S> notMatched = new LinkedList<S>();
    for (S s : in) {
      final VirtualFile vf = convertor.convert(s);
      if (vf == null) continue;

      final File ioFile = new File(vf.getPath());
      SVNURL url = mapping.getUrlForFile(ioFile);
      if (url == null) {
        url = SvnUtil.getUrl(this, ioFile);
        if (url == null) {
          notMatched.add(s);
          continue;
        }
      }
      infos.add(new MyPair<S>(vf, url.toString(), s));
    }
    final List<MyPair<S>> filtered = new ArrayList<MyPair<S>>(infos.size());
    ForNestedRootChecker.filterOutSuperfluousChildren(this, infos, filtered);

    final List<S> converted =
        ObjectsConvertor.convert(
            filtered,
            new Convertor<MyPair<S>, S>() {
              @Override
              public S convert(final MyPair<S> o) {
                return o.getSrc();
              }
            });
    if (!notMatched.isEmpty()) {
      // potential bug is here: order is not kept. but seems it only occurs for cases where result
      // is sorted after filtering so ok
      converted.addAll(notMatched);
    }
    return converted;
  }