All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ui4j.webkit.browser.WebKitPage Maven / Gradle / Ivy

The newest version!
package com.ui4j.webkit.browser;

import java.lang.reflect.Field;
import java.net.URLStreamHandler;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.web.PromptData;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebEvent;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javafx.util.Callback;

import com.sun.webkit.network.URLs;
import com.ui4j.api.browser.BrowserType;
import com.ui4j.api.browser.Page;
import com.ui4j.api.dialog.AlertHandler;
import com.ui4j.api.dialog.ConfirmHandler;
import com.ui4j.api.dialog.DialogEvent;
import com.ui4j.api.dialog.PromptDialogEvent;
import com.ui4j.api.dialog.PromptHandler;
import com.ui4j.api.dom.Document;
import com.ui4j.api.dom.Window;
import com.ui4j.api.event.DocumentListener;
import com.ui4j.api.event.DocumentLoadEvent;
import com.ui4j.api.util.Logger;
import com.ui4j.api.util.LoggerFactory;
import com.ui4j.api.util.Ui4jException;
import com.ui4j.spi.JavaScriptEngine;
import com.ui4j.spi.PageView;
import com.ui4j.spi.Ui4jExecutionTimeoutException;
import com.ui4j.webkit.spi.WebKitJavaScriptEngine;

public class WebKitPage implements Page, PageView, JavaScriptEngine {

    private static final Logger LOG = LoggerFactory.getLogger(WebKitPage.class);

    private WebView webView;

    private Window window;

    private Document document;

    private Scene scene;

    private Stage stage;

    private List listeners = new ArrayList<>();

    private WebKitJavaScriptEngine engine;

	private int pageId;

    public static class SyncDocumentListener implements DocumentListener {

        private CountDownLatch latch;

        private Window window;

        private Document document;

        public SyncDocumentListener(CountDownLatch latch) {
            this.latch = latch;
        }

        @Override
        public void onLoad(DocumentLoadEvent event) {
            this.window = event.getWindow();
            this.document = event.getDocument();
            latch.countDown();
        }

        public Document getDocument() {
            return document;
        }

        public Window getWindow() {
            return window;
        }
    }

    public static class AlertDelegationHandler implements EventHandler> {

        private AlertHandler handler;

        public AlertDelegationHandler(AlertHandler handler) {
            this.handler = handler;
        }

        @Override
        public void handle(WebEvent event) {
            handler.handle(new DialogEvent(event.getData()));
        }
    }

    public static class PromptDelegationHandler implements Callback {

        private PromptHandler handler;

        public PromptDelegationHandler(PromptHandler handler) {
            this.handler = handler;
        }

        @Override
        public String call(PromptData param) {
            return handler.handle(new PromptDialogEvent(param.getMessage(), param.getDefaultValue()));
        }
    }

    public static class ConfirmDelegationHandler implements Callback {

        private ConfirmHandler handler;

        public ConfirmDelegationHandler(ConfirmHandler handler) {
            this.handler = handler;
        }

        @Override
        public Boolean call(String message) {
            return handler.handle(new DialogEvent(message));
        }
    }

    public static class DocumentDelegationListener implements ChangeListener {

        private Window window;

        private DocumentListener listener;

        public DocumentDelegationListener(Window window, DocumentListener listener) {
            this.window = window;
            this.listener = listener;
        }

        @Override
        public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
            if (newState == Worker.State.SUCCEEDED) {
                DocumentLoadEvent event = new DocumentLoadEvent(window);
                listener.onLoad(event);
            }
        }

