[hg] don't confirm deletion for newly added files.
authorKirill Likhodedov <kirill.likhodedov@jetbrains.com>
Fri, 8 Apr 2011 09:34:18 +0000 (13:34 +0400)
committerKirill Likhodedov <kirill.likhodedov@jetbrains.com>
Fri, 8 Apr 2011 10:22:23 +0000 (14:22 +0400)
Moved the logic from needConfirmDeletion() to executeDelete because hg is requested to see whether the file is new or not. Made a single Task for all operations in executeDelete().

plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java

index a7a79f50e418623e7729e5bbc123e57ca2c3dfc2..0f98a89c5eca39470f1a26ce148c7c7029734176 100644 (file)
@@ -15,6 +15,7 @@
  */
 package org.zmlx.hg4idea;
 
+import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.progress.ProgressIndicator;
 import com.intellij.openapi.progress.Task;
 import com.intellij.openapi.project.Project;
@@ -28,6 +29,7 @@ import org.jetbrains.annotations.NotNull;
 import org.zmlx.hg4idea.command.*;
 
 import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Listens to VFS events (such as adding or deleting bunch of files) and performs necessary operations with the VCS.
@@ -142,56 +144,81 @@ public class HgVFSListener extends VcsVFSListener {
     return HgVcsMessages.message("hg4idea.remove.single.body");
   }
 
