org.sellcom.javafx.stage.FxmlDialog Maven / Gradle / Ivy
/*
* Copyright (c) 2015-2017 Petr Zelenka .
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sellcom.javafx.stage;
import java.io.IOException;
import org.sellcom.core.Contract;
import org.sellcom.core.Strings;
import org.sellcom.core.i18n.Resources;
import javafx.beans.InvalidationListener;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.DialogPane;
import javafx.scene.control.Hyperlink;
/**
* Base class for {@link Dialog}s loaded from FXML resource.
*
* @since 1.0
*
* @see Dialog
*/
public abstract class FxmlDialog extends Dialog {
private final DialogPane dialogPane;
private final Object controller;
/**
* Creates a new dialog and loads its dialog pane contents from the given resource.
*
* @since 1.0
*
* @see Class#getResource(String)
*/
protected FxmlDialog(String resourceName) {
Contract.checkArgument(!Strings.isNullOrEmpty(resourceName), "Resource name must not be null or empty");
// Use custom dialog pane to enable localization
dialogPane = new LocalizedDialogPane();
setDialogPane(dialogPane);
try {
// Load FXML
FXMLLoader loader = new FXMLLoader(getClass().getResource(resourceName));
dialogPane.setContent(loader.load());
dialogPane.getStylesheets().add(getClass().getResource("/resources/styles/validation.css").toExternalForm());
controller = loader.getController();
} catch (IOException e) {
throw new FxmlLoaderException(String.format("Error loading FXML resource: %s", resourceName), e);
}
}
/**
* Returns the controller associated with this dialog.
*
* @throws IllegalArgumentException if {@code controllerClass} is {@code null}
* @throws ClassCastException if the type of the associated controller is not {@code controllerClass}
*
* @since 1.0
*/
@SuppressWarnings("unchecked")
public T getController(Class controllerClass) {
Contract.checkArgument(controllerClass != null, "Controller class must not be null");
return (T) controller;
}
/**
* Sets the types of the buttons shown in this dialog.
*
* @throws IllegalArgumentException if {@code firstButtonType} is {@code null}
*
* @since 1.0
*/
public void setButtonTypes(ButtonType firstButtonType, ButtonType... nextButtonTypes) {
Contract.checkArgument(firstButtonType != null, "First button type must not be null");
dialogPane.getButtonTypes().setAll(firstButtonType);
dialogPane.getButtonTypes().addAll(nextButtonTypes);
}
// ------------------------------------------------------------
// ------------------------------------------------------------
// ------------------------------------------------------------
static class LocalizedDialogPane extends DialogPane {
@Override
protected Node createDetailsButton() {
Hyperlink detailsButton = new Hyperlink();
InvalidationListener expandedAndCollapsedListener = (observable) -> {
if (isExpanded()) {
detailsButton.getStyleClass().setAll("details-button", "less");
detailsButton.setText(Resources.getString("dialog.detail.showLess"));
} else {
detailsButton.getStyleClass().setAll("details-button", "more");
detailsButton.setText(Resources.getString("dialog.detail.showMore"));
}
};
expandedAndCollapsedListener.invalidated(null);
expandedProperty().addListener(expandedAndCollapsedListener);
detailsButton.setOnAction(event -> setExpanded(!isExpanded()));
return detailsButton;
}
}
}