예제 #1
0
  public Alarm(@NotNull ThreadToUse threadToUse, Disposable parentDisposable) {
    myThreadToUse = threadToUse;
    myExecutorService =
        threadToUse == ThreadToUse.OWN_THREAD
            ? ConcurrencyUtil.newSingleThreadExecutor("Alarm pool(own)", Thread.NORM_PRIORITY - 2)
            : ourSharedExecutorService;

    if (parentDisposable != null) {
      Disposer.register(parentDisposable, this);
    }
  }
예제 #2
0
public class Alarm implements Disposable {
  private static final Logger LOG = Logger.getInstance("#com.intellij.util.Alarm");

  private volatile boolean myDisposed;

  private final List<Request> myRequests = new ArrayList<Request>();
  private final List<Request> myPendingRequests = new ArrayList<Request>();

  private final ExecutorService myExecutorService;

  private static final ThreadPoolExecutor ourSharedExecutorService =
      ConcurrencyUtil.newSingleThreadExecutor("Alarm pool(shared)", Thread.NORM_PRIORITY - 2);

  private final Object LOCK = new Object();
  private final ThreadToUse myThreadToUse;

  private JComponent myActivationComponent;

  @Override
  public void dispose() {
    myDisposed = true;
    cancelAllRequests();

    if (myThreadToUse == ThreadToUse.POOLED_THREAD) {
      myExecutorService.shutdown();
    } else if (myThreadToUse == ThreadToUse.OWN_THREAD) {
      myExecutorService.shutdown();
      ((ThreadPoolExecutor) myExecutorService).getQueue().clear();
    }
  }

  public enum ThreadToUse {
    SWING_THREAD,
    SHARED_THREAD,
    POOLED_THREAD,
    OWN_THREAD
  }

  /** Creates alarm that works in Swing thread */
  public Alarm() {
    this(ThreadToUse.SWING_THREAD);
  }

  public Alarm(Disposable parentDisposable) {
    this(ThreadToUse.SWING_THREAD, parentDisposable);
  }

  public Alarm(@NotNull ThreadToUse threadToUse) {
    this(threadToUse, null);
    LOG.assertTrue(
        threadToUse != ThreadToUse.POOLED_THREAD && threadToUse != ThreadToUse.OWN_THREAD,
        "You must provide parent Disposable for ThreadToUse.POOLED_THREAD and ThreadToUse.OWN_THREAD Alarm");
  }

  public Alarm(@NotNull ThreadToUse threadToUse, Disposable parentDisposable) {
    myThreadToUse = threadToUse;

    if (threadToUse == ThreadToUse.POOLED_THREAD) {
      myExecutorService = new MyExecutor();
    } else if (threadToUse == ThreadToUse.OWN_THREAD) {
      myExecutorService =
          ConcurrencyUtil.newSingleThreadExecutor("Alarm pool(own)", Thread.NORM_PRIORITY - 2);
    } else {
      myExecutorService = ourSharedExecutorService;
    }

    if (parentDisposable != null) {
      Disposer.register(parentDisposable, this);
    }
  }

  public void addRequest(
      @NotNull final Runnable request, final int delay, boolean runWithActiveFrameOnly) {
    if (runWithActiveFrameOnly && !ApplicationManager.getApplication().isActive()) {
      final MessageBus bus = ApplicationManager.getApplication().getMessageBus();
      final MessageBusConnection connection = bus.connect(this);
      connection.subscribe(
          ApplicationActivationListener.TOPIC,
          new ApplicationActivationListener() {
            @Override
            public void applicationActivated(IdeFrame ideFrame) {
              connection.disconnect();
              addRequest(request, delay);
            }

            @Override
            public void applicationDeactivated(IdeFrame ideFrame) {}
          });
    } else {
      addRequest(request, delay);
    }
  }

  public void addRequest(@NotNull Runnable request, long delayMillis) {
    _addRequest(
        request,
        delayMillis,
        myThreadToUse == ThreadToUse.SWING_THREAD ? ModalityState.current() : null);
  }

  public void addRequest(@NotNull Runnable request, int delayMillis) {
    _addRequest(
        request,
        delayMillis,
        myThreadToUse == ThreadToUse.SWING_THREAD ? ModalityState.current() : null);
  }

  public void addComponentRequest(@NotNull Runnable request, int delay) {
    assert myActivationComponent != null;
    _addRequest(request, delay, ModalityState.stateForComponent(myActivationComponent));
  }

  public void addComponentRequest(@NotNull Runnable request, long delayMillis) {
    assert myActivationComponent != null;
    _addRequest(request, delayMillis, ModalityState.stateForComponent(myActivationComponent));
  }

  public void addRequest(
      @NotNull Runnable request, int delayMillis, @Nullable final ModalityState modalityState) {
    LOG.assertTrue(myThreadToUse == ThreadToUse.SWING_THREAD);
    _addRequest(request, delayMillis, modalityState);
  }

  public void addRequest(
      @NotNull Runnable request, long delayMillis, @Nullable final ModalityState modalityState) {
    LOG.assertTrue(myThreadToUse == ThreadToUse.SWING_THREAD);
    _addRequest(request, delayMillis, modalityState);
  }