-  @Override
-  protected VcsDeleteType needConfirmDeletion(VirtualFile file) {
-    //// newly added files (which were added to the repo but never committed) should be removed from the VCS,
-    //// but without user confirmation.
-    //final FilePath filePath = VcsUtil.getFilePath(file.getPath());
-    //final VirtualFile repo = HgUtil.getHgRootOrNull(myProject, filePath);
-    //if (repo == null) {
-    //  return super.needConfirmDeletion(file);
-    //}
-    //final HgFile hgFile = new HgFile(repo, filePath);
-    //
-    //final HgLogCommand logCommand = new HgLogCommand(myProject);
-    //logCommand.setLogFile(true);
-    //logCommand.setFollowCopies(false);
-    //logCommand.setIncludeRemoved(true);
-    //final List<HgFileRevision> localRevisions = logCommand.execute(hgFile, -1, true);
-    //// file is newly added, if it doesn't have a history or if the last history action was deleting this file.
-    //if (localRevisions == null || localRevisions.isEmpty() || localRevisions.get(0).getDeletedFiles().contains(hgFile.getRelativePath())) {
-    //  return VcsDeleteType.SILENT;
-    //}
-    return VcsDeleteType.CONFIRM;
-  }
-
   protected void executeDelete() {
     final List<FilePath> filesToDelete = new ArrayList<FilePath>(myDeletedWithoutConfirmFiles);
-    final List<FilePath> deletedFiles = new ArrayList<FilePath>(myDeletedFiles);
+    final List<FilePath> filesToConfirmDeletion = new ArrayList<FilePath>(myDeletedFiles);
     myDeletedWithoutConfirmFiles.clear();
     myDeletedFiles.clear();
 
     // skip unversioned files and files which are not under Mercurial
     final ChangeListManagerImpl changeListManager = ChangeListManagerImpl.getInstanceImpl(myProject);
     skipUnversionedAndNotUnderHg(changeListManager, filesToDelete);
-    skipUnversionedAndNotUnderHg(changeListManager, deletedFiles);
+    skipUnversionedAndNotUnderHg(changeListManager, filesToConfirmDeletion);
+
+    // newly added files (which were added to the repo but never committed) should be removed from the VCS,
+    // but without user confirmation.
+    new Task.ConditionalModal(myProject,
+                              HgVcsMessages.message("hg4idea.remove.progress"),
+                              false,
+                              VcsConfiguration.getInstance(myProject).getAddRemoveOption()) {
+      @Override public void run( @NotNull ProgressIndicator indicator ) {
+        // move files that are not to be confirmed anyway from filesToConfirmDeletion to filesToDelete
+        for (Iterator<FilePath> it = filesToConfirmDeletion.iterator(); it.hasNext(); ) {
+          FilePath file = it.next();
+          if (!isDeleteCofirmationNeeded(file)) {
+            filesToDelete.add(file);
+            it.remove();
+          }
+        }
 
-    // confirm removal from the VCS if needed
-    if (myRemoveOption.getValue() != VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) {
-      if (myRemoveOption.getValue() == VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY || deletedFiles.isEmpty()) {
-        filesToDelete.addAll(deletedFiles);
-      }
-      else {
-        Collection<FilePath> filePaths = selectFilePathsToDelete(deletedFiles);
-        if (filePaths != null) {
-          filesToDelete.addAll(filePaths);
+        // confirm removal from the VCS if needed
+        if (myRemoveOption.getValue() != VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) {
+          if (myRemoveOption.getValue() == VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY || filesToConfirmDeletion.isEmpty()) {
+            filesToDelete.addAll(filesToConfirmDeletion);
+          }
+          else {
+            final AtomicReference<Collection<FilePath>> filePaths = new AtomicReference<Collection<FilePath>>();
+            ApplicationManager.getApplication().invokeAndWait(new Runnable() {
+                @Override public void run() {
+                  filePaths.set(selectFilePathsToDelete(filesToConfirmDeletion));
+                }
+              }, indicator.getModalityState());
+            if (filePaths.get() != null) {
+              filesToDelete.addAll(filePaths.get());
+            }
+          }
+        }
+
+        if (!filesToDelete.isEmpty()) {
+          performDeletion(filesToDelete);
         }
       }
-    }
+    }.queue();
+  }
 
-    if (!filesToDelete.isEmpty()) {
-      performDeletion(filesToDelete);
+  /**
+   * Newly added files (which were added to the repo but never committed) should be removed from the VCS,
+   * but without user confirmation.
+   * <p>NB: we don't use {@link #needConfirmDeletion(com.intellij.openapi.vfs.VirtualFile)},
+   * because it is executed in EDT, while we need to access hg log, which should be done in background. Starting a Task.Modal for
+   * each file is ineffective, so we start it once (in {@link #executeDelete()} for all files.</p
+   * 
+   * @return true if remove confirmation is needed.
+   */
+  private boolean isDeleteCofirmationNeeded(FilePath filePath) {
+    final VirtualFile repo = HgUtil.getHgRootOrNull(myProject, filePath);
+    if (repo == null) {
+      return false;
     }
+    final HgFile hgFile = new HgFile(repo, filePath);
+    final HgLogCommand logCommand = new HgLogCommand(myProject);
+    logCommand.setLogFile(true);
+    logCommand.setFollowCopies(false);
+    logCommand.setIncludeRemoved(true);
+    final List<HgFileRevision> localRevisions = logCommand.execute(hgFile, -1, true);
+
+    // file is newly added, if it doesn't have a history or if the last history action was deleting this file.
+    return localRevisions != null && !localRevisions.isEmpty() && !localRevisions.get(0).getDeletedFiles().contains(hgFile.getRelativePath());
   }
 
     /**
@@ -211,30 +238,22 @@ public class HgVFSListener extends VcsVFSListener {
 
   @Override
   protected void performDeletion( final List<FilePath> filesToDelete) {
-    (new Task.ConditionalModal(myProject,
-                                        HgVcsMessages.message("hg4idea.remove.progress"),
-                                        false,
-                                        VcsConfiguration.getInstance(myProject).getAddRemoveOption()) {
-      @Override public void run( @NotNull ProgressIndicator aProgressIndicator ) {
-        final ArrayList<HgFile> deletes = new ArrayList<HgFile>();
-        for (FilePath file : filesToDelete) {
-          if (file.isDirectory()) {
-            continue;
-          }
-
-          deletes.add(new HgFile(VcsUtil.getVcsRootFor(myProject, file), file));
-        }
+    final ArrayList<HgFile> deletes = new ArrayList<HgFile>();
+    for (FilePath file : filesToDelete) {
+      if (file.isDirectory()) {
+        continue;
+      }
 
-        if (!deletes.isEmpty()) {
-          new HgRemoveCommand(myProject).execute(deletes);
-        }
+      deletes.add(new HgFile(VcsUtil.getVcsRootFor(myProject, file), file));
+    }
 
-        for (HgFile file : deletes) {
-          dirtyScopeManager.fileDirty(file.toFilePath());
-        }
-      }
+    if (!deletes.isEmpty()) {
+      new HgRemoveCommand(myProject).execute(deletes);
+    }
 
-    }).queue();
+    for (HgFile file : deletes) {
+      dirtyScopeManager.fileDirty(file.toFilePath());
+    }
   }
 
   @Override