private void updateFinished() {
    myDumb = false;
    if (myProject.isDisposed()) return;

    if (ApplicationManager.getApplication().isInternal()) LOG.info("updateFinished");

    try {
      myPublisher.exitDumbMode();
      FileEditorManagerEx.getInstanceEx(myProject).refreshIcons();
    } finally {
      // It may happen that one of the pending runWhenSmart actions triggers new dumb mode;
      // in this case we should quit processing pending actions and postpone them until the newly
      // started dumb mode finishes.
      while (!myDumb) {
        final Runnable runnable;
        synchronized (myRunWhenSmartQueue) {
          if (myRunWhenSmartQueue.isEmpty()) {
            break;
          }
          runnable = myRunWhenSmartQueue.pullFirst();
        }
        try {
          runnable.run();
        } catch (Throwable e) {
          LOG.error(e);
        }
      }
    }
  }
  public void doRollback(
      final Collection<Change> changes,
      final boolean deleteLocallyAddedFiles,
      @Nullable final Runnable afterVcsRefreshInAwt,
      @Nullable final String localHistoryActionName) {
    final ChangeListManager changeListManager = ChangeListManager.getInstance(myProject);
    final Runnable notifier = changeListManager.prepareForChangeDeletion(changes);
    final Runnable afterRefresh =
        new Runnable() {
          public void run() {
            changeListManager.invokeAfterUpdate(
                new Runnable() {
                  public void run() {
                    notifier.run();
                    if (afterVcsRefreshInAwt != null) {
                      afterVcsRefreshInAwt.run();
                    }
                  }
                },
                InvokeAfterUpdateMode.SILENT,
                "Refresh change lists after update",
                ModalityState.current());
          }
        };

    final Runnable rollbackAction =
        new MyRollbackRunnable(
            changes, deleteLocallyAddedFiles, afterRefresh, localHistoryActionName);

    if (ApplicationManager.getApplication().isDispatchThread()) {
      ProgressManager.getInstance()
          .run(
              new Task.Backgroundable(
                  myProject,
                  VcsBundle.message("changes.action.rollback.text"),
                  true,
                  new PerformInBackgroundOption() {
                    public boolean shouldStartInBackground() {
                      return VcsConfiguration.getInstance(myProject).PERFORM_ROLLBACK_IN_BACKGROUND;
                    }

                    public void processSentToBackground() {
                      VcsConfiguration.getInstance(myProject).PERFORM_ROLLBACK_IN_BACKGROUND = true;
                    }
                  }) {
                public void run(@NotNull ProgressIndicator indicator) {
                  rollbackAction.run();
                }
              });
    } else {
      rollbackAction.run();
    }
    ((ChangeListManagerImpl) changeListManager).showLocalChangesInvalidated();
  }
 @TestOnly
 public static void runWithAlwaysCheckingCanceled(@NotNull Runnable runnable) {
   Thread fake = new Thread("fake");
   try {
     threadsUnderCanceledIndicator.add(fake);
     runnable.run();
   } finally {
     threadsUnderCanceledIndicator.remove(fake);
   }
 }
 @Override
 public void runWhenSmart(@NotNull Runnable runnable) {
   if (!isDumb()) {
     runnable.run();
   } else {
     synchronized (myRunWhenSmartQueue) {
       myRunWhenSmartQueue.addLast(runnable);
     }
   }
 }
  public void performActionSync(
      final CvsHandler handler, final CvsOperationExecutorCallback callback) {
    final CvsTabbedWindow tabbedWindow = myIsQuietOperation ? null : openTabbedWindow(handler);

    final Runnable finish =
        new Runnable() {
          @Override
          public void run() {
            try {
              myResult.addAllErrors(handler.getErrorsExceptAborted());
              handler.finish();
              if (myProject == null || myProject != null && !myProject.isDisposed()) {
                showErrors(handler, tabbedWindow);
              }
            } finally {
              try {
                if (myResult.finishedUnsuccessfully(handler)) {
                  callback.executionFinished(false);
                } else {
                  if (handler.getErrors().isEmpty()) callback.executionFinishedSuccessfully();
                  callback.executionFinished(true);
                }
              } finally {
                if (myProject != null && handler != CvsHandler.NULL) {
                  StatusBar.Info.set(getStatusMessage(handler), myProject);
                }
              }
            }
          }
        };

    final Runnable cvsAction =
        new Runnable() {
          @Override
          public void run() {
            try {
              if (handler == CvsHandler.NULL) return;
              setText(CvsBundle.message("progress.text.preparing.for.login"));

              handler.beforeLogin();

              if (myResult.finishedUnsuccessfully(handler)) return;

              setText(CvsBundle.message("progress.text.preparing.for.action", handler.getTitle()));

              handler.run(myProject, myExecutor);
              if (myResult.finishedUnsuccessfully(handler)) return;

            } catch (ProcessCanceledException ex) {
              myResult.setIsCanceled();
            } finally {
              callback.executeInProgressAfterAction(myExecutor);
            }
          }
        };

    if (doNotShowProgress()) {
      cvsAction.run();
      if (myIsQuietOperation) {
        finish.run();
      } else {
        myExecutor.runInDispatchThread(finish, myProject);
      }
    } else {
      final PerformInBackgroundOption backgroundOption = handler.getBackgroundOption(myProject);
      if (backgroundOption != null) {
        final Task.Backgroundable task =
            new Task.Backgroundable(
                myProject, handler.getTitle(), handler.canBeCanceled(), backgroundOption) {
              @Override
              public void run(@NotNull final ProgressIndicator indicator) {
                cvsAction.run();
              }

              @Override
              public void onSuccess() {
                finish.run();
              }
            };
        ProgressManager.getInstance().run(task);
      } else {
        if (ProgressManager.getInstance()
            .runProcessWithProgressSynchronously(
                cvsAction, handler.getTitle(), handler.canBeCanceled(), myProject)) {
          finish.run();
        }
      }
    }
  }