All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.speedment.tool.core.internal.controller.NotificationController Maven / Gradle / Ivy

Go to download

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
            );
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy