X-Git-Url: https://git.argeo.org/?p=gpl%2Fargeo-suite.git;a=blobdiff_plain;f=org.argeo.app.ui%2Fsrc%2Forg%2Fargeo%2Fapp%2Fui%2Fwidgets%2FDelayedText.java;h=ecf66396868364ba893c187a5dbf0014babe04bd;hp=1eab6d6a9c359a92a9a5a33b6c4683069cf4541f;hb=37b8da6d2986158840e40e61e44ed7cd5d6455fa;hpb=91e07cbcf67fdadf1e1b7233a458fc7bc69cc6e5 diff --git a/org.argeo.app.ui/src/org/argeo/app/ui/widgets/DelayedText.java b/org.argeo.app.ui/src/org/argeo/app/ui/widgets/DelayedText.java index 1eab6d6..ecf6639 100644 --- a/org.argeo.app.ui/src/org/argeo/app/ui/widgets/DelayedText.java +++ b/org.argeo.app.ui/src/org/argeo/app/ui/widgets/DelayedText.java @@ -1,117 +1,91 @@ package org.argeo.app.ui.widgets; -import java.util.Timer; -import java.util.TimerTask; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import org.eclipse.rap.rwt.service.ServerPushSession; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Text; /** - * Text that introduce a timer in the attached ModifyListener. - * - * Note that corresponding ModifyEvent will *NOT* be sent in the UI thread. - * Calling ModifierInstance must be implemented in consequence. Note also that - * this delayed text only manages one listener at a time. - * + * A text input which notifies changes after a delay, typically in order to + * apply a filter. */ public class DelayedText { - final int delay; - private Object lock = new Object(); - private MyTimer timer = new MyTimer(DelayedText.this.toString()); - private ModifyListener delayedModifyListener; - private ServerPushSession pushSession; - - private Text text; - - private ModifyListener modifyListener = new ModifyListener() { - private static final long serialVersionUID = 1117506414462641980L; + private final static ScheduledExecutorService scheduler; + static { + // create only one scheduler, in order not to exhaust threads + scheduler = Executors.newScheduledThreadPool(0, (r) -> { + Thread thread = new Thread(r, "Delayed text scheduler"); + // we mark threads as deamons so that the shutdown hook is triggered + thread.setDaemon(true); + return thread; + }); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + scheduler.shutdown(); + }, "Shutdown delayed text scheduler")); + } + private final static int DEFAULT_DELAY = 800; - public void modifyText(ModifyEvent e) { - ModifyEvent delayedEvent = null; - synchronized (lock) { - if (delayedModifyListener != null) { - Event tmpEvent = new Event(); - tmpEvent.widget = text; - tmpEvent.display = e.display; - tmpEvent.data = e.data; - tmpEvent.time = e.time; - delayedEvent = new ModifyEvent(tmpEvent); - } - } - final ModifyEvent timerModifyEvent = delayedEvent; + private final long delay; + private final InternalModifyListener modifyListener; + private final Text text; + protected List> toDos = new ArrayList<>(); + private ServerPushSession pushSession; - synchronized (timer) { - if (timer.timerTask != null) { - timer.timerTask.cancel(); - timer.timerTask = null; - } + private ScheduledFuture lastTask; - if (delayedEvent != null) { - timer.timerTask = new TimerTask() { - public void run() { - synchronized (lock) { - delayedModifyListener.modifyText(timerModifyEvent); - } - synchronized (timer) { - timer.timerTask = null; - } - } - }; - timer.schedule(timer.timerTask, delay); - if (pushSession != null) - pushSession.start(); - } - } - }; - }; + public DelayedText(Composite parent, int style) { + this(parent, style, DEFAULT_DELAY); + } - public DelayedText(Composite parent, int style, int delayInMs) { - // super(parent, style); - text = new Text(parent, style); + public DelayedText(Composite parent, int style, long delayInMs) { this.delay = delayInMs; + this.modifyListener = new InternalModifyListener(); + pushSession = new ServerPushSession(); + pushSession.start(); + text = new Text(parent, style); text.addModifyListener(modifyListener); } - /** - * Adds a modify text listener that will be delayed. If another Modify event - * happens during the waiting delay, the older event will be cancelled an a new - * one will be scheduled after another new delay. - */ - public void addDelayedModifyListener(ServerPushSession pushSession, ModifyListener listener) { - synchronized (lock) { - delayedModifyListener = listener; - this.pushSession = pushSession; + protected void notifyText(String txt) { + // text.getDisplay().syncExec(()-> pushSession.start()); + for (Consumer toDo : toDos) { + text.getDisplay().syncExec(() -> toDo.accept(txt)); } + // text.getDisplay().syncExec(()->pushSession.stop()); } - public void removeDelayedModifyListener(ModifyListener listener) { - synchronized (lock) { - delayedModifyListener = null; - pushSession = null; - } + public Text getText() { + return text; } - private class MyTimer extends Timer { - private TimerTask timerTask = null; - - public MyTimer(String name) { - super(name); - } + public void addListener(Consumer toDo) { + toDos.add(toDo); } - public Text getText() { - return text; - } + private class InternalModifyListener implements ModifyListener { + private static final long serialVersionUID = -6178431173400385005L; - public void close() { - if (pushSession != null) - pushSession.stop(); - if (timer != null) - timer.cancel(); + public void modifyText(ModifyEvent e) { + String txt = text.getText(); + ScheduledFuture task = scheduler.schedule(() -> { + notifyText(txt); + return txt; + }, delay, TimeUnit.MILLISECONDS); + // cancel previous task + if (lastTask != null && !lastTask.isDone()) { + lastTask.cancel(false); + } + lastTask = task; + } }; }