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

org.controlsfx.control.BreadCrumbBar Maven / Gradle / Ivy

Go to download

High quality UI controls and other tools to complement the core JavaFX distribution

There is a newer version: 11.2.1
Show newest version
/**
 * Copyright (c) 2014, 2020, 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.BreadCrumbBarSkin;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ObjectPropertyBase;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Skin;
import javafx.scene.control.TreeItem;
import javafx.scene.paint.Color;
import javafx.scene.shape.ArcTo;
import javafx.scene.shape.ClosePath;
import javafx.scene.shape.HLineTo;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.util.Callback;

import java.util.UUID;

/**
 * Represents a bread crumb bar. This control is useful to visualize and navigate 
 * a hierarchical path structure, such as file systems.
 * 
 * 

Shown below is a screenshot of the BreadCrumbBar control: * *
*

* Screenshot of BreadCrumbBar *
*/ public class BreadCrumbBar extends ControlsFXControl { private static final String STYLE_CLASS_FIRST = "first"; //$NON-NLS-1$ /** * Represents an Event which is fired when a bread crumb was activated. */ @SuppressWarnings("serial") public static class BreadCrumbActionEvent extends Event { /** * The event type that should be listened to by people interested in * knowing when the {@link BreadCrumbBar#selectedCrumbProperty() selected crumb} * has changed. */ public static final EventType> CRUMB_ACTION = new EventType<>("CRUMB_ACTION" + UUID.randomUUID().toString()); //$NON-NLS-1$ private final TreeItem selectedCrumb; /** * Creates a new event that can subsequently be fired. */ public BreadCrumbActionEvent(TreeItem selectedCrumb) { super(CRUMB_ACTION); this.selectedCrumb = selectedCrumb; } /** * Returns the crumb which was the action target. */ public TreeItem getSelectedCrumb() { return selectedCrumb; } } /** * Construct a tree model from the flat list which then can be set * as selectedCrumb node to be shown * @param crumbs */ public static TreeItem buildTreeModel(@SuppressWarnings("unchecked") T... crumbs){ TreeItem subRoot = null; for (T crumb : crumbs) { TreeItem currentNode = new TreeItem<>(crumb); if(subRoot == null){ subRoot = currentNode; }else{ subRoot.getChildren().add(currentNode); subRoot = currentNode; } } return subRoot; } /*************************************************************************** * * Private fields * **************************************************************************/ /** * Default crumb node factory. This factory is used when no custom factory is specified by the user. */ private final Callback, Button> defaultCrumbNodeFactory = new Callback, Button>(){ @Override public Button call(TreeItem crumb) { return new BreadCrumbButton(crumb.getValue() != null ? crumb.getValue().toString() : ""); //$NON-NLS-1$ } }; /*************************************************************************** * * * Constructors * * * **************************************************************************/ /** * Creates an empty bread crumb bar */ public BreadCrumbBar(){ this(null); } /** * Creates a bread crumb bar with the given TreeItem as the currently * selected crumb. */ public BreadCrumbBar(TreeItem selectedCrumb) { getStyleClass().add(DEFAULT_STYLE_CLASS); setSelectedCrumb(selectedCrumb); setCrumbFactory(defaultCrumbNodeFactory); } /*************************************************************************** * * * Properties * * * **************************************************************************/ // --- selectedCrumb /** * Represents the bottom-most path node (the node on the most-right side in * terms of the bread crumb bar). The full path is then being constructed * using getParent() of the tree-items. * *

* Consider the following hierarchy: * [Root] > [Folder] > [SubFolder] > [myfile.txt] * * To show the above bread crumb bar, you have to set the [myfile.txt] tree-node as selected crumb. */ public final ObjectProperty> selectedCrumbProperty() { return selectedCrumb; } private final ObjectProperty> selectedCrumb = new SimpleObjectProperty<>(this, "selectedCrumb"); //$NON-NLS-1$ /** * Get the current target path */ public final TreeItem getSelectedCrumb() { return selectedCrumb.get(); } /** * Select one node in the BreadCrumbBar for being the bottom-most path node. * @param selectedCrumb */ public final void setSelectedCrumb(TreeItem selectedCrumb){ this.selectedCrumb.set(selectedCrumb); } // --- autoNavigation /** * Enable or disable auto navigation (default is enabled). * If auto navigation is enabled, it will automatically navigate to the crumb which was clicked by the user. * @return a {@link BooleanProperty} */ public final BooleanProperty autoNavigationEnabledProperty() { return autoNavigation; } private final BooleanProperty autoNavigation = new SimpleBooleanProperty(this, "autoNavigationEnabled", true); //$NON-NLS-1$ /** * Return whether auto-navigation is enabled. * @return whether auto-navigation is enabled. */ public final boolean isAutoNavigationEnabled() { return autoNavigation.get(); } /** * Enable or disable auto navigation (default is enabled). * If auto navigation is enabled, it will automatically navigate to the crumb which was clicked by the user. * @param enabled */ public final void setAutoNavigationEnabled(boolean enabled) { autoNavigation.set(enabled); } // --- crumbFactory /** * Return an ObjectProperty of the CrumbFactory. * @return an ObjectProperty of the CrumbFactory. */ public final ObjectProperty, Button>> crumbFactoryProperty() { return crumbFactory; } private final ObjectProperty, Button>> crumbFactory = new SimpleObjectProperty<>(this, "crumbFactory"); //$NON-NLS-1$ /** * Sets the crumb factory to create (custom) {@link BreadCrumbButton} instances. * null is not allowed and will result in a fall back to the default factory. * @param value */ public final void setCrumbFactory(Callback, Button> value) { if(value == null){ value = defaultCrumbNodeFactory; } crumbFactoryProperty().set(value); } /** * Returns the cell factory that will be used to create {@link BreadCrumbButton} * instances */ public final Callback, Button> getCrumbFactory() { return crumbFactory.get(); } // --- onCrumbAction /** * @return an ObjectProperty representing the crumbAction EventHandler being used. */ public final ObjectProperty>> onCrumbActionProperty() { return onCrumbAction; } /** * Set a new EventHandler for when a user selects a crumb. * @param value */ public final void setOnCrumbAction(EventHandler> value) { onCrumbActionProperty().set(value); } /** * Return the EventHandler currently used when a user selects a crumb. * @return the EventHandler currently used when a user selects a crumb. */ public final EventHandler> getOnCrumbAction() { return onCrumbActionProperty().get(); } private ObjectProperty>> onCrumbAction = new ObjectPropertyBase>>() { @SuppressWarnings({ "rawtypes", "unchecked" }) @Override protected void invalidated() { setEventHandler(BreadCrumbActionEvent.CRUMB_ACTION, (EventHandler)(Object)get()); } @Override public Object getBean() { return BreadCrumbBar.this; } @Override public String getName() { return "onCrumbAction"; //$NON-NLS-1$ } }; /*************************************************************************** * * * Stylesheet Handling * * * **************************************************************************/ private static final String DEFAULT_STYLE_CLASS = "bread-crumb-bar"; //$NON-NLS-1$ /** {@inheritDoc} */ @Override protected Skin createDefaultSkin() { return new BreadCrumbBarSkin<>(this); } /** {@inheritDoc} */ @Override public String getUserAgentStylesheet() { return getUserAgentStylesheet(BreadCrumbBar.class, "breadcrumbbar.css"); } /** * Represents a BreadCrumb Button * *

     * ----------
     *  \         \
     *  /         /
     * ----------
     * 
* * */ public static class BreadCrumbButton extends Button { private final ObjectProperty first = new SimpleObjectProperty<>(this, STYLE_CLASS_FIRST); //$NON-NLS-1$ private final double arrowWidth = 5; private final double arrowHeight = 20; /** * Create a BreadCrumbButton * * @param text Buttons text */ public BreadCrumbButton(String text){ this(text, null); } /** * Create a BreadCrumbButton * @param text Buttons text * @param gfx Gfx of the Button */ public BreadCrumbButton(String text, Node gfx){ super(text, gfx); first.set(false); getStyleClass().addListener(new InvalidationListener() { @Override public void invalidated(Observable arg0) { updateShape(); } }); updateShape(); } private void updateShape(){ this.setShape(createButtonShape()); } /** * Gets the crumb arrow with * @return */ public double getArrowWidth(){ return arrowWidth; } /** * Create an arrow path * * Based upon Uwe / Andy Till code snippet found here: * @see http://ustesis.wordpress.com/2013/11/04/implementing-breadcrumbs-in-javafx/ * @return */ private Path createButtonShape(){ // build the following shape (or home without left arrow) // -------- // \ \ // / / // -------- Path path = new Path(); // begin in the upper left corner MoveTo e1 = new MoveTo(0, 0); path.getElements().add(e1); // draw a horizontal line that defines the width of the shape HLineTo e2 = new HLineTo(); // bind the width of the shape to the width of the button e2.xProperty().bind(this.widthProperty().subtract(arrowWidth)); path.getElements().add(e2); // draw upper part of right arrow LineTo e3 = new LineTo(); // the x endpoint of this line depends on the x property of line e2 e3.xProperty().bind(e2.xProperty().add(arrowWidth)); e3.setY(arrowHeight / 2.0); path.getElements().add(e3); // draw lower part of right arrow LineTo e4 = new LineTo(); // the x endpoint of this line depends on the x property of line e2 e4.xProperty().bind(e2.xProperty()); e4.setY(arrowHeight); path.getElements().add(e4); // draw lower horizontal line HLineTo e5 = new HLineTo(0); path.getElements().add(e5); if(! getStyleClass().contains(STYLE_CLASS_FIRST)){ // draw lower part of left arrow // we simply can omit it for the first Button LineTo e6 = new LineTo(arrowWidth, arrowHeight / 2.0); path.getElements().add(e6); }else{ // draw an arc for the first bread crumb ArcTo arcTo = new ArcTo(); arcTo.setSweepFlag(true); arcTo.setX(0); arcTo.setY(0); arcTo.setRadiusX(15.0f); arcTo.setRadiusY(15.0f); path.getElements().add(arcTo); } // close path ClosePath e7 = new ClosePath(); path.getElements().add(e7); // this is a dummy color to fill the shape, it won't be visible path.setFill(Color.BLACK); return path; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy