From cbdd60631c12ce25488034be441457fe2c4b1823 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Thu, 30 Oct 2014 13:21:07 +0100 Subject: [PATCH 1/4] Introduce dependency on eu.hansolo.enzo:Enzo:0.1.5 Remove manually-copied classes and resources in favor of depending on the latest released Enzo distribution. --- build.gradle | 1 + .../eu/hansolo/enzo/notification/Demo.java | 88 --- .../enzo/notification/Notification.java | 566 ------------------ .../notification/NotificationBuilder.java | 84 --- .../enzo/notification/NotificationEvent.java | 43 -- .../enzo/notification/NotifierBuilder.java | 112 ---- .../eu/hansolo/enzo/notification/error.png | Bin 704 -> 0 bytes .../eu/hansolo/enzo/notification/info.png | Bin 810 -> 0 bytes .../eu/hansolo/enzo/notification/notifier.css | 40 -- .../eu/hansolo/enzo/notification/success.png | Bin 839 -> 0 bytes .../eu/hansolo/enzo/notification/warning.png | Bin 623 -> 0 bytes 11 files changed, 1 insertion(+), 933 deletions(-) delete mode 100644 src/main/java/eu/hansolo/enzo/notification/Demo.java delete mode 100644 src/main/java/eu/hansolo/enzo/notification/Notification.java delete mode 100644 src/main/java/eu/hansolo/enzo/notification/NotificationBuilder.java delete mode 100644 src/main/java/eu/hansolo/enzo/notification/NotificationEvent.java delete mode 100644 src/main/java/eu/hansolo/enzo/notification/NotifierBuilder.java delete mode 100644 src/main/resources/eu/hansolo/enzo/notification/error.png delete mode 100644 src/main/resources/eu/hansolo/enzo/notification/info.png delete mode 100644 src/main/resources/eu/hansolo/enzo/notification/notifier.css delete mode 100644 src/main/resources/eu/hansolo/enzo/notification/success.png delete mode 100644 src/main/resources/eu/hansolo/enzo/notification/warning.png diff --git a/build.gradle b/build.gradle index c23c113067..af9cb0f601 100644 --- a/build.gradle +++ b/build.gradle @@ -43,6 +43,7 @@ dependencies { compile 'net.jcip:jcip-annotations:1.0' compile 'org.jetbrains:annotations:13.0' compile 'net.sourceforge.argparse4j:argparse4j:0.4.4' + compile 'eu.hansolo.enzo:Enzo:0.1.5' testCompile 'junit:junit:4.11' testCompile 'org.mockito:mockito-all:1.9.5' } diff --git a/src/main/java/eu/hansolo/enzo/notification/Demo.java b/src/main/java/eu/hansolo/enzo/notification/Demo.java deleted file mode 100644 index 5de95ace61..0000000000 --- a/src/main/java/eu/hansolo/enzo/notification/Demo.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2013 by Gerrit Grunwald - * - * 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 eu.hansolo.enzo.notification; - -/** - * Created by - * User: hansolo - * Date: 01.07.13 - * Time: 07:10 - */ - -import java.util.Random; - -import javafx.application.Application; -import javafx.geometry.Insets; -import javafx.scene.*; -import javafx.scene.control.*; -import javafx.scene.layout.*; -import javafx.stage.Stage; - - -public class Demo extends Application { - private static final Random RND = new Random(); - private static final Notification[] NOTIFICATIONS = { - NotificationBuilder.create().title("Info").message("New Information").image(Notification.INFO_ICON).build(), - NotificationBuilder.create().title("Warning").message("Attention, somethings wrong").image(Notification - .WARNING_ICON).build(), - NotificationBuilder.create().title("Success").message("Great it works").image(Notification.SUCCESS_ICON) - .build(), - NotificationBuilder.create().title("Error").message("ZOMG").image(Notification.ERROR_ICON).build() - }; - private Notification.Notifier notifier; - private Button button; - - - // ******************** Initialization ************************************ - @Override - public void init() { - button = new Button("Notify"); - button.setOnAction(event -> { - notifier.notify(NOTIFICATIONS[RND.nextInt(4)]); - }); - } - - - // ******************** Application start ********************************* - @Override - public void start(Stage stage) { - notifier = NotifierBuilder.create() - //.popupLocation(Pos.BOTTOM_RIGHT) - .build(); - notifier.setOnNotificationPressed(event -> System.out.println("Notification pressed: " + event.NOTIFICATION - .TITLE)); - notifier.setOnShowNotification(event -> System.out.println("Notification shown: " + event.NOTIFICATION.TITLE)); - notifier.setOnHideNotification(event -> System.out.println("Notification hidden: " + event.NOTIFICATION.TITLE)); - - StackPane pane = new StackPane(); - pane.setPadding(new Insets(10, 10, 10, 10)); - pane.getChildren().addAll(button); - - Scene scene = new Scene(pane); - stage.setOnCloseRequest(observable -> notifier.stop()); - stage.setScene(scene); - stage.show(); - } - - @Override - public void stop() { - } - - public static void main(String[] args) { - launch(args); - } -} diff --git a/src/main/java/eu/hansolo/enzo/notification/Notification.java b/src/main/java/eu/hansolo/enzo/notification/Notification.java deleted file mode 100644 index 4f00edf772..0000000000 --- a/src/main/java/eu/hansolo/enzo/notification/Notification.java +++ /dev/null @@ -1,566 +0,0 @@ -/* - * Copyright (c) 2013 by Gerrit Grunwald - * - * 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 eu.hansolo.enzo.notification; - -import java.util.stream.IntStream; - -import javafx.animation.KeyFrame; -import javafx.animation.KeyValue; -import javafx.animation.Timeline; -import javafx.application.Platform; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ObjectPropertyBase; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.event.EventHandler; -import javafx.event.EventType; -import javafx.event.WeakEventHandler; -import javafx.geometry.Pos; -import javafx.scene.*; -import javafx.scene.control.*; -import javafx.scene.image.*; -import javafx.scene.input.*; -import javafx.scene.layout.*; -import javafx.stage.Screen; -import javafx.stage.Stage; -import javafx.stage.StageStyle; -import javafx.util.Duration; - -import org.controlsfx.control.PopOver; - - -/** - * Created by - * User: hansolo - * Date: 01.07.13 - * Time: 07:10 - */ -public class Notification { - public static final Image INFO_ICON = new Image(Notifier.class.getResourceAsStream("info.png")); - public static final Image WARNING_ICON = new Image(Notifier.class.getResourceAsStream("warning.png")); - public static final Image SUCCESS_ICON = new Image(Notifier.class.getResourceAsStream("success.png")); - public static final Image ERROR_ICON = new Image(Notifier.class.getResourceAsStream("error.png")); - public final String TITLE; - public final String MESSAGE; - public final Image IMAGE; - - - // ******************** Constructors ************************************** - public Notification(final String TITLE, final String MESSAGE) { - this(TITLE, MESSAGE, null); - } - - public Notification(final String MESSAGE, final Image IMAGE) { - this("", MESSAGE, IMAGE); - } - - public Notification(final String TITLE, final String MESSAGE, final Image IMAGE) { - this.TITLE = TITLE; - this.MESSAGE = MESSAGE; - this.IMAGE = IMAGE; - } - - - // ******************** Inner Classes ************************************* - public enum Notifier { - INSTANCE; - - private static final double ICON_WIDTH = 24; - private static final double ICON_HEIGHT = 24; - private static double width = 321; - private static double height = 49; - private static double offsetX = 0; - private static double offsetY = 2; - private static double spacingY = 5; - private static Pos popupLocation = Pos.TOP_RIGHT; - private static Stage stageRef = null; - private Duration popupLifetime; - private Duration popupAnimationTime; - private Stage stage; - private Scene scene; - private ObservableList popups; - - - // ******************** Constructor *************************************** - private Notifier() { - init(); - initGraphics(); - } - - - // ******************** Initialization ************************************ - private void init() { - popupLifetime = Duration.millis(5000); - popupAnimationTime = Duration.millis(500); - popups = FXCollections.observableArrayList(); - } - - private void initGraphics() { - scene = new Scene(new Region()); - scene.setFill(null); - // scene.getStylesheets().add(getClass().getResource("notifier.css").toExternalForm()); - scene.getStylesheets().setAll(getClass().getResource("/io/bitsquare/gui/bitsquare.css").toExternalForm(), - getClass().getResource("/io/bitsquare/gui/images.css").toExternalForm()); - - stage = new Stage(); - stage.initStyle(StageStyle.TRANSPARENT); - // stage.setAlwaysOnTop(true); - } - - - // ******************** Methods ******************************************* - - /** - * @param STAGE_REF The Notification will be positioned relative to the given Stage.
- * If null then the Notification will be positioned relative to the primary Screen. - * @param POPUP_LOCATION The default is TOP_RIGHT of primary Screen. - */ - public static void setPopupLocation(final Stage STAGE_REF, final Pos POPUP_LOCATION) { - if (null != STAGE_REF) { - INSTANCE.stage.initOwner(STAGE_REF); - Notifier.stageRef = STAGE_REF; - } - Notifier.popupLocation = POPUP_LOCATION; - } - - /** - * Sets the Notification's owner stage so that when the owner - * stage is closed Notifications will be shut down as well.
- * This is only needed if setPopupLocation is called - * without a stage reference. - * - * @param OWNER - */ - public static void setNotificationOwner(final Stage OWNER) { - INSTANCE.stage.initOwner(OWNER); - } - - /** - * @param OFFSET_X The horizontal shift required. - *
The default is 0 px. - */ - public static void setOffsetX(final double OFFSET_X) { - Notifier.offsetX = OFFSET_X; - } - - /** - * @param OFFSET_Y The vertical shift required. - *
The default is 25 px. - */ - public static void setOffsetY(final double OFFSET_Y) { - Notifier.offsetY = OFFSET_Y; - } - - /** - * @param WIDTH The default is 300 px. - */ - public static void setWidth(final double WIDTH) { - Notifier.width = WIDTH; - } - - /** - * @param HEIGHT The default is 80 px. - */ - public static void setHeight(final double HEIGHT) { - Notifier.height = HEIGHT; - } - - /** - * @param SPACING_Y The spacing between multiple Notifications. - *
The default is 5 px. - */ - public static void setSpacingY(final double SPACING_Y) { - Notifier.spacingY = SPACING_Y; - } - - public void stop() { - popups.clear(); - stage.close(); - } - - /** - * Returns the Duration that the notification will stay on screen before it - * will fade out. The default is 5000 ms - * - * @return the Duration the popup notification will stay on screen - */ - public Duration getPopupLifetime() { - return popupLifetime; - } - - /** - * Defines the Duration that the popup notification will stay on screen before it - * will fade out. The parameter is limited to values between 2 and 20 seconds. - * - * @param POPUP_LIFETIME - */ - public void setPopupLifetime(final Duration POPUP_LIFETIME) { - popupLifetime = Duration.millis(clamp(2000, 20000, POPUP_LIFETIME.toMillis())); - } - - /** - * Returns the Duration that it takes to fade out the notification - * The parameter is limited to values between 0 and 1000 ms - * - * @return the Duration that it takes to fade out the notification - */ - public Duration getPopupAnimationTime() { - return popupAnimationTime; - } - - /** - * Defines the Duration that it takes to fade out the notification - * The parameter is limited to values between 0 and 1000 ms - * Default value is 500 ms - * - * @param POPUP_ANIMATION_TIME - */ - public void setPopupAnimationTime(final Duration POPUP_ANIMATION_TIME) { - popupAnimationTime = Duration.millis(clamp(0, 1000, POPUP_ANIMATION_TIME.toMillis())); - } - - /** - * Show the given Notification on the screen - * - * @param NOTIFICATION - */ - public void notify(final Notification NOTIFICATION) { - preOrder(); - showPopup(NOTIFICATION); - } - - /** - * Show a Notification with the given parameters on the screen - * - * @param TITLE - * @param MESSAGE - * @param IMAGE - */ - public void notify(final String TITLE, final String MESSAGE, final Image IMAGE) { - notify(new Notification(TITLE, MESSAGE, IMAGE)); - } - - /** - * Show a Notification with the given title and message and an Info icon - * - * @param TITLE - * @param MESSAGE - */ - public void notifyInfo(final String TITLE, final String MESSAGE) { - notify(new Notification(TITLE, MESSAGE, Notification.INFO_ICON)); - } - - /** - * Show a Notification with the given title and message and a Warning icon - * - * @param TITLE - * @param MESSAGE - */ - public void notifyWarning(final String TITLE, final String MESSAGE) { - notify(new Notification(TITLE, MESSAGE, Notification.WARNING_ICON)); - } - - /** - * Show a Notification with the given title and message and a Checkmark icon - * - * @param TITLE - * @param MESSAGE - */ - public void notifySuccess(final String TITLE, final String MESSAGE) { - notify(new Notification(TITLE, MESSAGE, Notification.SUCCESS_ICON)); - } - - /** - * Show a Notification with the given title and message and an Error icon - * - * @param TITLE - * @param MESSAGE - */ - public void notifyError(final String TITLE, final String MESSAGE) { - notify(new Notification(TITLE, MESSAGE, Notification.ERROR_ICON)); - } - - /** - * Makes sure that the given VALUE is within the range of MIN to MAX - * - * @param MIN - * @param MAX - * @param VALUE - * @return - */ - private double clamp(final double MIN, final double MAX, final double VALUE) { - if (VALUE < MIN) return MIN; - if (VALUE > MAX) return MAX; - return VALUE; - } - - /** - * Reorder the popup Notifications on screen so that the latest Notification will stay on top - */ - private void preOrder() { - if (popups.isEmpty()) return; - IntStream.range(0, popups.size()).parallel().forEachOrdered( - i -> { - Platform.runLater(() -> preOrderTask(i)); - /* switch (popupLocation) { - case TOP_LEFT: case TOP_CENTER: case TOP_RIGHT: - popups.get(i).setY(popups.get(i).getY() + height + spacingY); - break; - - case BOTTOM_LEFT: case BOTTOM_CENTER: case BOTTOM_RIGHT: - popups.get(i).setY(popups.get(i).getY() - height - spacingY); - break; - - default: - popups.get(i).setY(popups.get(i).getY() - height - spacingY); - break; - } */ - } - ); - } - - private void preOrderTask(int i) { - switch (popupLocation) { - case TOP_LEFT: - case TOP_CENTER: - case TOP_RIGHT: - popups.get(i).setY(popups.get(i).getY() + height + spacingY); - break; - - case BOTTOM_LEFT: - case BOTTOM_CENTER: - case BOTTOM_RIGHT: - popups.get(i).setY(popups.get(i).getY() - height - spacingY); - break; - - default: - popups.get(i).setY(popups.get(i).getY() - height - spacingY); - break; - } - } - - /** - * Creates and shows a popup with the data from the given Notification object - * - * @param NOTIFICATION - */ - private void showPopup(final Notification NOTIFICATION) { - ImageView icon = new ImageView(new Image(Notifier.class.getResourceAsStream("/images/notification_logo" + - ".png"))); - //icon.setId("notification-logo"); - icon.relocate(10, 7); - - Label title = new Label(NOTIFICATION.TITLE); - title.setStyle(" -fx-text-fill:#333333; -fx-font-size:12; -fx-font-weight:bold;"); - title.relocate(60, 6); - - Label message = new Label(NOTIFICATION.MESSAGE); - message.relocate(60, 25); - message.setStyle(" -fx-text-fill:#333333; -fx-font-size:11; "); - - Pane popupLayout = new Pane(); - popupLayout.setPrefSize(width, height); - popupLayout.getChildren().addAll(icon, title, message); - - PopOver popOver = new PopOver(popupLayout); - popOver.setDetachable(false); - popOver.setArrowSize(0); - popOver.setX(getX()); - popOver.setY(getY()); - popOver.addEventHandler(MouseEvent.MOUSE_PRESSED, new WeakEventHandler<>(event -> - fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, popOver, - NotificationEvent.NOTIFICATION_PRESSED)) - )); - popups.add(popOver); - - // Add a timeline for popup fade out - KeyValue fadeOutBegin = new KeyValue(popOver.opacityProperty(), 1.0); - KeyValue fadeOutEnd = new KeyValue(popOver.opacityProperty(), 0.0); - - KeyFrame kfBegin = new KeyFrame(Duration.ZERO, fadeOutBegin); - KeyFrame kfEnd = new KeyFrame(popupAnimationTime, fadeOutEnd); - - Timeline timeline = new Timeline(kfBegin, kfEnd); - timeline.setDelay(popupLifetime); - timeline.setOnFinished(actionEvent -> Platform.runLater(() -> { - popOver.hide(); - popups.remove(popOver); - fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, popOver, - NotificationEvent.HIDE_NOTIFICATION)); - })); - - if (stage.isShowing()) { - stage.toFront(); - } - else { - stage.show(); - } - - popOver.show(stage); - fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, popOver, - NotificationEvent.SHOW_NOTIFICATION)); - timeline.play(); - } - - private double getX() { - if (null == stageRef) return calcX(0.0, Screen.getPrimary().getBounds().getWidth()); - - return calcX(stageRef.getX(), stageRef.getWidth()); - } - - private double getY() { - if (null == stageRef) return calcY(0.0, Screen.getPrimary().getBounds().getHeight()); - return calcY(stageRef.getY(), stageRef.getHeight()); - } - - private double calcX(final double LEFT, final double TOTAL_WIDTH) { - switch (popupLocation) { - case TOP_LEFT: - case CENTER_LEFT: - case BOTTOM_LEFT: - return LEFT + offsetX; - case TOP_CENTER: - case CENTER: - case BOTTOM_CENTER: - return LEFT + (TOTAL_WIDTH - width) * 0.5 - offsetX; - case TOP_RIGHT: - case CENTER_RIGHT: - case BOTTOM_RIGHT: - return LEFT + TOTAL_WIDTH - width - offsetX; - default: - return 0.0; - } - } - - private double calcY(final double TOP, final double TOTAL_HEIGHT) { - switch (popupLocation) { - case TOP_LEFT: - case TOP_CENTER: - case TOP_RIGHT: - return TOP + offsetY; - case CENTER_LEFT: - case CENTER: - case CENTER_RIGHT: - return TOP + (TOTAL_HEIGHT - height) / 2 - offsetY; - case BOTTOM_LEFT: - case BOTTOM_CENTER: - case BOTTOM_RIGHT: - return TOP + TOTAL_HEIGHT - height - offsetY; - default: - return 0.0; - } - } - - - // ******************** Event handling ******************************** - public final ObjectProperty> onNotificationPressedProperty() { - return onNotificationPressed; - } - - public final void setOnNotificationPressed(EventHandler value) { - onNotificationPressedProperty().set(value); - } - - public final EventHandler getOnNotificationPressed() { - return onNotificationPressedProperty().get(); - } - - private ObjectProperty> onNotificationPressed = new - ObjectPropertyBase>() { - @Override - public Object getBean() { - return this; - } - - @Override - public String getName() { - return "onNotificationPressed"; - } - }; - - public final ObjectProperty> onShowNotificationProperty() { - return onShowNotification; - } - - public final void setOnShowNotification(EventHandler value) { - onShowNotificationProperty().set(value); - } - - public final EventHandler getOnShowNotification() { - return onShowNotificationProperty().get(); - } - - private ObjectProperty> onShowNotification = new - ObjectPropertyBase>() { - @Override - public Object getBean() { - return this; - } - - @Override - public String getName() { - return "onShowNotification"; - } - }; - - public final ObjectProperty> onHideNotificationProperty() { - return onHideNotification; - } - - public final void setOnHideNotification(EventHandler value) { - onHideNotificationProperty().set(value); - } - - public final EventHandler getOnHideNotification() { - return onHideNotificationProperty().get(); - } - - private ObjectProperty> onHideNotification = new - ObjectPropertyBase>() { - @Override - public Object getBean() { - return this; - } - - @Override - public String getName() { - return "onHideNotification"; - } - }; - - - public void fireNotificationEvent(final NotificationEvent EVENT) { - final EventType TYPE = EVENT.getEventType(); - final EventHandler HANDLER; - if (NotificationEvent.NOTIFICATION_PRESSED == TYPE) { - HANDLER = getOnNotificationPressed(); - } - else if (NotificationEvent.SHOW_NOTIFICATION == TYPE) { - HANDLER = getOnShowNotification(); - } - else if (NotificationEvent.HIDE_NOTIFICATION == TYPE) { - HANDLER = getOnHideNotification(); - } - else { - HANDLER = null; - } - if (null == HANDLER) return; - HANDLER.handle(EVENT); - } - - } -} diff --git a/src/main/java/eu/hansolo/enzo/notification/NotificationBuilder.java b/src/main/java/eu/hansolo/enzo/notification/NotificationBuilder.java deleted file mode 100644 index 2fb81c52a1..0000000000 --- a/src/main/java/eu/hansolo/enzo/notification/NotificationBuilder.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2014 by Gerrit Grunwald - * - * 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 eu.hansolo.enzo.notification; - -import java.util.HashMap; - -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.Property; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; -import javafx.scene.image.*; - - -/** - * User: hansolo - * Date: 29.04.14 - * Time: 08:53 - */ -public class NotificationBuilder> { - private HashMap properties = new HashMap<>(); - - - // ******************** Constructors ************************************** - protected NotificationBuilder() { - } - - - // ******************** Methods ******************************************* - public final static NotificationBuilder create() { - return new NotificationBuilder(); - } - - public final B title(final String TITLE) { - properties.put("title", new SimpleStringProperty(TITLE)); - return (B) this; - } - - public final B message(final String MESSAGE) { - properties.put("message", new SimpleStringProperty(MESSAGE)); - return (B) this; - } - - public final B image(final Image IMAGE) { - properties.put("image", new SimpleObjectProperty<>(IMAGE)); - return (B) this; - } - - public final Notification build() { - final Notification NOTIFICATION; - if (properties.keySet().contains("title") && properties.keySet().contains("message") && properties.keySet() - .contains("image")) { - NOTIFICATION = new Notification(((StringProperty) properties.get("title")).get(), - ((StringProperty) properties.get("message")).get(), - ((ObjectProperty) properties.get("image")).get()); - } - else if (properties.keySet().contains("title") && properties.keySet().contains("message")) { - NOTIFICATION = new Notification(((StringProperty) properties.get("title")).get(), - ((StringProperty) properties.get("message")).get()); - } - else if (properties.keySet().contains("message") && properties.keySet().contains("image")) { - NOTIFICATION = new Notification(((StringProperty) properties.get("message")).get(), - ((ObjectProperty) properties.get("image")).get()); - } - else { - throw new IllegalArgumentException("Wrong or missing parameters."); - } - return NOTIFICATION; - } -} diff --git a/src/main/java/eu/hansolo/enzo/notification/NotificationEvent.java b/src/main/java/eu/hansolo/enzo/notification/NotificationEvent.java deleted file mode 100644 index 5eb9657293..0000000000 --- a/src/main/java/eu/hansolo/enzo/notification/NotificationEvent.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2014 by Gerrit Grunwald - * - * 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 eu.hansolo.enzo.notification; - -import javafx.event.Event; -import javafx.event.EventTarget; -import javafx.event.EventType; - - -/** - * User: hansolo - * Date: 29.04.14 - * Time: 10:03 - */ -public class NotificationEvent extends Event { - public static final EventType NOTIFICATION_PRESSED = new EventType(ANY, "NOTIFICATION_PRESSED"); - public static final EventType SHOW_NOTIFICATION = new EventType(ANY, "SHOW_NOTIFICATION"); - public static final EventType HIDE_NOTIFICATION = new EventType(ANY, "HIDE_NOTIFICATION"); - - public final Notification NOTIFICATION; - - - // ******************** Constructors ************************************** - public NotificationEvent(final Notification NOTIFICATION, final Object SOURCE, final EventTarget TARGET, - EventType TYPE) { - super(SOURCE, TARGET, TYPE); - this.NOTIFICATION = NOTIFICATION; - } -} diff --git a/src/main/java/eu/hansolo/enzo/notification/NotifierBuilder.java b/src/main/java/eu/hansolo/enzo/notification/NotifierBuilder.java deleted file mode 100644 index b4fb514ee2..0000000000 --- a/src/main/java/eu/hansolo/enzo/notification/NotifierBuilder.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2014 by Gerrit Grunwald - * - * 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 eu.hansolo.enzo.notification; - -import java.util.HashMap; - -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.Property; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.geometry.Pos; -import javafx.stage.Stage; -import javafx.util.Duration; - - -/** - * User: hansolo - * Date: 29.04.14 - * Time: 08:32 - */ -public class NotifierBuilder> { - private HashMap properties = new HashMap<>(); - - - // ******************** Constructors ************************************** - protected NotifierBuilder() { - } - - - // ******************** Methods ******************************************* - public final static NotifierBuilder create() { - return new NotifierBuilder(); - } - - public final B owner(final Stage OWNER) { - properties.put("stage", new SimpleObjectProperty<>(OWNER)); - return (B) this; - } - - public final B popupLocation(Pos LOCATION) { - properties.put("popupLocation", new SimpleObjectProperty<>(LOCATION)); - return (B) this; - } - - public final B width(final double WIDTH) { - properties.put("width", new SimpleDoubleProperty(WIDTH)); - return (B) this; - } - - public final B height(final double HEIGHT) { - properties.put("height", new SimpleDoubleProperty(HEIGHT)); - return (B) this; - } - - public final B spacingY(final double SPACING_Y) { - properties.put("spacingY", new SimpleDoubleProperty(SPACING_Y)); - return (B) this; - } - - public final B popupLifeTime(final Duration POPUP_LIFETIME) { - properties.put("popupLifeTime", new SimpleObjectProperty<>(POPUP_LIFETIME)); - return (B) this; - } - - public final B popupAnimationTime(final Duration POPUP_ANIMATION_TIME) { - properties.put("popupAnimationTime", new SimpleObjectProperty<>(POPUP_ANIMATION_TIME)); - return (B) this; - } - - public final Notification.Notifier build() { - final Notification.Notifier NOTIFIER = Notification.Notifier.INSTANCE; - for (String key : properties.keySet()) { - if ("owner".equals(key)) { - NOTIFIER.setNotificationOwner(((ObjectProperty) properties.get(key)).get()); - } - else if ("popupLocation".equals(key)) { - NOTIFIER.setPopupLocation(null, ((ObjectProperty) properties.get(key)).get()); - } - else if ("width".equals(key)) { - NOTIFIER.setWidth(((DoubleProperty) properties.get(key)).get()); - } - else if ("height".equals(key)) { - NOTIFIER.setHeight(((DoubleProperty) properties.get(key)).get()); - } - else if ("spacingY".equals(key)) { - NOTIFIER.setSpacingY(((DoubleProperty) properties.get(key)).get()); - } - else if ("popupLifeTime".equals(key)) { - NOTIFIER.setPopupLifetime(((ObjectProperty) properties.get(key)).get()); - } - else if ("popupAnimationTime".equals(key)) { - NOTIFIER.setPopupAnimationTime(((ObjectProperty) properties.get(key)).get()); - } - } - return NOTIFIER; - } -} diff --git a/src/main/resources/eu/hansolo/enzo/notification/error.png b/src/main/resources/eu/hansolo/enzo/notification/error.png deleted file mode 100644 index f0651ec351db0a270c295195802c436869650cb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 704 zcmV;x0zdtUP)P000;W1^@s654Bdt00004b3#c}2nYxW zdP}K-Mc%gai#jxU)FM;%3j;$J^wJoDM9Ho%zrIKX2dc>;?`o6&k<| z;5u*#xB%3E9`G4>2fP5Dhn#MbLzPfLUIXp|_kpvA6=L=scmO;OIlUuAR5%B$16Q2; z7w`($27UskfEnN_aMIyk1B)T&n-_@%nkuwaP`h#!?x;|&*m2$Bxyxy*&`gS`FrmVZ z1Fu$*SBR~;+#MArQX#~i;n1`3cD8DEeK8EOYC=fD;Ddh zFqQ#xK*Qosq9@RGRhQjV}NzlCjCd{ ztvI8ZM9w5IZnr-&;Dd`_P6%vKK7(77&*){`-Vx8o40sEJF?~A%H()SYiZggdxf$xf zi70Q;)-FX8sIcbxdMet@&@ZF;r&Q<~-`db)rE1KiaH+B4D;Vv7G(bG+SB`zu8+ari mt$*_Q{Xahvk=U{P68!-uhjovBUk&#F0000P000;W1^@s654Bdt00004b3#c}2nYxW zd4ig;WsWT#P=-jJl|dS-K&M`Y0k`G` z%sDgDqfWBC58JT~>oI^{yucm&h9B^qkWO}kXti2;D!_Yj0AFEQZ6byIi(@z=q%Yn~ zlI8uljEyDh6a0kRc!)(J+k~C9F91run&?LIEcLw=89%B)a3momSZVCowCwwj^Ik1?TxsRghNq3$3aKd zwQ5N6s2?lJw_8%D74{N8N{^Sy)?Iyk0?YSkV{l#$1ZkxLZL|##x(`GI}PYkGc@-K)<42 z7Dwy<_`Px;1FQim)wM5yy|bUb@qzjB_i&uZmKG&nkk3OXEvOWcltIlATdc;(8*a z6BvueU9x=T6!+py*;=xU;cHBEg)icFwS8M7gA?t8KN)o&PCGhYzMVh9+|v9a#)Ncq z8bJ|v8gt6H1xZM6pb;0gN|LM;dQZ_0llUH+g|wlYB*}4|T{j|b?Nxsc2j0b1|DGSM oPT&kbza63({zyzEdnaF_mll`s5^Y~IWdHyG07*qoM6N<$f{XfRrvLx| diff --git a/src/main/resources/eu/hansolo/enzo/notification/notifier.css b/src/main/resources/eu/hansolo/enzo/notification/notifier.css deleted file mode 100644 index afebed8fa5..0000000000 --- a/src/main/resources/eu/hansolo/enzo/notification/notifier.css +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013 by Gerrit Grunwald - * - * 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. - */ -/* -.root { - -fx-background-color: transparent; - -fx-fill : transparent; -} -.notification { - -fx-background-color : rgba(15, 15, 15, 0.8); - -fx-background-radius: 5; - -fx-effect : innershadow(two-pass-box, rgba(255, 255, 255, 0.6), 5.0, 0.25, 0, 0); - -foreground-color : white; - -icon-color : white; -} - -.notification .title { - -fx-font-size : 1.083333em; - -fx-font-weight: bold; - -fx-text-fill : -foreground-color; -} -.notification .message { - -fx-font-size : 1.0em; - -fx-content-display : left; - -fx-graphic-text-gap: 10; - -fx-text-fill : -foreground-color; -} -*/ diff --git a/src/main/resources/eu/hansolo/enzo/notification/success.png b/src/main/resources/eu/hansolo/enzo/notification/success.png deleted file mode 100644 index 472804af55afc0b647b833e12992f5efd7cd3f0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 839 zcmV-N1GxN&P)P000;W1^@s654Bdt00004b3#c}2nYxW zdJNR7i=v*3YY!MHC0{&pS8rk`$Jk2%_8sl0FawDG`W~iFdMvBwRPCoAMv1u$Gz7 z&W#!bx3*?rIz|vgn=qk}CJPC}lFFdeexO_l-?zncUU|6P_q}(Kp3RwaX3qC}<~(y| zo}Mw1OEZaQ@eCfr3QXWS&fz4E;e(Rv?0gu5!9Z^W_yk_WYq)n@A|b!xbsQ|YUSE(T zm*zek!s8wHU-%f`;4<#U!*~jJb=G}`ttHoAMv~;xJcv*6K)BAuZr(4sUYjSOCD;*r+L$J5xx_cq; zp+q9vb7?N%mB87Dosc4vN3bJej`#chR~Jjrm43g!8^^=k5x6Z0UJ88;yFT1}daxMK zT$|I6Pb@^R>FBB+-p00YeTyecu78feS)H_v1y@S0f6U2v zb1u!{D2+`=SM^d#`?aNj@9}iW^|x+Z;9Lpwo@9jN(mbK9`4+sBOEZyD+N-^8;AgBa zx&AbM@9pWj9OI?AG|M`3XS7WP)A$-MhkZfY)#pbfxC~3fyp$q%C~JpP000;W1^@s654Bdt00004b3#c}2nYxW zd-V>?93NPk=`)k%dJvbS%{5D9M>W@VH302Swo&~&OGP*&tYcnZFM>wyR9~~TCFT| zis1+*@wTk$B|W%}MS%Ns8eFK4BOOc#kn$!f#Y%Re#CFbilL3!eqA=2Nihr!48au6W=6VzuM7PVTUazwbNipofM~rTh{1xwT-M^oiZY|?X zS=B$;cqWhf0AReV>M4x(@r~l)+M<9I!*M+BlQ^iRQw+z}A$WM>vZ~u_g(s|DyW!scf%OZEG?VPMvj6cr(O=Ovc^M;Tyk`Ia002ov JPDHLkV1h)#3WNXv From 47d9693a07474a0d12737d64e14f958bfd4dfbdb Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Thu, 30 Oct 2014 15:02:43 +0100 Subject: [PATCH 2/4] Re-introduce enzo Notification in original form Copied from https://hansolo@bitbucket.org/hansolo/enzo.git at commit eb1d32 --- .../enzo/notification/Notification.java | 452 ++++++++++++++++++ 1 file changed, 452 insertions(+) create mode 100644 src/main/java/eu/hansolo/enzo/notification/Notification.java diff --git a/src/main/java/eu/hansolo/enzo/notification/Notification.java b/src/main/java/eu/hansolo/enzo/notification/Notification.java new file mode 100644 index 0000000000..f493a5c306 --- /dev/null +++ b/src/main/java/eu/hansolo/enzo/notification/Notification.java @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2013 by Gerrit Grunwald + * + * 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 eu.hansolo.enzo.notification; + +import javafx.animation.KeyFrame; +import javafx.animation.KeyValue; +import javafx.animation.Timeline; +import javafx.application.Platform; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ObjectPropertyBase; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.event.EventHandler; +import javafx.event.EventType; +import javafx.event.WeakEventHandler; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.stage.Popup; +import javafx.stage.Screen; +import javafx.stage.Stage; +import javafx.stage.StageStyle; +import javafx.util.Duration; + +import java.util.stream.IntStream; + + +/** + * Created by + * User: hansolo + * Date: 01.07.13 + * Time: 07:10 + */ +public class Notification { + public static final Image INFO_ICON = new Image(Notifier.class.getResourceAsStream("info.png")); + public static final Image WARNING_ICON = new Image(Notifier.class.getResourceAsStream("warning.png")); + public static final Image SUCCESS_ICON = new Image(Notifier.class.getResourceAsStream("success.png")); + public static final Image ERROR_ICON = new Image(Notifier.class.getResourceAsStream("error.png")); + public final String TITLE; + public final String MESSAGE; + public final Image IMAGE; + + + // ******************** Constructors ************************************** + public Notification(final String TITLE, final String MESSAGE) { + this(TITLE, MESSAGE, null); + } + public Notification(final String MESSAGE, final Image IMAGE) { + this("", MESSAGE, IMAGE); + } + public Notification(final String TITLE, final String MESSAGE, final Image IMAGE) { + this.TITLE = TITLE; + this.MESSAGE = MESSAGE; + this.IMAGE = IMAGE; + } + + + // ******************** Inner Classes ************************************* + public enum Notifier { + INSTANCE; + + private static final double ICON_WIDTH = 24; + private static final double ICON_HEIGHT = 24; + private static double width = 300; + private static double height = 80; + private static double offsetX = 0; + private static double offsetY = 25; + private static double spacingY = 5; + private static Pos popupLocation = Pos.TOP_RIGHT; + private static Stage stageRef = null; + private Duration popupLifetime; + private Duration popupAnimationTime; + private Stage stage; + private Scene scene; + private ObservableList popups; + + + // ******************** Constructor *************************************** + private Notifier() { + init(); + initGraphics(); + } + + + // ******************** Initialization ************************************ + private void init() { + popupLifetime = Duration.millis(5000); + popupAnimationTime = Duration.millis(500); + popups = FXCollections.observableArrayList(); + } + + private void initGraphics() { + scene = new Scene(new Region()); + scene.setFill(null); + scene.getStylesheets().add(getClass().getResource("notifier.css").toExternalForm()); + + stage = new Stage(); + stage.initStyle(StageStyle.TRANSPARENT); + stage.setAlwaysOnTop(true); + } + + + // ******************** Methods ******************************************* + /** + * @param STAGE_REF The Notification will be positioned relative to the given Stage.
+ * If null then the Notification will be positioned relative to the primary Screen. + * @param POPUP_LOCATION The default is TOP_RIGHT of primary Screen. + */ + public static void setPopupLocation(final Stage STAGE_REF, final Pos POPUP_LOCATION) { + if (null != STAGE_REF) { + INSTANCE.stage.initOwner(STAGE_REF); + Notifier.stageRef = STAGE_REF; + } + Notifier.popupLocation = POPUP_LOCATION; + } + + /** + * Sets the Notification's owner stage so that when the owner + * stage is closed Notifications will be shut down as well.
+ * This is only needed if setPopupLocation is called + * without a stage reference. + * @param OWNER + */ + public static void setNotificationOwner(final Stage OWNER) { + INSTANCE.stage.initOwner(OWNER); + } + + /** + * @param OFFSET_X The horizontal shift required. + *
The default is 0 px. + */ + public static void setOffsetX(final double OFFSET_X) { + Notifier.offsetX = OFFSET_X; + } + + /** + * @param OFFSET_Y The vertical shift required. + *
The default is 25 px. + */ + public static void setOffsetY(final double OFFSET_Y) { + Notifier.offsetY = OFFSET_Y; + } + + /** + * @param WIDTH The default is 300 px. + */ + public static void setWidth(final double WIDTH) { + Notifier.width = WIDTH; + } + + /** + * @param HEIGHT The default is 80 px. + */ + public static void setHeight(final double HEIGHT) { + Notifier.height = HEIGHT; + } + + /** + * @param SPACING_Y The spacing between multiple Notifications. + *
The default is 5 px. + */ + public static void setSpacingY(final double SPACING_Y) { + Notifier.spacingY = SPACING_Y; + } + + public void stop() { + popups.clear(); + stage.close(); + } + + /** + * Returns the Duration that the notification will stay on screen before it + * will fade out. The default is 5000 ms + * @return the Duration the popup notification will stay on screen + */ + public Duration getPopupLifetime() { + return popupLifetime; + } + + /** + * Defines the Duration that the popup notification will stay on screen before it + * will fade out. The parameter is limited to values between 2 and 20 seconds. + * @param POPUP_LIFETIME + */ + public void setPopupLifetime(final Duration POPUP_LIFETIME) { + popupLifetime = Duration.millis(clamp(2000, 20000, POPUP_LIFETIME.toMillis())); + } + + /** + * Returns the Duration that it takes to fade out the notification + * The parameter is limited to values between 0 and 1000 ms + * @return the Duration that it takes to fade out the notification + */ + public Duration getPopupAnimationTime() { + return popupAnimationTime; + } + + /** + * Defines the Duration that it takes to fade out the notification + * The parameter is limited to values between 0 and 1000 ms + * Default value is 500 ms + * @param POPUP_ANIMATION_TIME + */ + public void setPopupAnimationTime(final Duration POPUP_ANIMATION_TIME) { + popupAnimationTime = Duration.millis(clamp(0, 1000, POPUP_ANIMATION_TIME.toMillis())); + } + + /** + * Show the given Notification on the screen + * @param NOTIFICATION + */ + public void notify(final Notification NOTIFICATION) { + preOrder(); + showPopup(NOTIFICATION); + } + + /** + * Show a Notification with the given parameters on the screen + * @param TITLE + * @param MESSAGE + * @param IMAGE + */ + public void notify(final String TITLE, final String MESSAGE, final Image IMAGE) { + notify(new Notification(TITLE, MESSAGE, IMAGE)); + } + + /** + * Show a Notification with the given title and message and an Info icon + * @param TITLE + * @param MESSAGE + */ + public void notifyInfo(final String TITLE, final String MESSAGE) { + notify(new Notification(TITLE, MESSAGE, Notification.INFO_ICON)); + } + + /** + * Show a Notification with the given title and message and a Warning icon + * @param TITLE + * @param MESSAGE + */ + public void notifyWarning(final String TITLE, final String MESSAGE) { + notify(new Notification(TITLE, MESSAGE, Notification.WARNING_ICON)); + } + + /** + * Show a Notification with the given title and message and a Checkmark icon + * @param TITLE + * @param MESSAGE + */ + public void notifySuccess(final String TITLE, final String MESSAGE) { + notify(new Notification(TITLE, MESSAGE, Notification.SUCCESS_ICON)); + } + + /** + * Show a Notification with the given title and message and an Error icon + * @param TITLE + * @param MESSAGE + */ + public void notifyError(final String TITLE, final String MESSAGE) { + notify(new Notification(TITLE, MESSAGE, Notification.ERROR_ICON)); + } + + /** + * Makes sure that the given VALUE is within the range of MIN to MAX + * @param MIN + * @param MAX + * @param VALUE + * @return + */ + private double clamp(final double MIN, final double MAX, final double VALUE) { + if (VALUE < MIN) return MIN; + if (VALUE > MAX) return MAX; + return VALUE; + } + + /** + * Reorder the popup Notifications on screen so that the latest Notification will stay on top + */ + private void preOrder() { + if (popups.isEmpty()) return; + IntStream.range(0, popups.size()).parallel().forEachOrdered( + i -> { + switch (popupLocation) { + case TOP_LEFT: case TOP_CENTER: case TOP_RIGHT: + popups.get(i).setY(popups.get(i).getY() + height + spacingY); + break; + + case BOTTOM_LEFT: case BOTTOM_CENTER: case BOTTOM_RIGHT: + popups.get(i).setY(popups.get(i).getY() - height - spacingY); + break; + + default: + popups.get(i).setY(popups.get(i).getY() - height - spacingY); + break; + } + } + ); + } + + /** + * Creates and shows a popup with the data from the given Notification object + * @param NOTIFICATION + */ + private void showPopup(final Notification NOTIFICATION) { + Label title = new Label(NOTIFICATION.TITLE); + title.getStyleClass().add("title"); + + ImageView icon = new ImageView(NOTIFICATION.IMAGE); + icon.setFitWidth(ICON_WIDTH); + icon.setFitHeight(ICON_HEIGHT); + + Label message = new Label(NOTIFICATION.MESSAGE, icon); + message.getStyleClass().add("message"); + + VBox popupLayout = new VBox(); + popupLayout.setSpacing(10); + popupLayout.setPadding(new Insets(10, 10, 10, 10)); + popupLayout.getChildren().addAll(title, message); + + StackPane popupContent = new StackPane(); + popupContent.setPrefSize(width, height); + popupContent.getStyleClass().add("notification"); + popupContent.getChildren().addAll(popupLayout); + + final Popup POPUP = new Popup(); + POPUP.setX(getX()); + POPUP.setY(getY()); + POPUP.getContent().add(popupContent); + POPUP.addEventHandler(MouseEvent.MOUSE_PRESSED, new WeakEventHandler<>(event -> + fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, POPUP, NotificationEvent.NOTIFICATION_PRESSED)) + )); + popups.add(POPUP); + + // Add a timeline for popup fade out + KeyValue fadeOutBegin = new KeyValue(POPUP.opacityProperty(), 1.0); + KeyValue fadeOutEnd = new KeyValue(POPUP.opacityProperty(), 0.0); + + KeyFrame kfBegin = new KeyFrame(Duration.ZERO, fadeOutBegin); + KeyFrame kfEnd = new KeyFrame(popupAnimationTime, fadeOutEnd); + + Timeline timeline = new Timeline(kfBegin, kfEnd); + timeline.setDelay(popupLifetime); + timeline.setOnFinished(actionEvent -> Platform.runLater(() -> { + POPUP.hide(); + popups.remove(POPUP); + fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, POPUP, NotificationEvent.HIDE_NOTIFICATION)); + })); + + if (stage.isShowing()) { + stage.toFront(); + } else { + stage.show(); + } + + POPUP.show(stage); + fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, POPUP, NotificationEvent.SHOW_NOTIFICATION)); + timeline.play(); + } + + private double getX() { + if (null == stageRef) return calcX( 0.0, Screen.getPrimary().getBounds().getWidth() ); + + return calcX(stageRef.getX(), stageRef.getWidth()); + } + private double getY() { + if (null == stageRef) return calcY( 0.0, Screen.getPrimary().getBounds().getHeight() ); + return calcY(stageRef.getY(), stageRef.getHeight()); + } + + private double calcX(final double LEFT, final double TOTAL_WIDTH) { + switch (popupLocation) { + case TOP_LEFT : case CENTER_LEFT : case BOTTOM_LEFT : return LEFT + offsetX; + case TOP_CENTER: case CENTER : case BOTTOM_CENTER: return LEFT + (TOTAL_WIDTH - width) * 0.5 - offsetX; + case TOP_RIGHT : case CENTER_RIGHT: case BOTTOM_RIGHT : return LEFT + TOTAL_WIDTH - width - offsetX; + default: return 0.0; + } + } + private double calcY(final double TOP, final double TOTAL_HEIGHT ) { + switch (popupLocation) { + case TOP_LEFT : case TOP_CENTER : case TOP_RIGHT : return TOP + offsetY; + case CENTER_LEFT: case CENTER : case CENTER_RIGHT: return TOP + (TOTAL_HEIGHT- height)/2 - offsetY; + case BOTTOM_LEFT: case BOTTOM_CENTER: case BOTTOM_RIGHT: return TOP + TOTAL_HEIGHT - height - offsetY; + default: return 0.0; + } + } + + + // ******************** Event handling ******************************** + public final ObjectProperty> onNotificationPressedProperty() { return onNotificationPressed; } + public final void setOnNotificationPressed(EventHandler value) { onNotificationPressedProperty().set(value); } + public final EventHandler getOnNotificationPressed() { return onNotificationPressedProperty().get(); } + private ObjectProperty> onNotificationPressed = new ObjectPropertyBase>() { + @Override public Object getBean() { return this; } + @Override public String getName() { return "onNotificationPressed";} + }; + + public final ObjectProperty> onShowNotificationProperty() { return onShowNotification; } + public final void setOnShowNotification(EventHandler value) { onShowNotificationProperty().set(value); } + public final EventHandler getOnShowNotification() { return onShowNotificationProperty().get(); } + private ObjectProperty> onShowNotification = new ObjectPropertyBase>() { + @Override public Object getBean() { return this; } + @Override public String getName() { return "onShowNotification";} + }; + + public final ObjectProperty> onHideNotificationProperty() { return onHideNotification; } + public final void setOnHideNotification(EventHandler value) { onHideNotificationProperty().set(value); } + public final EventHandler getOnHideNotification() { return onHideNotificationProperty().get(); } + private ObjectProperty> onHideNotification = new ObjectPropertyBase>() { + @Override public Object getBean() { return this; } + @Override public String getName() { return "onHideNotification";} + }; + + + public void fireNotificationEvent(final NotificationEvent EVENT) { + final EventType TYPE = EVENT.getEventType(); + final EventHandler HANDLER; + if (NotificationEvent.NOTIFICATION_PRESSED == TYPE) { + HANDLER = getOnNotificationPressed(); + } else if (NotificationEvent.SHOW_NOTIFICATION == TYPE) { + HANDLER = getOnShowNotification(); + } else if (NotificationEvent.HIDE_NOTIFICATION == TYPE) { + HANDLER = getOnHideNotification(); + } else { + HANDLER = null; + } + if (null == HANDLER) return; + HANDLER.handle(EVENT); + } + + } +} From 6435e2ab803de7d47d741112e6415bba28ade0c4 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Thu, 30 Oct 2014 15:06:25 +0100 Subject: [PATCH 3/4] Reformat enzo Notification per Bitsquare rules --- .../enzo/notification/Notification.java | 317 ++++++++++++------ 1 file changed, 207 insertions(+), 110 deletions(-) diff --git a/src/main/java/eu/hansolo/enzo/notification/Notification.java b/src/main/java/eu/hansolo/enzo/notification/Notification.java index f493a5c306..7b1e3f9f35 100644 --- a/src/main/java/eu/hansolo/enzo/notification/Notification.java +++ b/src/main/java/eu/hansolo/enzo/notification/Notification.java @@ -16,6 +16,8 @@ package eu.hansolo.enzo.notification; +import java.util.stream.IntStream; + import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; @@ -29,22 +31,17 @@ import javafx.event.EventType; import javafx.event.WeakEventHandler; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.Scene; -import javafx.scene.control.Label; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.Region; -import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; +import javafx.scene.*; +import javafx.scene.control.*; +import javafx.scene.image.*; +import javafx.scene.input.*; +import javafx.scene.layout.*; import javafx.stage.Popup; import javafx.stage.Screen; import javafx.stage.Stage; import javafx.stage.StageStyle; import javafx.util.Duration; -import java.util.stream.IntStream; - /** * Created by @@ -53,47 +50,49 @@ import java.util.stream.IntStream; * Time: 07:10 */ public class Notification { - public static final Image INFO_ICON = new Image(Notifier.class.getResourceAsStream("info.png")); + public static final Image INFO_ICON = new Image(Notifier.class.getResourceAsStream("info.png")); public static final Image WARNING_ICON = new Image(Notifier.class.getResourceAsStream("warning.png")); public static final Image SUCCESS_ICON = new Image(Notifier.class.getResourceAsStream("success.png")); - public static final Image ERROR_ICON = new Image(Notifier.class.getResourceAsStream("error.png")); - public final String TITLE; - public final String MESSAGE; - public final Image IMAGE; + public static final Image ERROR_ICON = new Image(Notifier.class.getResourceAsStream("error.png")); + public final String TITLE; + public final String MESSAGE; + public final Image IMAGE; // ******************** Constructors ************************************** public Notification(final String TITLE, final String MESSAGE) { this(TITLE, MESSAGE, null); } + public Notification(final String MESSAGE, final Image IMAGE) { this("", MESSAGE, IMAGE); } + public Notification(final String TITLE, final String MESSAGE, final Image IMAGE) { - this.TITLE = TITLE; + this.TITLE = TITLE; this.MESSAGE = MESSAGE; - this.IMAGE = IMAGE; + this.IMAGE = IMAGE; } - + // ******************** Inner Classes ************************************* public enum Notifier { INSTANCE; - private static final double ICON_WIDTH = 24; - private static final double ICON_HEIGHT = 24; - private static double width = 300; - private static double height = 80; - private static double offsetX = 0; - private static double offsetY = 25; - private static double spacingY = 5; - private static Pos popupLocation = Pos.TOP_RIGHT; - private static Stage stageRef = null; - private Duration popupLifetime; - private Duration popupAnimationTime; - private Stage stage; - private Scene scene; - private ObservableList popups; + private static final double ICON_WIDTH = 24; + private static final double ICON_HEIGHT = 24; + private static double width = 300; + private static double height = 80; + private static double offsetX = 0; + private static double offsetY = 25; + private static double spacingY = 5; + private static Pos popupLocation = Pos.TOP_RIGHT; + private static Stage stageRef = null; + private Duration popupLifetime; + private Duration popupAnimationTime; + private Stage stage; + private Scene scene; + private ObservableList popups; // ******************** Constructor *************************************** @@ -105,27 +104,28 @@ public class Notification { // ******************** Initialization ************************************ private void init() { - popupLifetime = Duration.millis(5000); + popupLifetime = Duration.millis(5000); popupAnimationTime = Duration.millis(500); - popups = FXCollections.observableArrayList(); + popups = FXCollections.observableArrayList(); } private void initGraphics() { scene = new Scene(new Region()); scene.setFill(null); - scene.getStylesheets().add(getClass().getResource("notifier.css").toExternalForm()); + scene.getStylesheets().add(getClass().getResource("notifier.css").toExternalForm()); stage = new Stage(); stage.initStyle(StageStyle.TRANSPARENT); - stage.setAlwaysOnTop(true); + stage.setAlwaysOnTop(true); } // ******************** Methods ******************************************* + /** - * @param STAGE_REF The Notification will be positioned relative to the given Stage.
- * If null then the Notification will be positioned relative to the primary Screen. - * @param POPUP_LOCATION The default is TOP_RIGHT of primary Screen. + * @param STAGE_REF The Notification will be positioned relative to the given Stage.
+ * If null then the Notification will be positioned relative to the primary Screen. + * @param POPUP_LOCATION The default is TOP_RIGHT of primary Screen. */ public static void setPopupLocation(final Stage STAGE_REF, final Pos POPUP_LOCATION) { if (null != STAGE_REF) { @@ -140,6 +140,7 @@ public class Notification { * stage is closed Notifications will be shut down as well.
* This is only needed if setPopupLocation is called * without a stage reference. + * * @param OWNER */ public static void setNotificationOwner(final Stage OWNER) { @@ -147,43 +148,43 @@ public class Notification { } /** - * @param OFFSET_X The horizontal shift required. - *
The default is 0 px. + * @param OFFSET_X The horizontal shift required. + *
The default is 0 px. */ public static void setOffsetX(final double OFFSET_X) { Notifier.offsetX = OFFSET_X; } /** - * @param OFFSET_Y The vertical shift required. - *
The default is 25 px. + * @param OFFSET_Y The vertical shift required. + *
The default is 25 px. */ public static void setOffsetY(final double OFFSET_Y) { Notifier.offsetY = OFFSET_Y; } /** - * @param WIDTH The default is 300 px. + * @param WIDTH The default is 300 px. */ public static void setWidth(final double WIDTH) { Notifier.width = WIDTH; } /** - * @param HEIGHT The default is 80 px. + * @param HEIGHT The default is 80 px. */ public static void setHeight(final double HEIGHT) { Notifier.height = HEIGHT; } /** - * @param SPACING_Y The spacing between multiple Notifications. - *
The default is 5 px. + * @param SPACING_Y The spacing between multiple Notifications. + *
The default is 5 px. */ public static void setSpacingY(final double SPACING_Y) { Notifier.spacingY = SPACING_Y; } - + public void stop() { popups.clear(); stage.close(); @@ -192,6 +193,7 @@ public class Notification { /** * Returns the Duration that the notification will stay on screen before it * will fade out. The default is 5000 ms + * * @return the Duration the popup notification will stay on screen */ public Duration getPopupLifetime() { @@ -201,6 +203,7 @@ public class Notification { /** * Defines the Duration that the popup notification will stay on screen before it * will fade out. The parameter is limited to values between 2 and 20 seconds. + * * @param POPUP_LIFETIME */ public void setPopupLifetime(final Duration POPUP_LIFETIME) { @@ -210,6 +213,7 @@ public class Notification { /** * Returns the Duration that it takes to fade out the notification * The parameter is limited to values between 0 and 1000 ms + * * @return the Duration that it takes to fade out the notification */ public Duration getPopupAnimationTime() { @@ -220,14 +224,16 @@ public class Notification { * Defines the Duration that it takes to fade out the notification * The parameter is limited to values between 0 and 1000 ms * Default value is 500 ms + * * @param POPUP_ANIMATION_TIME */ public void setPopupAnimationTime(final Duration POPUP_ANIMATION_TIME) { popupAnimationTime = Duration.millis(clamp(0, 1000, POPUP_ANIMATION_TIME.toMillis())); } - + /** * Show the given Notification on the screen + * * @param NOTIFICATION */ public void notify(final Notification NOTIFICATION) { @@ -237,6 +243,7 @@ public class Notification { /** * Show a Notification with the given parameters on the screen + * * @param TITLE * @param MESSAGE * @param IMAGE @@ -247,6 +254,7 @@ public class Notification { /** * Show a Notification with the given title and message and an Info icon + * * @param TITLE * @param MESSAGE */ @@ -256,6 +264,7 @@ public class Notification { /** * Show a Notification with the given title and message and a Warning icon + * * @param TITLE * @param MESSAGE */ @@ -265,6 +274,7 @@ public class Notification { /** * Show a Notification with the given title and message and a Checkmark icon + * * @param TITLE * @param MESSAGE */ @@ -274,6 +284,7 @@ public class Notification { /** * Show a Notification with the given title and message and an Error icon + * * @param TITLE * @param MESSAGE */ @@ -283,6 +294,7 @@ public class Notification { /** * Makes sure that the given VALUE is within the range of MIN to MAX + * * @param MIN * @param MAX * @param VALUE @@ -298,28 +310,33 @@ public class Notification { * Reorder the popup Notifications on screen so that the latest Notification will stay on top */ private void preOrder() { - if (popups.isEmpty()) return; + if (popups.isEmpty()) return; IntStream.range(0, popups.size()).parallel().forEachOrdered( - i -> { - switch (popupLocation) { - case TOP_LEFT: case TOP_CENTER: case TOP_RIGHT: - popups.get(i).setY(popups.get(i).getY() + height + spacingY); - break; - - case BOTTOM_LEFT: case BOTTOM_CENTER: case BOTTOM_RIGHT: - popups.get(i).setY(popups.get(i).getY() - height - spacingY); - break; - - default: - popups.get(i).setY(popups.get(i).getY() - height - spacingY); - break; - } - } + i -> { + switch (popupLocation) { + case TOP_LEFT: + case TOP_CENTER: + case TOP_RIGHT: + popups.get(i).setY(popups.get(i).getY() + height + spacingY); + break; + + case BOTTOM_LEFT: + case BOTTOM_CENTER: + case BOTTOM_RIGHT: + popups.get(i).setY(popups.get(i).getY() - height - spacingY); + break; + + default: + popups.get(i).setY(popups.get(i).getY() - height - spacingY); + break; + } + } ); } /** * Creates and shows a popup with the data from the given Notification object + * * @param NOTIFICATION */ private void showPopup(final Notification NOTIFICATION) { @@ -348,88 +365,165 @@ public class Notification { POPUP.setY(getY()); POPUP.getContent().add(popupContent); POPUP.addEventHandler(MouseEvent.MOUSE_PRESSED, new WeakEventHandler<>(event -> - fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, POPUP, NotificationEvent.NOTIFICATION_PRESSED)) - )); + fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, POPUP, + NotificationEvent.NOTIFICATION_PRESSED)) + )); popups.add(POPUP); // Add a timeline for popup fade out - KeyValue fadeOutBegin = new KeyValue(POPUP.opacityProperty(), 1.0); - KeyValue fadeOutEnd = new KeyValue(POPUP.opacityProperty(), 0.0); + KeyValue fadeOutBegin = new KeyValue(POPUP.opacityProperty(), 1.0); + KeyValue fadeOutEnd = new KeyValue(POPUP.opacityProperty(), 0.0); KeyFrame kfBegin = new KeyFrame(Duration.ZERO, fadeOutBegin); - KeyFrame kfEnd = new KeyFrame(popupAnimationTime, fadeOutEnd); + KeyFrame kfEnd = new KeyFrame(popupAnimationTime, fadeOutEnd); Timeline timeline = new Timeline(kfBegin, kfEnd); timeline.setDelay(popupLifetime); timeline.setOnFinished(actionEvent -> Platform.runLater(() -> { POPUP.hide(); popups.remove(POPUP); - fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, POPUP, NotificationEvent.HIDE_NOTIFICATION)); + fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, POPUP, + NotificationEvent.HIDE_NOTIFICATION)); })); if (stage.isShowing()) { stage.toFront(); - } else { + } + else { stage.show(); } POPUP.show(stage); - fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, POPUP, NotificationEvent.SHOW_NOTIFICATION)); + fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, POPUP, + NotificationEvent.SHOW_NOTIFICATION)); timeline.play(); } private double getX() { - if (null == stageRef) return calcX( 0.0, Screen.getPrimary().getBounds().getWidth() ); + if (null == stageRef) return calcX(0.0, Screen.getPrimary().getBounds().getWidth()); return calcX(stageRef.getX(), stageRef.getWidth()); } + private double getY() { - if (null == stageRef) return calcY( 0.0, Screen.getPrimary().getBounds().getHeight() ); + if (null == stageRef) return calcY(0.0, Screen.getPrimary().getBounds().getHeight()); return calcY(stageRef.getY(), stageRef.getHeight()); } private double calcX(final double LEFT, final double TOTAL_WIDTH) { switch (popupLocation) { - case TOP_LEFT : case CENTER_LEFT : case BOTTOM_LEFT : return LEFT + offsetX; - case TOP_CENTER: case CENTER : case BOTTOM_CENTER: return LEFT + (TOTAL_WIDTH - width) * 0.5 - offsetX; - case TOP_RIGHT : case CENTER_RIGHT: case BOTTOM_RIGHT : return LEFT + TOTAL_WIDTH - width - offsetX; - default: return 0.0; + case TOP_LEFT: + case CENTER_LEFT: + case BOTTOM_LEFT: + return LEFT + offsetX; + case TOP_CENTER: + case CENTER: + case BOTTOM_CENTER: + return LEFT + (TOTAL_WIDTH - width) * 0.5 - offsetX; + case TOP_RIGHT: + case CENTER_RIGHT: + case BOTTOM_RIGHT: + return LEFT + TOTAL_WIDTH - width - offsetX; + default: + return 0.0; } } - private double calcY(final double TOP, final double TOTAL_HEIGHT ) { + + private double calcY(final double TOP, final double TOTAL_HEIGHT) { switch (popupLocation) { - case TOP_LEFT : case TOP_CENTER : case TOP_RIGHT : return TOP + offsetY; - case CENTER_LEFT: case CENTER : case CENTER_RIGHT: return TOP + (TOTAL_HEIGHT- height)/2 - offsetY; - case BOTTOM_LEFT: case BOTTOM_CENTER: case BOTTOM_RIGHT: return TOP + TOTAL_HEIGHT - height - offsetY; - default: return 0.0; + case TOP_LEFT: + case TOP_CENTER: + case TOP_RIGHT: + return TOP + offsetY; + case CENTER_LEFT: + case CENTER: + case CENTER_RIGHT: + return TOP + (TOTAL_HEIGHT - height) / 2 - offsetY; + case BOTTOM_LEFT: + case BOTTOM_CENTER: + case BOTTOM_RIGHT: + return TOP + TOTAL_HEIGHT - height - offsetY; + default: + return 0.0; } } - - + + // ******************** Event handling ******************************** - public final ObjectProperty> onNotificationPressedProperty() { return onNotificationPressed; } - public final void setOnNotificationPressed(EventHandler value) { onNotificationPressedProperty().set(value); } - public final EventHandler getOnNotificationPressed() { return onNotificationPressedProperty().get(); } - private ObjectProperty> onNotificationPressed = new ObjectPropertyBase>() { - @Override public Object getBean() { return this; } - @Override public String getName() { return "onNotificationPressed";} - }; + public final ObjectProperty> onNotificationPressedProperty() { + return onNotificationPressed; + } - public final ObjectProperty> onShowNotificationProperty() { return onShowNotification; } - public final void setOnShowNotification(EventHandler value) { onShowNotificationProperty().set(value); } - public final EventHandler getOnShowNotification() { return onShowNotificationProperty().get(); } - private ObjectProperty> onShowNotification = new ObjectPropertyBase>() { - @Override public Object getBean() { return this; } - @Override public String getName() { return "onShowNotification";} - }; + public final void setOnNotificationPressed(EventHandler value) { + onNotificationPressedProperty().set(value); + } - public final ObjectProperty> onHideNotificationProperty() { return onHideNotification; } - public final void setOnHideNotification(EventHandler value) { onHideNotificationProperty().set(value); } - public final EventHandler getOnHideNotification() { return onHideNotificationProperty().get(); } - private ObjectProperty> onHideNotification = new ObjectPropertyBase>() { - @Override public Object getBean() { return this; } - @Override public String getName() { return "onHideNotification";} - }; + public final EventHandler getOnNotificationPressed() { + return onNotificationPressedProperty().get(); + } + + private ObjectProperty> onNotificationPressed = new + ObjectPropertyBase>() { + @Override + public Object getBean() { + return this; + } + + @Override + public String getName() { + return "onNotificationPressed"; + } + }; + + public final ObjectProperty> onShowNotificationProperty() { + return onShowNotification; + } + + public final void setOnShowNotification(EventHandler value) { + onShowNotificationProperty().set(value); + } + + public final EventHandler getOnShowNotification() { + return onShowNotificationProperty().get(); + } + + private ObjectProperty> onShowNotification = new + ObjectPropertyBase>() { + @Override + public Object getBean() { + return this; + } + + @Override + public String getName() { + return "onShowNotification"; + } + }; + + public final ObjectProperty> onHideNotificationProperty() { + return onHideNotification; + } + + public final void setOnHideNotification(EventHandler value) { + onHideNotificationProperty().set(value); + } + + public final EventHandler getOnHideNotification() { + return onHideNotificationProperty().get(); + } + + private ObjectProperty> onHideNotification = new + ObjectPropertyBase>() { + @Override + public Object getBean() { + return this; + } + + @Override + public String getName() { + return "onHideNotification"; + } + }; public void fireNotificationEvent(final NotificationEvent EVENT) { @@ -437,11 +531,14 @@ public class Notification { final EventHandler HANDLER; if (NotificationEvent.NOTIFICATION_PRESSED == TYPE) { HANDLER = getOnNotificationPressed(); - } else if (NotificationEvent.SHOW_NOTIFICATION == TYPE) { + } + else if (NotificationEvent.SHOW_NOTIFICATION == TYPE) { HANDLER = getOnShowNotification(); - } else if (NotificationEvent.HIDE_NOTIFICATION == TYPE) { + } + else if (NotificationEvent.HIDE_NOTIFICATION == TYPE) { HANDLER = getOnHideNotification(); - } else { + } + else { HANDLER = null; } if (null == HANDLER) return; From a845088a6e26c238e21db04b2ea9da0b76be1b3a Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Thu, 30 Oct 2014 15:16:37 +0100 Subject: [PATCH 4/4] Customize enzo Notification to meet Bitsquare reqs This reflects the customizations to Notification originally committed in revision 1a6fb9, but includes *only* the Notification class instead of bringing in all related enzo types and resources. We now rely on the enzo jar for that. --- .../enzo/notification/Notification.java | 86 +++++++++---------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/src/main/java/eu/hansolo/enzo/notification/Notification.java b/src/main/java/eu/hansolo/enzo/notification/Notification.java index 7b1e3f9f35..4b5901f7f0 100644 --- a/src/main/java/eu/hansolo/enzo/notification/Notification.java +++ b/src/main/java/eu/hansolo/enzo/notification/Notification.java @@ -29,25 +29,25 @@ import javafx.collections.ObservableList; import javafx.event.EventHandler; import javafx.event.EventType; import javafx.event.WeakEventHandler; -import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.*; import javafx.scene.control.*; import javafx.scene.image.*; import javafx.scene.input.*; import javafx.scene.layout.*; -import javafx.stage.Popup; import javafx.stage.Screen; import javafx.stage.Stage; import javafx.stage.StageStyle; import javafx.util.Duration; +import org.controlsfx.control.PopOver; + /** - * Created by - * User: hansolo - * Date: 01.07.13 - * Time: 07:10 + * A copy of the original {@link eu.hansolo.enzo.notification.Notification} class at revision eb1d321, containing + * several changes that were otherwise not possible through subclassing or other customization via the existing + * Notification API. See git history for this file for exact details as to what has been changed. All other + * {@code eu.hansolo.enzo.*} types are loaded from the enzo jar (see build.gradle for details). */ public class Notification { public static final Image INFO_ICON = new Image(Notifier.class.getResourceAsStream("info.png")); @@ -81,10 +81,10 @@ public class Notification { private static final double ICON_WIDTH = 24; private static final double ICON_HEIGHT = 24; - private static double width = 300; - private static double height = 80; + private static double width = 321; + private static double height = 49; private static double offsetX = 0; - private static double offsetY = 25; + private static double offsetY = 2; private static double spacingY = 5; private static Pos popupLocation = Pos.TOP_RIGHT; private static Stage stageRef = null; @@ -92,7 +92,7 @@ public class Notification { private Duration popupAnimationTime; private Stage stage; private Scene scene; - private ObservableList popups; + private ObservableList popups; // ******************** Constructor *************************************** @@ -112,11 +112,12 @@ public class Notification { private void initGraphics() { scene = new Scene(new Region()); scene.setFill(null); - scene.getStylesheets().add(getClass().getResource("notifier.css").toExternalForm()); + scene.getStylesheets().setAll( + getClass().getResource("/io/bitsquare/gui/bitsquare.css").toExternalForm(), + getClass().getResource("/io/bitsquare/gui/images.css").toExternalForm()); stage = new Stage(); stage.initStyle(StageStyle.TRANSPARENT); - stage.setAlwaysOnTop(true); } @@ -312,7 +313,7 @@ public class Notification { private void preOrder() { if (popups.isEmpty()) return; IntStream.range(0, popups.size()).parallel().forEachOrdered( - i -> { + i -> Platform.runLater(() -> { switch (popupLocation) { case TOP_LEFT: case TOP_CENTER: @@ -330,7 +331,7 @@ public class Notification { popups.get(i).setY(popups.get(i).getY() - height - spacingY); break; } - } + }) ); } @@ -340,39 +341,36 @@ public class Notification { * @param NOTIFICATION */ private void showPopup(final Notification NOTIFICATION) { + ImageView icon = new ImageView( + new Image(Notifier.class.getResourceAsStream("/images/notification_logo.png"))); + icon.relocate(10, 7); + Label title = new Label(NOTIFICATION.TITLE); - title.getStyleClass().add("title"); + title.setStyle(" -fx-text-fill:#333333; -fx-font-size:12; -fx-font-weight:bold;"); + title.relocate(60, 6); - ImageView icon = new ImageView(NOTIFICATION.IMAGE); - icon.setFitWidth(ICON_WIDTH); - icon.setFitHeight(ICON_HEIGHT); + Label message = new Label(NOTIFICATION.MESSAGE); + message.relocate(60, 25); + message.setStyle(" -fx-text-fill:#333333; -fx-font-size:11; "); - Label message = new Label(NOTIFICATION.MESSAGE, icon); - message.getStyleClass().add("message"); + Pane popupLayout = new Pane(); + popupLayout.setPrefSize(width, height); + popupLayout.getChildren().addAll(icon, title, message); - VBox popupLayout = new VBox(); - popupLayout.setSpacing(10); - popupLayout.setPadding(new Insets(10, 10, 10, 10)); - popupLayout.getChildren().addAll(title, message); - - StackPane popupContent = new StackPane(); - popupContent.setPrefSize(width, height); - popupContent.getStyleClass().add("notification"); - popupContent.getChildren().addAll(popupLayout); - - final Popup POPUP = new Popup(); - POPUP.setX(getX()); - POPUP.setY(getY()); - POPUP.getContent().add(popupContent); - POPUP.addEventHandler(MouseEvent.MOUSE_PRESSED, new WeakEventHandler<>(event -> - fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, POPUP, + PopOver popOver = new PopOver(popupLayout); + popOver.setDetachable(false); + popOver.setArrowSize(0); + popOver.setX(getX()); + popOver.setY(getY()); + popOver.addEventHandler(MouseEvent.MOUSE_PRESSED, new WeakEventHandler<>(event -> + fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, popOver, NotificationEvent.NOTIFICATION_PRESSED)) )); - popups.add(POPUP); + popups.add(popOver); // Add a timeline for popup fade out - KeyValue fadeOutBegin = new KeyValue(POPUP.opacityProperty(), 1.0); - KeyValue fadeOutEnd = new KeyValue(POPUP.opacityProperty(), 0.0); + KeyValue fadeOutBegin = new KeyValue(popOver.opacityProperty(), 1.0); + KeyValue fadeOutEnd = new KeyValue(popOver.opacityProperty(), 0.0); KeyFrame kfBegin = new KeyFrame(Duration.ZERO, fadeOutBegin); KeyFrame kfEnd = new KeyFrame(popupAnimationTime, fadeOutEnd); @@ -380,9 +378,9 @@ public class Notification { Timeline timeline = new Timeline(kfBegin, kfEnd); timeline.setDelay(popupLifetime); timeline.setOnFinished(actionEvent -> Platform.runLater(() -> { - POPUP.hide(); - popups.remove(POPUP); - fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, POPUP, + popOver.hide(); + popups.remove(popOver); + fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, popOver, NotificationEvent.HIDE_NOTIFICATION)); })); @@ -393,8 +391,8 @@ public class Notification { stage.show(); } - POPUP.show(stage); - fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, POPUP, + popOver.show(stage); + fireNotificationEvent(new NotificationEvent(NOTIFICATION, Notifier.this, popOver, NotificationEvent.SHOW_NOTIFICATION)); timeline.play(); }