package org.openautonomousconnection.webclient.ui; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; import javafx.scene.Scene; import javafx.scene.web.WebEngine; import javafx.scene.web.WebHistory; import javafx.scene.web.WebView; import org.openautonomousconnection.oacswing.component.OACPanel; import org.openautonomousconnection.webclient.lua.WebLogger; import org.openautonomousconnection.webclient.settings.FxEngine; import java.awt.*; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** * A Swing panel that embeds a JavaFX WebView and runs LuaScript (no JavaScript). * *

Loads "web://" URLs so JavaFX can request subresources (CSS, images, href navigations) * through URLConnection (mapped to OAC WebRequestPacket).

*/ public final class TabView extends OACPanel { private final AtomicBoolean initialized = new AtomicBoolean(false); private JFXPanel fxPanel; private WebView webView; private WebEngine engine; private final Consumer onLocationChanged; private final WebLogger webLogger; private volatile FxEngine luaEngine; /** * Creates a new tab view. * * @param onLocationChanged callback invoked when the WebEngine location changes * @param url callback invoked on URL changes */ public TabView(Consumer onLocationChanged, String url) { super(); this.onLocationChanged = Objects.requireNonNull(onLocationChanged, "onLocationChanged"); this.webLogger = new WebLogger(url); setLayout(new BorderLayout()); } @Override public void addNotify() { super.addNotify(); if (!initialized.compareAndSet(false, true)) { return; } fxPanel = new JFXPanel(); add(fxPanel, BorderLayout.CENTER); Platform.runLater(() -> { webView = new WebView(); webView.setContextMenuEnabled(false); engine = webView.getEngine(); engine.setJavaScriptEnabled(false); engine.locationProperty().addListener((obs, oldV, newV) -> { if (newV != null) { onLocationChanged.accept(newV); } }); // Proper Lua integration from your library luaEngine = new FxEngine(engine, webView, webLogger); luaEngine.install(); fxPanel.setScene(new Scene(webView)); }); } /** * Loads a normalized URL (expected: web://...). * * @param url URL to load */ public void loadUrl(String url) { String u = Objects.requireNonNull(url, "url").trim(); if (u.isEmpty()) return; Platform.runLater(() -> { if (engine != null) { engine.load(u); } }); } /** * Reloads the current page. */ public void reload() { Platform.runLater(() -> { if (engine != null) engine.reload(); }); } /** * Navigates one step back in history if possible. */ public void back() { Platform.runLater(() -> { if (engine == null) return; WebHistory h = engine.getHistory(); if (h.getCurrentIndex() > 0) h.go(-1); }); } /** * Navigates one step forward in history if possible. */ public void forward() { Platform.runLater(() -> { if (engine == null) return; WebHistory h = engine.getHistory(); if (h.getCurrentIndex() < h.getEntries().size() - 1) h.go(1); }); } /** * Returns current engine location. * * @return location or null */ public String getEngineLocation() { return engine != null ? engine.getLocation() : null; } /** * Disposes resources. */ public void dispose() { FxEngine le = luaEngine; luaEngine = null; if (le != null) { try { le.close(); } catch (Exception ignored) { } } Platform.runLater(() -> { if (engine != null) { try { engine.load(null); } catch (Exception ignored) { } } engine = null; webView = null; if (fxPanel != null) { fxPanel.setScene(null); } }); } }