/*
 * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.javafx.charts;

import java.util.List;
import java.util.stream.Collectors;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.BooleanPropertyBase;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ObjectPropertyBase;
import javafx.beans.property.StringProperty;
import javafx.beans.property.StringPropertyBase;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.layout.Region;
import javafx.scene.layout.TilePane;

A chart legend that displays a list of items with symbols in a box
/** * A chart legend that displays a list of items with symbols in a box */
public class Legend extends TilePane { private static final int GAP = 5; // -------------- PRIVATE FIELDS ------------------------------------------ private ListChangeListener<LegendItem> itemsListener = c -> { List<Label> labels = getItems().stream() .map(i -> i.label) .collect(Collectors.toList()); getChildren().setAll(labels); if(isVisible()) requestLayout(); }; // -------------- PUBLIC PROPERTIES ----------------------------------------
The legend items should be laid out vertically in columns rather than horizontally in rows
/** The legend items should be laid out vertically in columns rather than * horizontally in rows */
private BooleanProperty vertical = new BooleanPropertyBase(false) { @Override protected void invalidated() { setOrientation(get() ? Orientation.VERTICAL : Orientation.HORIZONTAL); } @Override public Object getBean() { return Legend.this; } @Override public String getName() { return "vertical"; } }; public final boolean isVertical() { return vertical.get(); } public final void setVertical(boolean value) { vertical.set(value); } public final BooleanProperty verticalProperty() { return vertical; }
The legend items to display in this legend
/** The legend items to display in this legend */
private ObjectProperty<ObservableList<LegendItem>> items = new ObjectPropertyBase<ObservableList<LegendItem>>() { ObservableList<LegendItem> oldItems = null; @Override protected void invalidated() { if (oldItems != null) oldItems.removeListener(itemsListener); getChildren().clear(); ObservableList<LegendItem> newItems = get(); if (newItems != null) { newItems.addListener(itemsListener); List<Label> labels = newItems.stream() .map(i -> i.label) .collect(Collectors.toList()); getChildren().addAll(labels); } oldItems = newItems; requestLayout(); } @Override public Object getBean() { return Legend.this; } @Override public String getName() { return "items"; } }; public final void setItems(ObservableList<LegendItem> value) {itemsProperty().set(value);} public final ObservableList<LegendItem> getItems() { return items.get();} public final ObjectProperty<ObservableList<LegendItem>> itemsProperty() {return items;} // -------------- PROTECTED PROPERTIES ------------------------------------ // -------------- CONSTRUCTORS ---------------------------------------------- public Legend() { super(GAP, GAP); setTileAlignment(Pos.CENTER_LEFT); setItems(FXCollections.<LegendItem>observableArrayList()); getStyleClass().setAll("chart-legend"); } // -------------- METHODS --------------------------------------------------- @Override protected double computePrefWidth(double forHeight) { // Legend prefWidth is zero if there are no legend items return (getItems().size() > 0) ? super.computePrefWidth(forHeight) : 0; } @Override protected double computePrefHeight(double forWidth) { // Legend prefHeight is zero if there are no legend items return (getItems().size() > 0) ? super.computePrefHeight(forWidth) : 0; }
A item to be displayed on a Legend
/** A item to be displayed on a Legend */
public static class LegendItem {
Label used to represent the legend item
/** Label used to represent the legend item */
private Label label = new Label();
The item text
/** The item text */
private StringProperty text = new StringPropertyBase() { @Override protected void invalidated() { label.setText(get()); } @Override public Object getBean() { return LegendItem.this; } @Override public String getName() { return "text"; } }; public final String getText() { return text.getValue(); } public final void setText(String value) { text.setValue(value); } public final StringProperty textProperty() { return text; }
The symbol to use next to the item text, set to null for no symbol. The default is a simple square of symbolFill
/** The symbol to use next to the item text, set to null for no symbol. The default is a simple square of symbolFill */
//new Rectangle(8,8,null) private ObjectProperty<Node> symbol = new ObjectPropertyBase<Node>(new Region()) { @Override protected void invalidated() { Node symbol = get(); if(symbol != null) symbol.getStyleClass().setAll("chart-legend-item-symbol"); label.setGraphic(symbol); } @Override public Object getBean() { return LegendItem.this; } @Override public String getName() { return "symbol"; } }; public final Node getSymbol() { return symbol.getValue(); } public final void setSymbol(Node value) { symbol.setValue(value); } public final ObjectProperty<Node> symbolProperty() { return symbol; } public LegendItem(String text) { setText(text); label.getStyleClass().add("chart-legend-item"); label.setAlignment(Pos.CENTER_LEFT); label.setContentDisplay(ContentDisplay.LEFT); label.setGraphic(getSymbol()); getSymbol().getStyleClass().setAll("chart-legend-item-symbol"); } public LegendItem(String text, Node symbol) { this(text); setSymbol(symbol); } } }