/**
*
*/
package com.netifera.platform.ui.updater;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
/**
* @author kevin
*
*/
public abstract class ControlUpdater implements Runnable {
/* default 128 millisecond default delay between updates */
private static final int DEFAULT_DELAY = 128;
private final ScheduledTask scheduledTask;
private final Control control;
private volatile boolean disposed;
private Queue<Runnable> extraTasks = new ConcurrentLinkedQueue<Runnable>();
protected static Map<Control, ControlUpdater> controlToUpdater = new HashMap<Control, ControlUpdater>();
protected ControlUpdater(Control control) {
this.control = control;
scheduledTask = new ScheduledTask(this, 0, DEFAULT_DELAY);
/* register this new updater in the global map */
ControlUpdater.put(this);
}
protected static ControlUpdater get(Control control) {
synchronized (controlToUpdater) {
return controlToUpdater.get(control);
}
}
private static void put(final ControlUpdater controlUpdater) {
final Control control = controlUpdater.getControl();
/* add dispose listener to the wrapped control */
controlUpdater.addDisposeListener(new Listener() {
public void handleEvent(Event event) {
/* dispose the wrapper when the control is disposed */
controlUpdater.dispose();
}
});
synchronized (controlToUpdater) {
controlToUpdater.put(control, controlUpdater);
}
}
public void addDisposeListener(final Listener listener) {
if(!control.isDisposed()) {
control.addListener(SWT.Dispose, listener);
}
}
private static void remove(Control control) {
synchronized (controlToUpdater) {
if (controlToUpdater.containsKey(control)) {
controlToUpdater.remove(control);
}
}
}
/**
* If not already disposed, removes the updater from the scheduler and the
* control to updater map. The disposed flag is set.
*/
public void dispose() {
/* check if already disposed, it is only optimization */
if (disposed) {
return;
}
disposed = true;
/* remove from the viewer to updater global map */
remove(getControl());
/* remove the updater task from the scheduler */
scheduledTask.cancel();
}
protected boolean checkDisposed() {
if (getControl().isDisposed()) {
dispose();
}
return disposed;
}
protected void scheduleUpdate() {
scheduledTask.schedule();
}
public boolean asyncExec(Runnable task) {
return extraTasks.offer(task);
}
public void run() {
if (checkDisposed()) {
return;
}
if (Display.getCurrent() == null) {
getControl().getDisplay().syncExec(new Runnable() {
public void run() {
updateControl();
while (!extraTasks.isEmpty()) {
Runnable task = extraTasks.poll();
task.run();
}
}
});
} else {
updateControl();
}
}
public final Control getControl() {
return control;
}
public void setPeriod(int period) {
scheduledTask.setPeriod(period);
}
protected abstract void updateControl();
}