Introduce UX scheduler
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 13 Dec 2023 09:50:39 +0000 (10:50 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 13 Dec 2023 09:50:39 +0000 (10:50 +0100)
org.argeo.api.cms/src/org/argeo/api/cms/ux/CmsUi.java
org.argeo.api.cms/src/org/argeo/api/cms/ux/CmsView.java
org.argeo.cms.ux/src/org/argeo/cms/ux/CmsUxUtils.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/AbstractSwtCmsView.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsSwtUi.java

index 2103e49894dcb17916dd75511dcc8acad48fc762..ff6f5f081c4fbf985db0e85a4885353471301a00 100644 (file)
@@ -5,6 +5,11 @@ public interface CmsUi {
        Object getData(String key);
 
        void setData(String key, Object value);
-       
+
        CmsView getCmsView();
+
+       long getLastAccess();
+
+       void updateLastAccess();
+
 }
index 121e4bdcbf601a654fc608aeda89ec895f4b4e3b..b231bea9935dd2b478bb054134243243858b8cbb 100644 (file)
@@ -3,6 +3,7 @@ package org.argeo.api.cms.ux;
 import java.net.URI;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.TimerTask;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Executors;
 
@@ -100,4 +101,10 @@ public interface CmsView {
                throw new UnsupportedOperationException();
        }
 
+       /** Schedule a one-shot UX task to be executed within the UX context/thread. */
+       TimerTask schedule(Runnable task, long delay);
+
+       /** Schedule a recurring UX task to be executed within the UX context/thread. */
+       TimerTask schedule(Runnable task, long delay, long period);
+
 }
index 84e471aafbe2103403a24ed7535c941469f0ff36..f9ced18df866c5780cf28b36ef4191d3e2269f44 100644 (file)
@@ -7,6 +7,7 @@ import org.argeo.api.cms.ux.Cms2DSize;
 import org.argeo.api.cms.ux.CmsView;
 import org.argeo.cms.util.CurrentSubject;
 
+/** Utilities around UX. */
 public class CmsUxUtils {
        public static ContentSession getContentSession(ContentRepository contentRepository, CmsView cmsView) {
                return CurrentSubject.callAs(cmsView.getCmsSession().getSubject(), () -> contentRepository.get());
@@ -16,11 +17,6 @@ public class CmsUxUtils {
                return content.getName().getLocalPart();
        }
 
-       /** singleton */
-       private CmsUxUtils() {
-
-       }
-
        public static StringBuilder imgBuilder(String src, String width, String height) {
                return new StringBuilder(64).append("<img width='").append(width).append("' height='").append(height)
                                .append("' src='").append(src).append("'");
@@ -33,4 +29,10 @@ public class CmsUxUtils {
        public static String img(String src, Cms2DSize size) {
                return img(src, Integer.toString(size.width()), Integer.toString(size.height()));
        }
+
+       /** singleton */
+       private CmsUxUtils() {
+
+       }
+
 }
index 06bb9be3727c1a81f9ad2dd8f598da15611a38d6..127be0856195fecf7b0d484a16e654030f6849c4 100644 (file)
@@ -2,6 +2,8 @@ package org.argeo.cms.swt;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionException;
@@ -24,6 +26,20 @@ import org.eclipse.swt.widgets.Display;
 public abstract class AbstractSwtCmsView implements CmsView {
        private final static CmsLog log = CmsLog.getLog(AbstractSwtCmsView.class);
 
+       /** A timer to be used to perform background UX tasks. */
+       private final static Timer uxTimer = new Timer(true);
+
+       static {
+               // purge every day
+               uxTimer.schedule(new TimerTask() {
+
+                       @Override
+                       public void run() {
+                               uxTimer.purge();
+                       }
+               }, 0, 24 * 60 * 60 * 1000);
+       }
+
        protected final String uiName;
 
        protected LoginContext loginContext;
@@ -138,4 +154,37 @@ public abstract class AbstractSwtCmsView implements CmsView {
                }
        }
 
+       @Override
+       public TimerTask schedule(Runnable task, long delay) {
+               TimerTask timerTask = newSwtUxTimerTask(task);
+               uxTimer.schedule(timerTask, delay);
+               return timerTask;
+       }
+
+       @Override
+       public TimerTask schedule(Runnable task, long delay, long period) {
+               TimerTask timerTask = newSwtUxTimerTask(task);
+               uxTimer.schedule(timerTask, delay, period);
+               return timerTask;
+       }
+
+       protected TimerTask newSwtUxTimerTask(Runnable todo) {
+               return new TimerTask() {
+
+                       @Override
+                       public void run() {
+                               synchronized (display) {
+                                       try {
+                                               if (!display.isDisposed()) {
+                                                       display.syncExec(() -> {
+                                                               todo.run();
+                                                       });
+                                               }
+                                       } catch (Exception e) {
+                                               log.error("Cannot run UX timer task", e);
+                                       }
+                               }
+                       }
+               };
+       }
 }
index e0f63e45e2eb85578428923964f1421fa1ba25fe..7aac07b155fdbeefba571bab54d03c8917b09a2c 100644 (file)
@@ -1,5 +1,7 @@
 package org.argeo.cms.swt;
 
+import java.util.TimerTask;
+
 import org.argeo.api.cms.ux.CmsUi;
 import org.argeo.api.cms.ux.CmsView;
 import org.eclipse.swt.layout.GridLayout;
@@ -10,17 +12,42 @@ public class CmsSwtUi extends Composite implements CmsUi {
 
        private static final long serialVersionUID = -107939076610406448L;
 
+       /** Last time the UI was accessed. */
+       private long lastAccess = System.currentTimeMillis();
+       private TimerTask timeoutTask;
+
        private CmsView cmsView;
 
        public CmsSwtUi(Composite parent, int style) {
                super(parent, style);
                cmsView = CmsSwtUtils.getCmsView(parent);
-
+               // TODO make timeout configurable
+               setUiTimeout(12 * 60 * 60 * 1000);// 12 hours
                setLayout(new GridLayout());
        }
 
+       @Override
        public CmsView getCmsView() {
                return cmsView;
        }
 
+       @Override
+       public long getLastAccess() {
+               return lastAccess;
+       }
+
+       @Override
+       public void updateLastAccess() {
+               this.lastAccess = System.currentTimeMillis();
+       }
+
+       public void setUiTimeout(long uiTimeout) {
+               if (timeoutTask != null)
+                       timeoutTask.cancel();
+               timeoutTask = cmsView.schedule(() -> {
+                       if (System.currentTimeMillis() - getLastAccess() >= uiTimeout)
+                               dispose();
+               }, 0, 1000);
+       }
+
 }
\ No newline at end of file