
org.controlsfx.control.spreadsheet.SpreadsheetCellBase Maven / Gradle / Ivy
/**
* Copyright (c) 2013, 2023 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
© 2015 - 2025 Weber Informatics LLC | Privacy Policy