  private void _addRequest(
      @NotNull Runnable request, long delayMillis, ModalityState modalityState) {
    synchronized (LOCK) {
      LOG.assertTrue(!myDisposed, "Already disposed");
      final Request requestToSchedule = new Request(request, modalityState, delayMillis);

      if (myActivationComponent == null || myActivationComponent.isShowing()) {
        _add(requestToSchedule);
      } else {
        if (!myPendingRequests.contains(requestToSchedule)) {
          myPendingRequests.add(requestToSchedule);
        }
      }
    }
  }

  private void _add(@NotNull Request requestToSchedule) {
    final ScheduledFuture<?> future =
        JobScheduler.getScheduler()
            .schedule(requestToSchedule, requestToSchedule.myDelay, TimeUnit.MILLISECONDS);
    requestToSchedule.setFuture(future);
    myRequests.add(requestToSchedule);
  }

  private void flushPending() {
    for (Request each : myPendingRequests) {
      _add(each);
    }

    myPendingRequests.clear();
  }

  public boolean cancelRequest(@NotNull Runnable request) {
    synchronized (LOCK) {
      cancelRequest(request, myRequests);
      cancelRequest(request, myPendingRequests);
      return true;
    }
  }

  private void cancelRequest(@NotNull Runnable request, @NotNull List<Request> list) {
    for (int i = list.size() - 1; i >= 0; i--) {
      Request r = list.get(i);
      if (r.getTask() == request) {
        r.cancel();
        list.remove(i);
      }
    }
  }

  public int cancelAllRequests() {
    synchronized (LOCK) {
      int count = cancelAllRequests(myRequests);
      cancelAllRequests(myPendingRequests);
      return count;
    }
  }

  private int cancelAllRequests(@NotNull List<Request> list) {
    int count = 0;
    for (Request request : list) {
      count++;
      request.cancel();
    }
    list.clear();
    return count;
  }

  public int getActiveRequestCount() {
    synchronized (LOCK) {
      return myRequests.size();
    }
  }

  protected boolean isEdt() {
    return isEventDispatchThread();
  }

  public static boolean isEventDispatchThread() {
    final Application app = ApplicationManager.getApplication();
    return app != null && app.isDispatchThread() || EventQueue.isDispatchThread();
  }

  private class Request implements Runnable {
    private Runnable myTask;
    private final ModalityState myModalityState;
    private Future<?> myFuture;
    private final long myDelay;

    private Request(
        @NotNull Runnable task, @Nullable ModalityState modalityState, long delayMillis) {
      myTask = task;
      myModalityState = modalityState;
      myDelay = delayMillis;
    }

    @Override
    public void run() {
      try {
        if (myDisposed) {
          return;
        }
        synchronized (LOCK) {
          if (myTask == null) return;
        }

        final Runnable scheduledTask =
            new Runnable() {
              @Override
              public void run() {
                final Runnable task;
                synchronized (LOCK) {
                  task = myTask;
                  if (task == null) return;
                  myTask = null;

                  myRequests.remove(Request.this);
                }

                if (myThreadToUse == ThreadToUse.SWING_THREAD && !isEdt()) {
                  try {
                    SwingUtilities.invokeAndWait(task);
                  } catch (Exception e) {
                    LOG.error(e);
                  }
                } else {
                  try {
                    task.run();
                  } catch (Exception e) {
                    LOG.error(e);
                  }
                }
              }
            };

        if (myModalityState == null) {
          myFuture = myExecutorService.submit(scheduledTask);
        } else {
          final Application app = ApplicationManager.getApplication();
          if (app != null) {
            app.invokeLater(scheduledTask, myModalityState);
          } else {
            SwingUtilities.invokeLater(scheduledTask);
          }
        }
      } catch (Throwable e) {
        LOG.error(e);
      }
    }

    private Runnable getTask() {
      return myTask;
    }

    public void setFuture(@NotNull ScheduledFuture<?> future) {
      myFuture = future;
    }

    public ModalityState getModalityState() {
      return myModalityState;
    }

    private void cancel() {
      synchronized (LOCK) {
        if (myFuture != null) {
          myFuture.cancel(false);
        }
        myTask = null;
      }
    }

    @Override
    public String toString() {
      Runnable task = myTask;
      return super.toString() + (task != null ? task.toString() : null);
    }
  }

  public Alarm setActivationComponent(@NotNull final JComponent component) {
    myActivationComponent = component;
    new UiNotifyConnector(
        component,
        new Activatable() {
          @Override
          public void showNotify() {
            flushPending();
          }

          @Override
          public void hideNotify() {}
        });

    return this;
  }

  public boolean isDisposed() {
    return myDisposed;
  }

  private class MyExecutor extends AbstractExecutorService {
    private final AtomicBoolean isShuttingDown = new AtomicBoolean();
    private final QueueProcessor<Runnable> myProcessor =
        QueueProcessor.createRunnableQueueProcessor();

    @Override
    public void shutdown() {
      myProcessor.clear();
      isShuttingDown.set(myDisposed);
    }

    @Override
    public List<Runnable> shutdownNow() {
      throw new UnsupportedOperationException();
    }

    @Override
    public boolean isShutdown() {
      return isShuttingDown.get();
    }

    @Override
    public boolean isTerminated() {
      return isShutdown() && myProcessor.isEmpty();
    }

    @Override
    public boolean awaitTermination(long timeout, @NotNull TimeUnit unit)
        throws InterruptedException {
      throw new UnsupportedOperationException();
    }

    @Override
    public void execute(@NotNull Runnable command) {
      myProcessor.add(command);
    }
  }
}