org.controlsfx.control.NotificationPane Maven / Gradle / Ivy
Show all versions of controlsfx Show documentation
/**
* Copyright (c) 2013, 2014 ControlsFX
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of ControlsFX, any associated website, nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.controlsfx.control;
import impl.org.controlsfx.skin.NotificationPaneSkin;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.scene.Node;
import javafx.scene.control.Skin;
import javafx.scene.web.WebView;
import org.controlsfx.control.action.Action;
/**
* The NotificationPane control is a container control that, when prompted by
* the {@link #show()} method, will show a non-modal message to the user. The
* notification appears as a bar that will slide in to their application window,
* either from the top or the bottom of the NotificationPane (based on
* {@link #showFromTopProperty()}) wherever that may be in the scenegraph.
*
* Alternative Styling
* As is visible in the screenshots further down this documentation,
* there are two different styles supported by the NotificationPane control.
* Firstly, there is the default style based on the JavaFX Modena look. The
* alternative style is what is currently referred to as the 'dark' look. To
* enable this functionality, simply do the following:
*
*
* {@code
* NotificationPane notificationPane = new NotificationPane();
* notificationPane.getStyleClass().add(NotificationPane.STYLE_CLASS_DARK);
* }
*
* Screenshots
* To better explain NotificationPane, here is a table showing both the
* default and dark look for the NotificationPane on a Windows machine (although
* that shouldn't impact the visuals a great deal). Also, to show the difference
* between top and bottom placement, these two modes are also captured in the
* screenshots below:
*
*
*
*
*
* Setting
* Screenshot
*
*
* Light theme from top:
*
*
*
* Light theme from bottom:
*
*
*
* Dark theme from top:
*
*
*
* Dark theme from bottom:
*
*
*
*
*
* Code Examples
*
* NotificationPane is a conceptually very simple control - you simply create
* your user interface as you normally would, and then wrap it inside the
* NotificationPane. You can then show a notification bar on top of your content
* simply by calling {@link #show()} on the notification bar. Here is an example:
*
*
* {@code
* // Create a WebView
* WebView webView = new WebView();
*
* // Wrap it inside a NotificationPane
* NotificationPane notificationPane = new NotificationPane(webView);
*
* // and put the NotificationPane inside a Tab
* Tab tab1 = new Tab("Tab 1");
* tab1.setContent(notificationPane);
*
* // and the Tab inside a TabPane. We just have one tab here, but of course
* // you can have more!
* TabPane tabPane = new TabPane();
* tabPane.getTabs().addAll(tab1);
* }
*
* Now that the notification pane is installed inside the tab, at some point
* later in you application lifecycle, you can do something like the following
* to have the notification bar slide into view:
*
*
* {@code
* notificationPane.setText("Do you want to save your password?");
* notificationPane.getActions().add(new AbstractAction("Save Password") {
* public void execute(ActionEvent ae) {
* // do save...
*
* // then hide...
* notificationPane.hide();
* }
* }}
*
* @see Action
* @see Action
*/
public class NotificationPane extends ControlsFXControl {
/***************************************************************************
*
* Static fields
*
**************************************************************************/
public static final String STYLE_CLASS_DARK = "dark"; //$NON-NLS-1$
/**
* Called when the NotificationPane will be shown.
*/
public static final EventType ON_SHOWING =
new EventType<>(Event.ANY, "NOTIFICATION_PANE_ON_SHOWING"); //$NON-NLS-1$
/**
* Called when the NotificationPane shows.
*/
public static final EventType ON_SHOWN =
new EventType<>(Event.ANY, "NOTIFICATION_PANE_ON_SHOWN"); //$NON-NLS-1$
/**
* Called when the NotificationPane will be hidden.
*/
public static final EventType ON_HIDING =
new EventType<>(Event.ANY, "NOTIFICATION_PANE_ON_HIDING"); //$NON-NLS-1$
/**
* Called when the NotificationPane is hidden.
*/
public static final EventType ON_HIDDEN =
new EventType<>(Event.ANY, "NOTIFICATION_PANE_ON_HIDDEN"); //$NON-NLS-1$
/***************************************************************************
*
* Constructors
*
**************************************************************************/
/**
* Creates an instance of NotificationPane with no
* {@link #contentProperty() content}, {@link #textProperty() text},
* {@link #graphicProperty() graphic} properties set, and no
* {@link #getActions() actions} specified.
*/
public NotificationPane() {
this(null);
}
/**
* Creates an instance of NotificationPane with the
* {@link #contentProperty() content} property set, but no
* {@link #textProperty() text} or
* {@link #graphicProperty() graphic} property set, and no
* {@link #getActions() actions} specified.
*
* @param content The content to show in the NotificationPane behind where
* the notification bar will appear, that is, the content
* will notappear in the notification bar.
*/
public NotificationPane(Node content) {
getStyleClass().add(DEFAULT_STYLE_CLASS);
setContent(content);
updateStyleClasses();
}
/***************************************************************************
*
* Overriding public API
*
**************************************************************************/
/** {@inheritDoc} */
@Override protected Skin> createDefaultSkin() {
return new NotificationPaneSkin(this);
}
/** {@inheritDoc} */
@Override public String getUserAgentStylesheet() {
return getUserAgentStylesheet(NotificationPane.class, "notificationpane.css");
}
/***************************************************************************
*
* Properties
*
**************************************************************************/
// --- content
private ObjectProperty content = new SimpleObjectProperty<>(this, "content"); //$NON-NLS-1$
/**
* The content property represents what is shown in the scene
* that is not within the notification bar. In other words,
* it is what the notification bar should appear on top of. For example, in
* the scenario where you are using a {@link WebView} to show to the user
* websites, and you want to popup up a notification bar to save a password,
* the content would be the {@link WebView}. Refer to the
* {@link NotificationPane} class documentation for more details.
*
* @return A property representing the content of this NotificationPane.
*/
public final ObjectProperty contentProperty() {
return content;
}
/**
* Set the content to be shown in the scene,
* that is not within the notification bar.
* @param value
*/
public final void setContent(Node value) {
this.content.set(value);
}
/**
*
* @return The content shown in the scene.
*/
public final Node getContent() {
return content.get();
}
// --- text
private StringProperty text = new SimpleStringProperty(this, "text"); //$NON-NLS-1$
/**
* The text property represents the text to show within the popup
* notification bar that appears on top of the
* {@link #contentProperty() content} that is within the NotificationPane.
*
* @return A property representing the text shown in the notification bar.
*/
public final StringProperty textProperty() {
return text;
}
/**
* Sets the text to show within the popup
* notification bar that appears on top of the
* {@link #contentProperty() content}.
* @param value
*/
public final void setText(String value) {
this.text.set(value);
}
/**
*
* @return the text showing within the popup
* notification bar that appears on top of the
* {@link #contentProperty() content}.
*/
public final String getText() {
return text.get();
}
// --- graphic
private ObjectProperty graphic = new SimpleObjectProperty<>(this, "graphic"); //$NON-NLS-1$
/**
* The graphic property represents the {@link Node} to show within the popup
* notification bar that appears on top of the
* {@link #contentProperty() content} that is within the NotificationPane.
* Despite the term 'graphic', this can be an arbitrarily complex scenegraph
* in its own right.
*
* @return A property representing the graphic shown in the notification bar.
*/
public final ObjectProperty graphicProperty() {
return graphic;
}
/**
* Sets the {@link Node} to show within the popup
* notification bar.
* @param value
*/
public final void setGraphic(Node value) {
this.graphic.set(value);
}
/**
*
* @return the {@link Node} to show within the popup
* notification bar.
*/
public final Node getGraphic() {
return graphic.get();
}
// --- showing
private ReadOnlyBooleanWrapper showing = new ReadOnlyBooleanWrapper(this, "showing"); //$NON-NLS-1$
/**
* A read-only property that represents whether the notification bar popup
* should be showing to the user or not. To toggle visibility, use the
* {@link #show()} and {@link #hide()} methods.
*
* @return A property representing whether the notification bar is currently showing.
*/
public final ReadOnlyBooleanProperty showingProperty() {
return showing.getReadOnlyProperty();
}
private final void setShowing(boolean value) {
this.showing.set(value);
}
/**
*
* @return whether the notification bar is currently showing.
*/
public final boolean isShowing() {
return showing.get();
}
// --- show from top
private BooleanProperty showFromTop = new SimpleBooleanProperty(this, "showFromTop", true) { //$NON-NLS-1$
@Override protected void invalidated() {
updateStyleClasses();
}
};
/**
* A property representing whether the notification bar should appear from the
* top or the bottom of the NotificationPane area. By default it will appear
* from the top, but this can be changed by setting this property to false.
*
* @return A property representing where the notification bar should appear from.
*/
public final BooleanProperty showFromTopProperty() {
return showFromTop;
}
/**
* Sets whether the notification bar should appear from the
* top or the bottom of the NotificationPane area.
* @param value
*/
public final void setShowFromTop(boolean value) {
this.showFromTop.set(value);
}
/**
* @return whether the notification bar is appearing from the
* top or the bottom of the NotificationPane area.
*/
public final boolean isShowFromTop() {
return showFromTop.get();
}
// --- On Showing
public final ObjectProperty> onShowingProperty() { return onShowing; }
/**
* Called just prior to the {@code NotificationPane} being shown.
*/
public final void setOnShowing(EventHandler value) { onShowingProperty().set(value); }
public final EventHandler getOnShowing() { return onShowingProperty().get(); }
private ObjectProperty> onShowing = new SimpleObjectProperty>(this, "onShowing") { //$NON-NLS-1$
@Override protected void invalidated() {
setEventHandler(ON_SHOWING, get());
}
};
// -- On Shown
public final ObjectProperty> onShownProperty() { return onShown; }
/**
* Called just after the {@link NotificationPane} is shown.
*/
public final void setOnShown(EventHandler value) { onShownProperty().set(value); }
public final EventHandler getOnShown() { return onShownProperty().get(); }
private ObjectProperty> onShown = new SimpleObjectProperty>(this, "onShown") { //$NON-NLS-1$
@Override protected void invalidated() {
setEventHandler(ON_SHOWN, get());
}
};
// --- On Hiding
public final ObjectProperty> onHidingProperty() { return onHiding; }
/**
* Called just prior to the {@link NotificationPane} being hidden.
*/
public final void setOnHiding(EventHandler value) { onHidingProperty().set(value); }
public final EventHandler getOnHiding() { return onHidingProperty().get(); }
private ObjectProperty> onHiding = new SimpleObjectProperty>(this, "onHiding") { //$NON-NLS-1$
@Override protected void invalidated() {
setEventHandler(ON_HIDING, get());
}
};
// --- On Hidden
public final ObjectProperty> onHiddenProperty() { return onHidden; }
/**
* Called just after the {@link NotificationPane} has been hidden.
*/
public final void setOnHidden(EventHandler value) { onHiddenProperty().set(value); }
public final EventHandler getOnHidden() { return onHiddenProperty().get(); }
private ObjectProperty> onHidden = new SimpleObjectProperty>(this, "onHidden") { //$NON-NLS-1$
@Override protected void invalidated() {
setEventHandler(ON_HIDDEN, get());
}
};
// --- close button visibility
private BooleanProperty closeButtonVisible = new SimpleBooleanProperty(this, "closeButtonVisible", true); //$NON-NLS-1$
/**
* A property representing whether the close button in the {@code NotificationPane} should be visible or not.
* By default it will appear but this can be changed by setting this property to false.
*
* @return A property representing whether the close button in the {@code NotificationPane} should be visible.
*/
public final BooleanProperty closeButtonVisibleProperty() {
return closeButtonVisible;
}
/**
* Sets whether the close button in {@code NotificationPane} should be visible.
*
* @param value
*/
public final void setCloseButtonVisible(boolean value) {
this.closeButtonVisible.set(value);
}
/**
* @return whether the close button in {@code NotificationPane} is visible.
*/
public final boolean isCloseButtonVisible() {
return closeButtonVisible.get();
}
/***************************************************************************
*
* Public API
*
**************************************************************************/
// --- actions
private final ObservableList actions = FXCollections. observableArrayList();
/**
* Observable list of actions used for the actions area of the notification
* bar. Modifying the contents of this list will change the actions available to
* the user.
* @return The {@link ObservableList} of actions available to the user.
*/
public final ObservableList getActions() {
return actions;
}
/**
* Call this to make the notification bar appear on top of the
* {@link #contentProperty() content} of this {@link NotificationPane}.
* If the notification bar is already showing this will be a no-op.
*/
public void show() {
setShowing(true);
}
/**
* Shows the NotificationPane with the
* {@link #contentProperty() content} and {@link #textProperty() text}
* property set, but no {@link #graphicProperty() graphic} property set, and
* no {@link #getActions() actions} specified.
*
* @param text The text to show in the notification pane.
*/
public void show(final String text) {
hideAndThen(new Runnable() {
@Override public void run() {
setText(text);
setShowing(true);
}
});
}
/**
* Shows the NotificationPane with the
* {@link #contentProperty() content}, {@link #textProperty() text} and
* {@link #graphicProperty() graphic} properties set, but no
* {@link #getActions() actions} specified.
*
* @param text The text to show in the notification pane.
* @param graphic The node to show in the notification pane.
*/
public void show(final String text, final Node graphic) {
hideAndThen(new Runnable() {
@Override public void run() {
setText(text);
setGraphic(graphic);
setShowing(true);
}
});
}
/**
* Shows the NotificationPane with the
* {@link #contentProperty() content}, {@link #textProperty() text} and
* {@link #graphicProperty() graphic} property set, and the provided actions
* copied into the {@link #getActions() actions} list.
*
* @param text The text to show in the notification pane.
* @param graphic The node to show in the notification pane.
* @param actions The actions to show in the notification pane.
*/
public void show(final String text, final Node graphic, final Action... actions) {
hideAndThen(new Runnable() {
@Override public void run() {
setText(text);
setGraphic(graphic);
if (actions == null) {
getActions().clear();
} else {
for (Action action : actions) {
if (action == null) continue;
getActions().add(action);
}
}
setShowing(true);
}
});
}
/**
* Call this to make the notification bar disappear from the
* {@link #contentProperty() content} of this {@link NotificationPane}.
* If the notification bar is already hidden this will be a no-op.
*/
public void hide() {
setShowing(false);
}
/**************************************************************************
* *
* Private Implementation *
* *
**************************************************************************/
private void updateStyleClasses() {
getStyleClass().removeAll("top", "bottom"); //$NON-NLS-1$ //$NON-NLS-2$
getStyleClass().add(isShowFromTop() ? "top" : "bottom"); //$NON-NLS-1$ //$NON-NLS-2$
}
private void hideAndThen(final Runnable r) {
if (isShowing()) {
final EventHandler eventHandler = new EventHandler() {
@Override public void handle(Event e) {
r.run();
removeEventHandler(NotificationPane.ON_HIDDEN, this);
}
};
addEventHandler(NotificationPane.ON_HIDDEN, eventHandler);
hide();
} else {
r.run();
}
}
/**************************************************************************
* *
* Stylesheet Handling *
* *
**************************************************************************/
private static final String DEFAULT_STYLE_CLASS = "notification-pane"; //$NON-NLS-1$
}