package org.jabref.gui;
import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Alert;
import javafx.scene.control.Dialog;
import javafx.scene.control.DialogPane;
import javafx.scene.image.Image;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.jabref.Globals;
import org.jabref.JabRefGUI;
import org.jabref.gui.keyboard.KeyBinding;
import org.jabref.gui.keyboard.KeyBindingRepository;
/**
* This class provides a super class for all dialogs implemented in JavaFX.
* It mimics the behavior of a Swing JDialog which means once a object of this class
* is shown all Swing windows will be blocked and stay in the background. Since this
* class extends from a JavaFX {@link Alert} it behaves as a normal dialog towards all
* windows in the JavaFX thread.
* <p>
* To create a custom JavaFX dialog one should create an instance of this class and set a dialog
* pane through the inherited {@link Dialog#setDialogPane(DialogPane)} method.
* The dialog can be shown via {@link Dialog#show()} or {@link Dialog#showAndWait()}.
*
* The layout of the pane should be defined in an external fxml file and loaded it via the
* {@link FXMLLoader}.
*/
public class FXDialog extends Alert {
/**
* The WindowAdapter will be added to all Swing windows once an instance
* of this class is shown and redirects the focus towards this instance.
* The WindowAdapter will be removed once the instance of this class gets hidden.
*
*/
private final WindowAdapter fxOverSwingHelper = new WindowAdapter() {
@Override
public void windowActivated(WindowEvent e) {
Platform.runLater(() -> {
Stage fxDialogWindow = getDialogWindow();
fxDialogWindow.toFront();
fxDialogWindow.requestFocus();
});
}
@Override
public void windowGainedFocus(WindowEvent e) {
Platform.runLater(() -> {
Stage fxDialogWindow = getDialogWindow();
fxDialogWindow.toFront();
fxDialogWindow.requestFocus();
});
}
};
public FXDialog(AlertType type, String title, Image image, boolean isModal) {
this(type, title, isModal);
setDialogIcon(image);
}
public FXDialog(AlertType type, String title, Image image) {
this(type, title, true);
setDialogIcon(image);
}
public FXDialog(AlertType type, String title, boolean isModal) {
this(type, isModal);
setTitle(title);
}
public FXDialog(AlertType type, String title) {
this(type);
setTitle(title);
}
public FXDialog(AlertType type, boolean isModal) {
super(type);
setDialogIcon(IconTheme.getJabRefImageFX());
Stage dialogWindow = getDialogWindow();
dialogWindow.setOnCloseRequest(evt -> this.close());
if (isModal) {
initModality(Modality.APPLICATION_MODAL);
} else {
initModality(Modality.NONE);
}
dialogWindow.setOnShown(evt -> {
setSwingWindowsEnabledAndFocusable(!isModal);
setLocationRelativeToMainWindow();
});
dialogWindow.setOnHiding(evt -> setSwingWindowsEnabledAndFocusable(true));
dialogWindow.setOnCloseRequest(evt -> this.close());
dialogWindow.getScene().setOnKeyPressed(event -> {
KeyBindingRepository keyBindingRepository = Globals.getKeyPrefs();
if (keyBindingRepository.checkKeyCombinationEquality(KeyBinding.CLOSE_DIALOG, event)) {
dialogWindow.close();
}
});
}
public FXDialog(AlertType type) {
this(type, true);
}
public void setDialogIcon(Image image) {
Stage fxDialogWindow = getDialogWindow();
fxDialogWindow.getIcons().add(image);
}
private Stage getDialogWindow() {
return (Stage) getDialogPane().getScene().getWindow();
}
private void setSwingWindowsEnabledAndFocusable(boolean enabled) {
for (Window swingWindow : Window.getWindows()) {
swingWindow.setEnabled(enabled);
if (!enabled) {
swingWindow.addWindowListener(fxOverSwingHelper);
} else {
swingWindow.removeWindowListener(fxOverSwingHelper);
}
}
}
private void setLocationRelativeToMainWindow() {
double mainWindowX = JabRefGUI.getMainFrame().getLocationOnScreen().getX();
double mainWindowY = JabRefGUI.getMainFrame().getLocationOnScreen().getY();
double mainWindowWidth = JabRefGUI.getMainFrame().getSize().getWidth();
double mainWindowHeight = JabRefGUI.getMainFrame().getSize().getHeight();
setX((mainWindowX + (mainWindowWidth / 2)) - (getWidth() / 2));
setY((mainWindowY + (mainWindowHeight / 2)) - (getHeight() / 2));
}
}