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

io.github.palexdev.virtualizedfx.cells.VFXCellBase Maven / Gradle / Ivy

There is a newer version: 21.6.4
Show newest version
/*
 * Copyright (C) 2024 Parisi Alessandro - [email protected]
 * This file is part of VirtualizedFX (https://github.com/palexdev/VirtualizedFX)
 *
 * VirtualizedFX is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 3 of the License,
 * or (at your option) any later version.
 *
 * VirtualizedFX 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with VirtualizedFX. If not, see .
 */

package io.github.palexdev.virtualizedfx.cells;

import io.github.palexdev.mfxcore.base.properties.styleable.StyleableObjectProperty;
import io.github.palexdev.mfxcore.controls.Control;
import io.github.palexdev.mfxcore.utils.fx.StyleUtils;
import io.github.palexdev.virtualizedfx.base.VFXStyleable;
import io.github.palexdev.virtualizedfx.cells.base.VFXCell;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.css.CssMetaData;
import javafx.css.Styleable;
import javafx.css.StyleablePropertyFactory;
import javafx.geometry.Pos;
import javafx.scene.Node;

import java.util.List;
import java.util.function.Supplier;

/**
 * The basic and typical implementation of a cell in JavaFX is a cell with just two properties: one to keep track
 * of the cell's index and the other to keep track of the displayed item.
 * 

* This abstract class is a good starting point to implement concrete, usable cells. *

* Unusually, this enforces the structuring of cells as specified by the {@code MVC} pattern. In fact, this extends * {@link Control}, expects behaviors of type {@link CellBaseBehavior} and doesn't come with a default skin. *

* The idea is to make the skin implementation responsible for how data is represented (a String, a Node, processing, etc.). * A downside of such approach is that for some reason, users are a bit reluctant in making or customizing skins, however, * I can assure you it's no big deal at all. Also, never forget that {@code VirtualizedFX} containers do not * enforce the usage of {@link VFXCellBase} or any of its implementations, if you are more comfortable using a simpler * cell system you are free do it. *

* The default style class is 'cell-base'. *

* A word on performance * As also stated in the javadocs of {@link #updateIndex(int)} and {@link #updateItem(Object)}, to simplify the internal * management of cells, there is no 100% guarantee that updates are called with a different index/item from what the cell * currently has. For this reason, here's how you should implement the 'rendering' operations:

* You probably want to execute some operations when the index or item change by listening to the respective properties, * {@link #indexProperty()} and {@link #itemProperty()}. This means that your operations will run only and only if the * property fires an invalidation/change event. In this base class the {@link #updateIndex(int)} and {@link #updateItem(Object)} * methods are implemented naively, because we work on generic items, we don't know the model, which means that they * update the respective properties without any check. *

- For the {@link #indexProperty()} it's tricky: the JVM caches Integers * between -128 and 127, which means that the '==' operator only works in that range; for larger datasets, you may want to * override the {@link #updateIndex(int)} method to actually check for equality. *

For the {@link #itemProperty()} it's the same concept. If you know the model, you may want to perform some equality * check in the {@link #updateItem(Object)} method to avoid useless updates. For example, if in your dataset there are two * {@code Person} objects with the same attributes but different references you may want to update the property (so that the * reference is correct) but not perform any operation that strictly depends on the attributes (if a label displays the attributes, * there's no need to re-compute the text) * * @see #alignmentProperty() * @see VFXCell */ public abstract class VFXCellBase extends Control> implements VFXCell, VFXStyleable { //================================================================================ // Properties //================================================================================ private final IntegerProperty index = new SimpleIntegerProperty(-1); private final ObjectProperty item = new SimpleObjectProperty<>(); private final ObjectProperty graphic = new SimpleObjectProperty<>(); //================================================================================ // Constructors //================================================================================ public VFXCellBase(T item) { initialize(); updateItem(item); } //================================================================================ // Methods //================================================================================ private void initialize() { getStyleClass().setAll(defaultStyleClasses()); setDefaultBehaviorProvider(); } //================================================================================ // Overridden Methods //================================================================================ @Override public List defaultStyleClasses() { return List.of("cell-base"); } @Override public Node toNode() { return this; } /** * {@inheritDoc} *

* Updates the {@link #itemProperty()}. */ @Override public void updateItem(T item) { setItem(item); } /** * {@inheritDoc} *

* Updates the {@link #indexProperty()}. */ @Override public void updateIndex(int index) { setIndex(index); } @Override public Supplier> defaultBehaviorProvider() { return () -> new CellBaseBehavior<>(this); } //================================================================================ // Styleable Properties //================================================================================ private final StyleableObjectProperty alignment = new StyleableObjectProperty<>( StyleableProperties.ALIGNMENT, this, "alignment", Pos.CENTER_LEFT ) { @Override protected void invalidated() { requestLayout(); } }; public Pos getAlignment() { return alignment.get(); } /** * Specifies the alignment of the displayed data. How this is used depends on the skin implementation. *

* This is settable via CSS with the "-fx-alignment" property. */ public StyleableObjectProperty alignmentProperty() { return alignment; } public void setAlignment(Pos alignment) { this.alignment.set(alignment); } //================================================================================ // CssMetaData //================================================================================ private static class StyleableProperties { private static final StyleablePropertyFactory> FACTORY = new StyleablePropertyFactory<>(Control.getClassCssMetaData()); private static final List> cssMetaDataList; private static final CssMetaData, Pos> ALIGNMENT = FACTORY.createEnumCssMetaData( Pos.class, "-fx-alignment", VFXCellBase::alignmentProperty, Pos.CENTER_LEFT ); static { cssMetaDataList = StyleUtils.cssMetaDataList( Control.getClassCssMetaData(), ALIGNMENT ); } } public static List> getClassCssMetaData() { return StyleableProperties.cssMetaDataList; } @Override protected List> getControlCssMetaData() { return getClassCssMetaData(); } //================================================================================ // Getters/Setters //================================================================================ public int getIndex() { return index.get(); } /** * Specifies the cell's index. */ public IntegerProperty indexProperty() { return index; } public void setIndex(int index) { this.index.set(index); } public T getItem() { return item.get(); } /** * Specifies the cell's item. */ public ObjectProperty itemProperty() { return item; } public void setItem(T item) { this.item.set(item); } public Node getGraphic() { return graphic.get(); } /** * Allows adding a {@code Node} to the cell. To be precise, how this property is used depends on the skin implementation. */ public ObjectProperty graphicProperty() { return graphic; } public void setGraphic(Node graphic) { this.graphic.set(graphic); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy