com.speedment.tool.core.internal.controller.NotificationController Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tool-deploy Show documentation
Show all versions of tool-deploy Show documentation
A Speedment bundle that shades all dependencies into one jar. This is
useful when deploying an application on a server.
The newest version!
/*
*
* Copyright (c) 2006-2019, Speedment, Inc. All Rights Reserved.
*
* 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 com.speedment.tool.core.internal.controller;
import com.speedment.tool.core.brand.Palette;
import com.speedment.tool.core.exception.SpeedmentToolException;
import com.speedment.tool.core.resource.Icon;
import javafx.animation.*;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.util.Duration;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import static java.util.Objects.requireNonNull;
import static javafx.application.Platform.runLater;
import static javafx.util.Duration.millis;
/**
* FXML Controller class
*
* @author Emil Forslund
* @since 2.3
*/
public final class NotificationController implements Initializable {
private static final int
ENTER_SPEED = 350,
EXIT_SPEED = 350,
ENTER_Y = 100;
private static final String NOTIFICATION_FXML = "/fxml/Notification.fxml";
private static final Duration TIMER = Duration.seconds(10);
private final String message;
private final Icon icon;
private final Palette palette;
private final Runnable onClose;
private final AtomicBoolean destroyed;
@FXML private Label notification;
private NotificationController(
final String message,
final Icon icon,
final Palette palette,
final Runnable onClose
) {
this.message = requireNonNull(message);
this.icon = requireNonNull(icon);
this.palette = requireNonNull(palette);
this.onClose = requireNonNull(onClose);
this.destroyed = new AtomicBoolean(false);
}
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
notification.setText(message);
notification.setGraphic(icon.view());
notification.getStyleClass().add(palette.name().toLowerCase());
}
@FXML public void close() {
if (destroyed.compareAndSet(false, true)) {
onClose.run();
remove(notification);
}
}
private void fadeAway() {
final FadeTransition fade = new FadeTransition(millis(EXIT_SPEED), notification);
fade.setFromValue(1);
fade.setToValue(0);
final TranslateTransition trans = new TranslateTransition(millis(EXIT_SPEED), notification);
trans.setFromY(0);
trans.setToY(ENTER_Y);
final SequentialTransition seq = new SequentialTransition(fade, trans);
seq.setOnFinished(ev -> {
if (destroyed.compareAndSet(false, true)) {
remove(notification);
}
});
seq.play();
}
static void showNotification(FlowPane area, String message, Icon icon, Palette palette, Runnable onClose) {
final FXMLLoader loader = new FXMLLoader(NotificationController.class.getResource(NOTIFICATION_FXML));
final AtomicReference ref = new AtomicReference<>();
loader.setControllerFactory(clazz -> {
ref.set(new NotificationController(message, icon, palette, onClose));
return ref.get();
});
final Node notification;
try {
notification = loader.load();
} catch (final IOException ex) {
throw new SpeedmentToolException(
"Failed to load FXML-file: '" + NOTIFICATION_FXML + "'.", ex
);
}
notification.setOpacity(0);
notification.setLayoutX(area.getWidth());
notification.setLayoutY(area.getHeight());
final FadeTransition fade = new FadeTransition(millis(ENTER_SPEED), notification);
fade.setFromValue(0);
fade.setToValue(1);
runLater(() -> {
childrenOf(area).add(notification);
fade.play();
final Timeline timeline = new Timeline(new KeyFrame(
TIMER, ev -> ref.get().fadeAway()
));
timeline.play();
});
}
private static void remove(Node node) {
siblingsOf(node).remove(node);
}
private static ObservableList siblingsOf(Node node) {
final Parent parent = node.getParent();
if (parent == null) {
throw new NullPointerException(
"Can't delete node from 'null' parent."
);
}
return childrenOf(parent);
}
private static ObservableList childrenOf(Node parent) {
final Method getChildren;
try {
getChildren = parent.getClass().getMethod("getChildren");
} catch (final NoSuchMethodException | SecurityException ex) {
throw new SpeedmentToolException(
"Could not find public method 'getChildren()' in class '" +
parent.getClass() + "'.", ex
);
}
try {
@SuppressWarnings("unchecked")
final ObservableList siblings = (ObservableList) getChildren.invoke(parent);
return siblings;
} catch (final IllegalAccessException
| IllegalArgumentException
| InvocationTargetException
| ClassCastException ex) {
throw new SpeedmentToolException(
"Error executing 'getChildren()' in class '" +
parent.getClass() + "'.", ex
);
}
}
}