blob: 56f78ed05c7138ffae60e14d55c64782747c0190 [file] [log] [blame]
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.find.actions;
import com.intellij.openapi.util.Condition;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Runs activity in the EDT.
* To schedule activity, call {@link #ping()}. It sets the flag telling that the activity should be run. Once it has run, the flag is cleared.
* So you can call ping() several times, but the activity will be executed only once.
* If activity took more than {@code maxUnitOfWorkThresholdMs} ms, it will yield till the next invokeLater.
*/
class PingEDT {
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
private final String myName;
private final Runnable pingAction;
private volatile boolean stopped;
private volatile boolean pinged;
private final Condition<?> myShutUpCondition;
private final int myMaxUnitOfWorkThresholdMs; //-1 means indefinite
private final AtomicBoolean invokeLaterScheduled = new AtomicBoolean();
private final Runnable myUpdateRunnable = new Runnable() {
@Override
public void run() {
boolean b = invokeLaterScheduled.compareAndSet(true, false);
assert b;
if (stopped || myShutUpCondition.value(null)) {
stop();
return;
}
long start = System.currentTimeMillis();
int processed = 0;
while (true) {
if (processNext()) {
processed++;
}
else {
break;
}
long finish = System.currentTimeMillis();
if (myMaxUnitOfWorkThresholdMs != -1 && finish - start > myMaxUnitOfWorkThresholdMs) break;
}
if (!isEmpty()) {
scheduleUpdate();
}
}
};
public PingEDT(@NotNull @NonNls String name,
@NotNull Condition<?> shutUpCondition,
int maxUnitOfWorkThresholdMs,
@NotNull Runnable pingAction) {
myName = name;
myShutUpCondition = shutUpCondition;
myMaxUnitOfWorkThresholdMs = maxUnitOfWorkThresholdMs;
this.pingAction = pingAction;
}
private boolean isEmpty() {
return !pinged;
}
private boolean processNext() {
pinged = false;
pingAction.run();
return pinged;
}
// returns true if invokeLater was called
public boolean ping() {
pinged = true;
return scheduleUpdate();
}
// returns true if invokeLater was called
private boolean scheduleUpdate() {
if (!stopped && invokeLaterScheduled.compareAndSet(false, true)) {
SwingUtilities.invokeLater(myUpdateRunnable);
return true;
}
return false;
}
public void stop() {
stopped = true;
}
}