예제 #1
0
/**
 * Base class for the actions, which update() method might be potentially slow to be executed
 * synchronously in Swing UI thread.
 *
 * @author max
 */
public abstract class AsyncUpdateAction<T> extends AnAction {
  private static final Logger LOG =
      Logger.getInstance("#com.intellij.openapi.actionSystem.AsyncUpdateAction");

  private static final ExecutorService ourUpdaterService =
      ConcurrencyUtil.newSingleThreadExecutor("Action Updater");

  // Async update
  @Override
  public final void update(AnActionEvent e) {
    final T data = prepareDataFromContext(e);
    final Presentation originalPresentation = e.getPresentation();
    if (!forceSyncUpdate(e) && isDumbAware()) {
      final Presentation realPresentation = (Presentation) originalPresentation.clone();
      ourUpdaterService.submit(
          new Runnable() {
            @Override
            public void run() {
              performUpdate(realPresentation, data);
              SwingUtilities.invokeLater(
                  new Runnable() {
                    @Override
                    public void run() {
                      if (originalPresentation.isVisible() != realPresentation.isVisible()) {
                        LOG.error(
                            "Async update is not supported for actions that change their visibility."
                                + "Either stop extending AsyncUpdateAction or override forceSyncUpdate() to return true."
                                + "Action class is: "
                                + AsyncUpdateAction.this.getClass().getName());
                      }
                      originalPresentation.copyFrom(realPresentation);
                    }
                  });
            }
          });

      originalPresentation.setVisible(true);
      originalPresentation.setEnabled(false);
    } else {
      performUpdate(originalPresentation, data);
    }
  }

  // Sync update
  @Override
  public final void beforeActionPerformedUpdate(@NotNull AnActionEvent e) {
    performUpdate(e.getPresentation(), prepareDataFromContext(e));
  }

  /**
   * Get all necessary data from event's DataContext to be used in <code>performUpdate()</code>,
   * which is called asynchronously.
   *
   * @param e action event original update() method have been called with.
   * @return prepared data for {@link #performUpdate} method.
   */
  protected abstract T prepareDataFromContext(final AnActionEvent e);

  /**
   * Perform real presentation tweaking here. Be aware of the fact this method may be called in
   * thread other than Swing UI thread thus probable restrictions like necessity to call
   * ApplcationManager.getApplication().runReadAction() apply.
   *
   * @param presentation Presentation object to be tweaked.
   * @param data necessary data calculated by {@link #prepareDataFromContext(AnActionEvent)}.
   */
  protected abstract void performUpdate(Presentation presentation, T data);

  /**
   * Override this method to return <code>true</code> value if update method cannot be called
   * asynchronously for whatever reason.
   *
   * @param e action event original update() method have been called with.
   * @return <code>false</code> if async update is possible and <code>false</code> otherwise.
   */
  protected boolean forceSyncUpdate(AnActionEvent e) {
    return false;
  }
}