package com.twasyl.slideshowfx.controllers;
import com.twasyl.slideshowfx.utils.ResourceHelper;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Side;
import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.scene.web.WebHistory;
import javafx.scene.web.WebView;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ResourceBundle;
/**
* The controller class for the internal browser view.
* @author Thierry Wasylczenko
* @version 1.0
* @since SlideshowFX 1.0
*/
public class InternalBrowserController implements Initializable {
@FXML private TextField addressBar;
@FXML private WebView browser;
@FXML private HBox addressPanel;
@FXML private Button previousPage;
@FXML private Button nextPage;
private final ContextMenu browsingHistoryContextMenu = new ContextMenu();
/**
* This method is called when a key is pressed within the address bar.
* @param event The event source.
*/
@FXML private void manageKeyPressed(KeyEvent event) {
if(event.getCode() == KeyCode.ENTER) {
this.browsingHistoryContextMenu.hide();
this.loadPage(this.addressBar.getText());
}
}
@FXML private void navigateToPreviousPage(ActionEvent event) {
this.goToPage(-1);
}
@FXML private void navigateToNextPage(ActionEvent event) {
this.goToPage(1);
}
/**
* Loads the given {@code address} in the browser. If the address to load doesn't start with {@code http://} or
* {@code https://}, {@code http://} will be appended at the beginning of the address to load.
* If the address is {@code null} or empty, nothing will be thrown and an error will not be raised.
* @param address The address to load.
*/
private void loadPage(final String address) {
if(address != null && !address.isEmpty()) {
final StringBuilder builder = new StringBuilder();
if(!address.startsWith("http://") && !address.startsWith("https://") && !address.startsWith("file://")) {
builder.append("http://");
}
builder.append(address);
this.browser.getEngine().load(builder.toString());
}
}
/**
* Navigate to the browsing history. This method calls {@link WebHistory#go(int)} with the {@code offset} passed in
* parameter.
* @param offset The offset to navigate to the page.
*/
private void goToPage(int offset) {
this.browser.getEngine().getHistory().go(offset);
this.addressBar.setText(this.browser.getEngine().getLocation());
this.browsingHistoryContextMenu.hide();
}
/**
* Displays the context menu for the address bar which contains the URL starting with {@code partialAddress} in the
* browsing history.
* If the {@code partialAddress} is {@code null} or empty, nothing is displayed.
*
* @param partialAddress The partial address to look in the browsing history.
*/
private void displayBrowsingHistorySuggestion(final String partialAddress) {
this.browsingHistoryContextMenu.getItems().clear();
if(partialAddress != null && !partialAddress.isEmpty()) {
this.browser.getEngine().getHistory().getEntries().forEach(entry -> {
try {
final URL url = new URL(entry.getUrl());
final String lowerCasePartialAddress = partialAddress.toLowerCase();
if(entry.getUrl().toLowerCase().startsWith(lowerCasePartialAddress) ||
(url.getAuthority() != null && (url.getAuthority().startsWith(lowerCasePartialAddress) ||
(url.getAuthority().startsWith("www.") && url.getAuthority().substring(4).startsWith(lowerCasePartialAddress)))) ||
(entry.getTitle() != null && entry.getTitle().toLowerCase().startsWith(lowerCasePartialAddress))) {
final MenuItem menuItem = new Menu(entry.getUrl());
menuItem.setOnAction(event -> {
this.addressBar.setText(entry.getUrl());
this.browsingHistoryContextMenu.hide();
this.loadPage(entry.getUrl());
});
this.browsingHistoryContextMenu.getItems().add(menuItem);
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
});
if(!this.browsingHistoryContextMenu.getItems().isEmpty()) {
this.browsingHistoryContextMenu.show(this.addressBar, Side.BOTTOM, 0, 0);
}
} else {
this.browsingHistoryContextMenu.hide();
}
}
@Override
public void initialize(URL location, ResourceBundle resources) {
this.browsingHistoryContextMenu.setAutoFix(true);
this.browsingHistoryContextMenu.setHideOnEscape(true);
this.addressBar.textProperty().addListener((textValue, oldText, newText) -> {
this.displayBrowsingHistorySuggestion(newText);
});
this.browser.getEngine().load(ResourceHelper.getExternalForm("/com/twasyl/slideshowfx/html/empty-webview.html"));
final WebHistory webHistory = this.browser.getEngine().getHistory();
BooleanBinding isHistoryEmpty = Bindings.isEmpty(webHistory.getEntries());
BooleanBinding isFirstPageDisplayed = isHistoryEmpty.or(webHistory.currentIndexProperty().isEqualTo(0));
BooleanBinding isLastPageDisplayed = isHistoryEmpty.or(webHistory.currentIndexProperty().isEqualTo(Bindings.size(webHistory.getEntries()).subtract(1)));
this.previousPage.disableProperty().bind(isFirstPageDisplayed);
this.nextPage.disableProperty().bind(isLastPageDisplayed);
}
}