        public DocumentListener getDocumentListener() {
            return listener;
        }
    }

    public WebKitPage(WebView webView, WebKitJavaScriptEngine engine, Window window, Document document, int pageId) {
        this.webView = webView;
        this.window = window;
        this.document = document;
        this.engine = engine;
        this.pageId = pageId;
    }

    @Override
    public void show(boolean maximized) {
        if (stage == null && scene == null) {
            stage = new Stage();
            scene = new Scene(webView, 600, 600);
            stage.setMaximized(maximized);
            stage.setScene(scene);
            stage.toFront();
            stage.show();
        }
    }

    @Override
    public void show() {
        show(false);
    }

    @Override
    public void addDocumentListener(DocumentListener listener) {
        WebEngine engine = webView.getEngine();
        DocumentDelegationListener delegationListener = new DocumentDelegationListener(window, listener);
        listeners.add(delegationListener);
        engine.getLoadWorker().stateProperty().addListener(delegationListener);
    }

    @Override
    public void removeListener(DocumentListener listener) {
        for (DocumentDelegationListener delegation : listeners) {
            if (delegation.getDocumentListener().equals(listener)) {
                WebEngine engine = webView.getEngine();
                engine.getLoadWorker().stateProperty().removeListener(delegation);
            }
        }
    }

	@Override
	@SuppressWarnings("unchecked")
    public void close() {
		// HACK #26
		Field handlerMap;
		try {
			handlerMap = URLs.class.getDeclaredField("handlerMap");
			handlerMap.setAccessible(true);
			Map handlers = (Map) handlerMap.get(null);
			handlers.remove("ui4j-" + String.valueOf(pageId));
		} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
			throw new Ui4jException(e);
		}
		// HACK #26
        if (getStage() != null) {
            getStage().close();
        }
    }

    @Override
    public void setAlertHandler(AlertHandler handler) {
        webView.getEngine().setOnAlert(new AlertDelegationHandler(handler));
    }

    @Override
    public void setPromptHandler(PromptHandler handler) {
        webView.getEngine().setPromptHandler(new PromptDelegationHandler(handler));
    }

    @Override
    public void setConfirmHandler(ConfirmHandler handler) {
        webView.getEngine().setConfirmHandler(new ConfirmDelegationHandler(handler));
    }

    @Override
    public void waitUntilDocReady() {
        waitUntilDocReady(60, TimeUnit.SECONDS);
    }

    @Override
    public void waitUntilDocReady(int timeout, TimeUnit unit) {
        String state = executeScript("document.readyState")
                                .toString()
                                .trim()
                                .toLowerCase(Locale.ENGLISH);
        if ("complete".equals(state)) {
            return;
        }
        LOG.debug("Waiting document ready, timeout=" + timeout + " " + unit.toString());
        CountDownLatch latch = new CountDownLatch(1);
        DocumentListener listener = new SyncDocumentListener(latch);
        addDocumentListener(listener);
        try {
            latch.await(timeout, unit);
        } catch (InterruptedException e) {
            throw new Ui4jExecutionTimeoutException(e, timeout, unit);
        }
        removeListener(listener);
    }

    @Override
    public void wait(int milliseconds) {
        LOG.debug("Waiting " + milliseconds + " milliseconds");
        try {
            Thread.sleep(milliseconds);
        } catch (InterruptedException e) {
            throw new Ui4jException(e);
        }
    }

    public WebView getWebView() {
        return webView;
    }

    @Override
    public Document getDocument() {
        return document;
    }

    @Override
    public Window getWindow() {
        return window;
    }

    public Scene getScene() {
        return scene;
    }

    public Stage getStage() {
        return stage;
    }

    @Override
    public void hide() {
        if (stage != null) {
            stage.hide();
        }
    }

    @Override
    public Object executeScript(String script) {
        Object result = engine.executeScript(script);

        String resultStr = String.valueOf(result);

        NumberFormat formatter = NumberFormat.getInstance();
        ParsePosition pos = new ParsePosition(0);
        Number number = formatter.parse(resultStr, pos);
        if (resultStr.length() == pos.getIndex()) {
            return number;
        }

        return result;
    }

    @Override
    public WebView getView() {
        return webView;
    }

    @Override
    public WebEngine getEngine() {
        return engine.getEngine();
    }

    @Override
    public BrowserType getBrowserType() {
        return BrowserType.WebKit;
    }

    public String getDocumentState() {
        return String.valueOf(webView.getEngine().executeScript("document.readyState"));
    }

	public int getPageId() {
		return pageId;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy