Reputation: 1594
I am trying to make kind of a Chat with formatted input, my problem is that you are not able to put links into the JavaFX HTMLEditor by default, so i have added a button that replaces the selected text with a hyperlink. My problem is that 1: the hyperlink in the editor is clickable and will cause the editor to open the link if you click it and problem number 2: when i click the link in the webView it doesn't open in the external browser but inside of the webView itself, so it practially is the same Problem since the HTMLEditor is using a webView. Does anyone know how to "fix" that?
Upvotes: 1
Views: 1332
Reputation: 1791
Since the WebView in JavaFX uses java.net.URLConnection
underneath you can use its built in mechanisms to provide your custom handler that will create a connection which delegates the url to the OS that will open the url in the default browser. Here is an example:
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import javafx.application.Application;
import javafx.application.HostServices;
import javafx.scene.Scene;
import javafx.scene.web.HTMLEditor;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class HTMLEditorSample extends Application {
@Override
public void start(Stage stage) {
stage.setTitle("HTMLEditor Sample");
stage.setWidth(400);
stage.setHeight(300);
final HTMLEditor htmlEditor = new HTMLEditor();
htmlEditor.setPrefHeight(245);
Scene scene = new Scene(htmlEditor);
stage.setScene(scene);
stage.show();
URL.setURLStreamHandlerFactory(protocol -> {
if (protocol.startsWith("http")) {
return new CustomUrlHandler();
}
return null;
});
WebView webview = (WebView) htmlEditor.lookup(".web-view");
webview.getEngine().load("http://google.com");
}
public static void main(String[] args) {
launch(args);
}
public class CustomUrlHandler extends URLStreamHandler {
@Override
protected URLConnection openConnection(URL u) throws IOException {
return new HostServicesUrlConnection(u, getHostServices());
}
}
public class HostServicesUrlConnection extends HttpURLConnection {
private URL urlToOpen;
private HostServices hostServices;
protected HostServicesUrlConnection(URL u, HostServices hostServices) {
super(u);
this.urlToOpen= u;
this.hostServices = hostServices;
}
@Override
public void disconnect() {
// do nothing
}
@Override
public boolean usingProxy() {
return false;
}
@Override
public void connect() throws IOException {
hostServices.showDocument(urlToOpen.toExternalForm());
}
@Override
public InputStream getInputStream() throws IOException {
return new InputStream() {
@Override
public int read() throws IOException {
return 0;
}
};
}
}
}
UPDATE:
The previous solution will override the functionality for every other class that uses URLConnection which might not be what you want. I found an easier solution to the problem by playing with the location and state of the load worker. Note that the canceling of load worker without the Platform.runLater crashed the JVM on JDK version 8u66:
webview.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
@Override
public void changed(ObservableValue<? extends State> observable, State oldValue, State newValue) {
Platform.runLater(() -> {
webview.getEngine().getLoadWorker().cancel();
});
}
});
webview.getEngine().locationProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
getHostServices().showDocument(newValue);
}
});
Upvotes: 1