package com.intellij.flex.uiDesigner; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ComponentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.AsyncResult; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.util.Processor; import com.intellij.util.containers.Queue; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import static com.intellij.flex.uiDesigner.DocumentFactoryManager.DocumentInfo; class RenderActionQueue implements Runnable { private final Queue<RenderAction> queue = new Queue<>(4); private boolean suspended; // pending due to suspend private boolean wasPending; public void suspend() { suspended = true; } public void resume() { suspended = false; if (wasPending) { wasPending = false; execute(queue.peekFirst()); } } public void add(RenderAction renderAction) { queue.addLast(renderAction); if (queue.size() == 1) { execute(renderAction); } } private void execute(RenderAction renderAction) { if (suspended) { assert !wasPending; wasPending = true; return; } renderAction.result.doWhenProcessed(this); Application application = ApplicationManager.getApplication(); boolean isDispatchThread = application.isDispatchThread(); if (renderAction.isNeedEdt()) { if (isDispatchThread) { renderAction.run(); } else { application.invokeLater(renderAction); } } else { if (isDispatchThread) { application.executeOnPooledThread(renderAction); } else { renderAction.run(); } } } @Override public void run() { queue.pullFirst(); if (!queue.isEmpty()) { execute(queue.peekFirst()); } } public void processActions(Processor<RenderAction> processor) { synchronized (queue) { queue.process(processor); } } public AsyncResult<DocumentInfo> findResult(PsiFile psiFile) { return findResult(psiFile.getVirtualFile()); } @SuppressWarnings("unchecked") private <T extends AsyncResult> T findResult(@Nullable final VirtualFile file) { if (queue.size() == 1) { RenderAction action = queue.peekFirst(); return Comparing.equal(action.file, file) ? (T)action.result : null; } final Ref<AsyncResult> result = new Ref<>(); processActions(action -> { if (Comparing.equal(action.file, file)) { result.set(action.result); return false; } return true; }); return (T)result.get(); } public boolean isEmpty() { return queue.isEmpty(); } protected abstract static class RenderAction<T extends AsyncResult> implements Runnable { protected final VirtualFile file; protected final Project project; protected final T result; protected RenderAction(@Nullable Project project, @Nullable VirtualFile file, @NotNull T renderResult) { this.project = project; this.file = file; result = renderResult; } abstract protected boolean isNeedEdt(); @Override public final void run() { ComponentManager disposable = project == null ? ApplicationManager.getApplication() : project; if (disposable == null || disposable.isDisposed()) { result.setRejected(); } else { doRun(); } } protected abstract void doRun(); } }