org.controlsfx.control.spreadsheet.SpreadsheetCellBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of controlsfx Show documentation
Show all versions of controlsfx Show documentation
High quality UI controls and other tools to complement the core JavaFX distribution
/**
* Copyright (c) 2013, 2016, 2018 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.spreadsheet;
import com.sun.javafx.event.EventHandlerManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;
import javafx.event.Event;
import javafx.event.EventDispatchChain;
import javafx.event.EventHandler;
import javafx.event.EventTarget;
import javafx.event.EventType;
import javafx.scene.Node;
import javafx.scene.control.MenuItem;
import javafx.scene.image.ImageView;
import javafx.stage.Popup;
/**
* The SpreadsheetCells serve as model for the {@link SpreadsheetView}.
* You will provide them when constructing a {@link Grid}.
*
*
* SpreadsheetCell Types
Each SpreadsheetCell has its own
* {@link SpreadsheetCellType} which has its own {@link SpreadsheetCellEditor}
* in order to control very closely the possible modifications.
*
*
* Different {@link SpreadsheetCellType SpreadsheetCellTypes} are available
* depending on the data you want to represent in your {@link SpreadsheetView}.
* You can use the different static method provided in
* {@link SpreadsheetCellType} in order to create the specialized
* SpreadsheetCell that suits your need.
*
*
*
*
*
* If you want to create a SpreadsheetCell of your own, you simply have to
* use one of the provided constructor. Usually you will let your {@link SpreadsheetCellType}
* create the cells. For example
* {@link SpreadsheetCellType.StringType#createCell(int, int, int, int, java.lang.String) }.
* You will also have to provide a custom {@link SpreadsheetCellEditor}.
*
*
Configuration
* You will have to indicate the coordinates of the cell together with the
* {@link #setRowSpan(int) row} and {@link #setColumnSpan(int) column} span. You
* can specify if you want the cell to be editable or not using
* {@link #setEditable(boolean)}. Be advised that a cell with a rowSpan means
* that the cell will replace all the cells situated in the rowSpan range. Same
* with the column span.
*
* So the best way to handle spanning is to fill your grid
* with unique cells, and then call at the end {@link GridBase#spanColumn(int, int, int)}
* or {@link GridBase#spanRow(int, int, int)}. These methods will handle the span
* for you.
*
*
*
* Format
* Your cell can have its very own format. If you want to display some dates
* with different format, you just have to create a unique
* {@link SpreadsheetCellType} and then specify for each cell their format with
* {@link #setFormat(String)}. You will then have the guaranty that all your
* cells will have a LocalDate as a value, but the value will be displayed
* differently for each cell. This will also guaranty that copy/paste and other
* operation will be compatible since every cell will share the same
* {@link SpreadsheetCellType}.
* Here an example :
*
*
*
* SpreadsheetCell cell = SpreadsheetCellType.DATE.createCell(row, column, rowSpan, colSpan,
* LocalDate.now().plusDays((int) (Math.random() * 10))); // Random value
* // given here
* final double random = Math.random();
* if (random < 0.25) {
* cell.setFormat("EEEE d");
* } else if (random < 0.5) {
* cell.setFormat("dd/MM :YY");
* } else {
* cell.setFormat("dd/MM/YYYY");
* }
*
*
*
*
* Popup
* Each cell can display a {@link Popup} when clicked. This is useful when some
* non editable cell wants to display several actions to take on the grid. This
* feature is completely different from the {@link Filter}. Filters are shown on
* one particular row whereas popup can be added to every cell.
*
*
* Graphic
* Each cell can have a graphic to display next to the text in the cells. Just
* use the {@link #setGraphic(Node)} in order to specify the graphic you want.
* If you specify an {@link ImageView}, the SpreadsheetView will try to resize it in
* order to fit the space available in the cell.
*
* For example :
*
*
* cell.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("icons/exclamation.png"))));
*
*
*
* In addition to that, you can also specify another graphic property to your
* cell with {@link #activateCorner(org.controlsfx.control.spreadsheet.SpreadsheetCell.CornerPosition) }.
* This allow you to activate or deactivate some graphics on the cell in every
* corner. Right now it's a little red triangle but you can modify this in your CSS by
* using the "cell-corner" style class.
*
*
* .cell-corner.top-left{
* -fx-background-color: red;
* -fx-shape : "M 0 0 L 1 0 L 0 1 z";
* }
*
*
*
*
*
*
* You can also customize the tooltip of your SpreadsheetCell by specifying one
* with {@link #setTooltip(java.lang.String) }.
*
* Style with CSS
* You can style your cell by specifying some styleClass with
* {@link #getStyleClass()}. You just have to create and custom that class in
* your CSS stylesheet associated with your {@link SpreadsheetView}. Also note
* that all {@link SpreadsheetCell} have a "spreadsheet-cell" styleClass
* added by default. Here is a example :
*
*
* cell.getStyleClass().add("row_header");
*
*
* And in the CSS:
*
*
* .spreadsheet-cell.row_header{
* -fx-background-color: #b4d4ad ;
* -fx-background-insets: 0, 0 1 1 0;
* -fx-alignment: center;
* }
*
*
* Examples
* Here is an example that uses all the pre-built {@link SpreadsheetCellType}
* types. The generation is random here so you will want to replace the logic to
* suit your needs.
*
*
* private SpreadsheetCell<?> generateCell(int row, int column, int rowSpan, int colSpan) {
* List<String> stringListTextCell = Arrays.asList("Shanghai","Paris","New York City","Bangkok","Singapore","Johannesburg","Berlin","Wellington","London","Montreal");
* final double random = Math.random();
* if (random < 0.10) {
* List<String> stringList = Arrays.asList("China","France","New Zealand","United States","Germany","Canada");
* cell = SpreadsheetCellType.LIST(stringList).createCell(row, column, rowSpan, colSpan, stringList.get((int) (Math.random() * 6)));
* } else if (random >= 0.10 && random < 0.25) {
* cell = SpreadsheetCellType.STRING.createCell(row, column, rowSpan, colSpan,stringListTextCell.get((int)(Math.random()*10)));
* } else if (random >= 0.25 && random < 0.75) {
* cell = SpreadsheetCellType.DOUBLE.createCell(row, column, rowSpan, colSpan,(double)Math.round((Math.random()*100)*100)/100);
* } else {
* cell = SpreadsheetCellType.DATE.createCell(row, column, rowSpan, colSpan, LocalDate.now().plusDays((int)(Math.random()*10)));
* }
* return cell;
* }
*
*
* @see SpreadsheetView
* @see SpreadsheetCellEditor
* @see SpreadsheetCellType
*/
public class SpreadsheetCellBase implements SpreadsheetCell, EventTarget{
/***************************************************************************
*
* Private Fields
*
**************************************************************************/
//The Bit position for the editable Property.
private static final int EDITABLE_BIT_POSITION = 4;
private static final int WRAP_BIT_POSITION = 5;
private static final int POPUP_BIT_POSITION = 6;
private static final int IS_BROWSER_POSITION = 7;
private final SpreadsheetCellType type;
private final int row;
private final int column;
private int rowSpan;
private int columnSpan;
private final StringProperty format;
private final StringProperty text;
private final StringProperty styleProperty;
private final ObjectProperty graphic;
private String tooltip;
/**
* This variable handles all boolean values of this SpreadsheetCell inside
* its bits. Instead of using regular boolean, we use that int so that we
* can reduce memory usage to the bare minimum.
*/
private int propertyContainer = 0;
private final EventHandlerManager eventHandlerManager = new EventHandlerManager(this);
private ObservableSet styleClass;
private List