From 20c77f2bd654c45b88175ddb62d5dc6e8a1e52f9 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Fri, 1 Sep 2023 07:52:26 +0200 Subject: [PATCH] Clean up and document JavaScript related code. --- .../src/org/argeo/app/geo/ux/MapPart.java | 9 +- .../org/argeo/app/geo/swt/MapUiProvider.java | 2 +- .../app/geo/swt/SwtJavaScriptMapPart.java | 141 ++++++++++++++++++ .../src/org/argeo/app/geo/swt/SwtMapPart.java | 103 ------------- 4 files changed, 147 insertions(+), 108 deletions(-) create mode 100644 swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/SwtJavaScriptMapPart.java delete mode 100644 swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/SwtMapPart.java diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/ux/MapPart.java b/org.argeo.app.geo/src/org/argeo/app/geo/ux/MapPart.java index 29678ab..9e61531 100644 --- a/org.argeo.app.geo/src/org/argeo/app/geo/ux/MapPart.java +++ b/org.argeo.app.geo/src/org/argeo/app/geo/ux/MapPart.java @@ -2,15 +2,16 @@ package org.argeo.app.geo.ux; /** An UX part displaying a map. */ public interface MapPart { - enum Format { + /** A supported geographical data format. */ + enum GeoFormat { GEOJSON, GPX; } - void addPoint(Double lng, Double lat, String style); + void addPoint(double lng, double lat, String style); - void addUrlLayer(String url, Format format); + void addUrlLayer(String url, GeoFormat format); void setZoom(int zoom); - void setCenter(Double lng, Double lat); + void setCenter(double lng, double lat); } diff --git a/swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/MapUiProvider.java b/swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/MapUiProvider.java index 80f8752..517a2dc 100644 --- a/swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/MapUiProvider.java +++ b/swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/MapUiProvider.java @@ -10,7 +10,7 @@ public class MapUiProvider implements SwtUiProvider { @Override public Control createUiPart(Composite parent, Content context) { - SwtMapPart map = new SwtMapPart(parent, 0); + SwtJavaScriptMapPart map = new SwtJavaScriptMapPart(parent, 0); map.setCenter(13.404954, 52.520008); // Berlin // map.setCenter(-74.00597, 40.71427); // NYC // map.addPoint(-74.00597, 40.71427, null); diff --git a/swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/SwtJavaScriptMapPart.java b/swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/SwtJavaScriptMapPart.java new file mode 100644 index 0000000..7d5d71d --- /dev/null +++ b/swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/SwtJavaScriptMapPart.java @@ -0,0 +1,141 @@ +package org.argeo.app.geo.swt; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.argeo.api.cms.CmsConstants; +import org.argeo.api.cms.CmsLog; +import org.argeo.api.cms.ux.CmsView; +import org.argeo.app.geo.ux.JsImplementation; +import org.argeo.app.geo.ux.MapPart; +import org.argeo.app.ux.SuiteUxEvent; +import org.argeo.cms.swt.CmsSwtUtils; +import org.eclipse.swt.SWT; +import org.eclipse.swt.browser.Browser; +import org.eclipse.swt.browser.BrowserFunction; +import org.eclipse.swt.browser.ProgressEvent; +import org.eclipse.swt.browser.ProgressListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; + +/** + * An SWT implementation of {@link MapPart} based on JavaScript execute in a + * {@link Browser} control. + */ +public class SwtJavaScriptMapPart extends Composite implements MapPart { + static final long serialVersionUID = 2713128477504858552L; + + private final static CmsLog log = CmsLog.getLog(SwtJavaScriptMapPart.class); + + private Browser browser; + + private CompletableFuture pageLoaded = new CompletableFuture<>(); + + private String jsImplementation = JsImplementation.OPENLAYERS_MAP_PART.getJsClass(); + private String mapVar = "globalThis.argeoMap"; + + private final CmsView cmsView; + + public SwtJavaScriptMapPart(Composite parent, int style) { + super(parent, style); + parent.setLayout(CmsSwtUtils.noSpaceGridLayout()); + setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + setLayout(CmsSwtUtils.noSpaceGridLayout()); + + cmsView = CmsSwtUtils.getCmsView(parent); + + browser = new Browser(this, SWT.BORDER); + browser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + // functions exposed to JavaScript + new onFeatureSelect(); + + browser.setUrl("/pkg/org.argeo.app.geo.js/index.html"); + browser.addProgressListener(new ProgressListener() { + static final long serialVersionUID = 1L; + + @Override + public void completed(ProgressEvent event) { + try { + // create map + browser.execute(mapVar + " = new " + jsImplementation + "();"); + pageLoaded.complete(true); + } catch (Exception e) { + log.error("Cannot create map in browser", e); + pageLoaded.complete(false); + } + } + + @Override + public void changed(ProgressEvent event) { + } + }); + } + + @Override + public void addPoint(double lng, double lat, String style) { + callMethod(mapVar, "addPoint(%f, %f, %s)", lng, lat, style == null ? "'default'" : style); + } + + @Override + public void addUrlLayer(String url, GeoFormat format) { + callMethod(mapVar, "addUrlLayer('%s', '%s')", url, format.name()); + } + + @Override + public void setZoom(int zoom) { + callMethod(mapVar, "setZoom(%d)", zoom); + } + + @Override + public void setCenter(double lng, double lat) { + callMethod(mapVar, "setCenter(%f, %f)", lng, lat); + } + + protected CompletionStage callMethod(String jsObject, String methodCall, Object... args) { + return evaluate(jsObject + '.' + methodCall, args); + } + + /** + * Execute this JavaScript on the client side after making sure that the page + * has been loaded and the map object has been created. + * + * @param js the JavaScript code, possibly formatted according to + * {@link String#format}, with {@link Locale#ROOT} as locale (for + * stability of decimal separator, as expected by JavaScript. + * @param args the optional arguments of + * {@link String#format(String, Object...)} + */ + protected CompletionStage evaluate(String js, Object... args) { + CompletableFuture res = pageLoaded.thenApply((ready) -> { + if (!ready) + throw new IllegalStateException("Map " + mapVar + " is not initialised."); + Object result = browser.evaluate(String.format(Locale.ROOT, js, args)); + return result; + }); + return res.minimalCompletionStage(); + } + + /** JavaScript function called when a feature is selected on the map. */ + private class onFeatureSelect extends BrowserFunction { + + onFeatureSelect() { + super(browser, onFeatureSelect.class.getSimpleName()); + } + + @Override + public Object function(Object[] arguments) { + if (arguments.length == 0) + return null; + String path = arguments[0].toString(); + Map properties = new HashMap<>(); + properties.put(SuiteUxEvent.CONTENT_PATH, '/' + CmsConstants.SYS_WORKSPACE + path); + cmsView.sendEvent(SuiteUxEvent.refreshPart.topic(), properties); + return null; + } + + } +} diff --git a/swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/SwtMapPart.java b/swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/SwtMapPart.java deleted file mode 100644 index 003b6b5..0000000 --- a/swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/SwtMapPart.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.argeo.app.geo.swt; - -import java.util.concurrent.CompletableFuture; - -import org.argeo.app.geo.ux.JsImplementation; -import org.argeo.app.geo.ux.MapPart; -import org.argeo.cms.swt.CmsSwtUtils; -import org.eclipse.swt.SWT; -import org.eclipse.swt.browser.Browser; -import org.eclipse.swt.browser.ProgressEvent; -import org.eclipse.swt.browser.ProgressListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Composite; - -public class SwtMapPart extends Composite implements MapPart { - static final long serialVersionUID = 2713128477504858552L; - private Browser browser; - - // private CompletableFuture renderCompleted = new - // CompletableFuture<>(); - private CompletableFuture pageLoaded = new CompletableFuture<>(); - - private String jsImplementation = JsImplementation.OPENLAYERS_MAP_PART.getJsClass(); - private String mapVar = "globalThis.argeoMap"; - - public SwtMapPart(Composite parent, int style) { - super(parent, style); - parent.setLayout(CmsSwtUtils.noSpaceGridLayout()); - setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - setLayout(CmsSwtUtils.noSpaceGridLayout()); - browser = new Browser(this, SWT.BORDER); - browser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - // functions exposed to JavaScript -// new onRenderComplete(); - browser.setUrl("/pkg/org.argeo.app.geo.js/index.html"); - browser.addProgressListener(new ProgressListener() { - static final long serialVersionUID = 1L; - - @Override - public void completed(ProgressEvent event) { - - // create map - browser.execute(mapVar + " = new " + jsImplementation + "();"); - - // browser.execute("console.log(myInstance.myField)"); - pageLoaded.complete(true); - } - - @Override - public void changed(ProgressEvent event) { - } - }); - } - - @Override - public void addPoint(Double lng, Double lat, String style) { - pageLoaded.thenAccept((b) -> { - browser.evaluate( - mapVar + ".addPoint(" + lng + ", " + lat + "," + (style == null ? "'default'" : style) + ")"); - }); - } - - @Override - public void addUrlLayer(String url, Format format) { - pageLoaded.thenAccept((b) -> { - browser.evaluate(mapVar + ".addUrlLayer('" + url + "','" + format.name() + "')"); - }); - } - - @Override - public void setZoom(int zoom) { - pageLoaded.thenAccept((b) -> { - browser.evaluate(mapVar + ".setZoom(" + zoom + ")"); - }); - } - - @Override - public void setCenter(Double lng, Double lat) { - pageLoaded.thenAccept((b) -> { - browser.evaluate(mapVar + ".setCenter(" + lng + ", " + lat + ")"); - }); - - } - -// private void setRenderCompleted() { -// renderCompleted.complete(true); -// } -// -// private class onRenderComplete extends BrowserFunction { -// -// onRenderComplete() { -// super(browser, onRenderComplete.class.getSimpleName()); -// } -// -// @Override -// public Object function(Object[] arguments) { -// setRenderCompleted(); -// System.out.println("Render complete (Java)"); -// return null; -// } -// -// } -} -- 2.30.2