/** * 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; } }