Explorar o código

Added missing documentation and updated for changed controls
Move documentation from declaration to public methods(part 1)

Signed-off-by: PAlex404 <alessandro.parisi406@gmail.com>

PAlex404 %!s(int64=4) %!d(string=hai) anos
pai
achega
1ecf1bac75
Modificáronse 31 ficheiros con 1012 adicións e 247 borrados
  1. 21 0
      materialfx/src/main/java/io/github/palexdev/materialfx/beans/MFXContextMenuItem.java
  2. 17 3
      materialfx/src/main/java/io/github/palexdev/materialfx/beans/MFXLoaderBean.java
  3. 26 35
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXButton.java
  4. 101 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXContextMenu.java
  5. 4 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXFilterComboBox.java
  6. 23 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXFlowlessCheckListView.java
  7. 23 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXFlowlessListView.java
  8. 81 29
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXHLoader.java
  9. 27 24
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXLabel.java
  10. 6 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableView.java
  11. 16 16
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXToggleNode.java
  12. 74 18
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXVLoader.java
  13. 70 43
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractFlowlessListView.java
  14. 99 24
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXFlowlessListCell.java
  15. 42 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/IListView.java
  16. 66 2
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXFlowlessCheckListCell.java
  17. 30 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXFlowlessListCell.java
  18. 8 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXTableColumnCell.java
  19. 31 0
      materialfx/src/main/java/io/github/palexdev/materialfx/selection/ComboSelectionModelMock.java
  20. 39 0
      materialfx/src/main/java/io/github/palexdev/materialfx/selection/ListCheckModel.java
  21. 78 13
      materialfx/src/main/java/io/github/palexdev/materialfx/selection/ListSelectionModel.java
  22. 4 4
      materialfx/src/main/java/io/github/palexdev/materialfx/selection/TableSelectionModel.java
  23. 3 0
      materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/IListCheckModel.java
  24. 3 0
      materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/IListSelectionModel.java
  25. 3 0
      materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXButtonSkin.java
  26. 13 8
      materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXComboBoxSkin.java
  27. 0 1
      materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXDateCellSkin.java
  28. 7 1
      materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXFilterComboBoxSkin.java
  29. 26 0
      materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXFlowlessListViewSkin.java
  30. 7 0
      materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableColumnCellSkin.java
  31. 64 26
      materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableViewSkin.java

+ 21 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/beans/MFXContextMenuItem.java

@@ -23,26 +23,44 @@ import javafx.scene.Node;
 import javafx.scene.control.Label;
 import javafx.scene.input.MouseEvent;
 
+/**
+ * Bean used in {@link io.github.palexdev.materialfx.controls.MFXContextMenu.Builder}.
+ * Contains the node reference to add to the context menu and the action automatically added to the node
+ * when is pressed.
+ */
 public class MFXContextMenuItem {
     private final Node node;
     private EventHandler<MouseEvent> action;
 
+    /**
+     * Creates a nre context menu item with the specified node and null action.
+     */
     public MFXContextMenuItem(Node node) {
         this.node = node;
     }
 
+    /**
+     * Created a new menu item with the specified node and action(added automatically to the node).
+     */
     public MFXContextMenuItem(Node node, EventHandler<MouseEvent> action) {
         this.node = node;
         this.action = action;
         node.addEventHandler(MouseEvent.MOUSE_PRESSED, action);
     }
 
+    /**
+     * Creates a new menu item with a Label that has the specified text set.
+     */
     public MFXContextMenuItem(String text) {
         Label label = new Label(text);
         label.setMaxWidth(Double.MAX_VALUE);
         node = new Label(text);
     }
 
+    /**
+     * Creates a new menu item with a Label that has the specified text set and the
+     * specified action on mouse pressed.
+     */
     public MFXContextMenuItem(String text, EventHandler<MouseEvent> action) {
         Label label = new Label(text);
         label.setMaxWidth(Double.MAX_VALUE);
@@ -58,6 +76,9 @@ public class MFXContextMenuItem {
         return action;
     }
 
+    /**
+     * Sets or replace the node action on mouse pressed.
+     */
     public void setAction(EventHandler<MouseEvent> action) {
         if (this.action != null) {
             node.removeEventHandler(MouseEvent.MOUSE_PRESSED, this.action);

+ 17 - 3
materialfx/src/main/java/io/github/palexdev/materialfx/beans/MFXLoaderBean.java

@@ -25,11 +25,14 @@ import javafx.util.Callback;
 import java.net.URL;
 
 /**
- * Support bean for {@code MFXHLoader} and {@code MFXVLoader}
+ * Support bean for {@code MFXHLoader} and {@code MFXVLoader}.
+ * <p>
  * Basically a wrapper for a {@code Node} which is the root of an fxml file,
- * the controller factory of the fxml file, the toggle button associated with the item
+ * the controller factory of the fxml file (optional), the toggle button associated with the item
  * which is responsible for the views switching, the {@code URL} of the fxml file,
- * and an index which represents the toggle button position in the children list of the loader.
+ * and a flag which specified if this is the view to be shown when loading is finished.
+ * <p></p>
+ * It is <b>highly recommended</b> to use the {@link Builder} class to create a bean.
  */
 public class MFXLoaderBean {
     //================================================================================
@@ -82,6 +85,9 @@ public class MFXLoaderBean {
         return fxmlURL;
     }
 
+    /**
+     * Utils class that facilitates the creation of {@code MFXLoaderBean}s with fluent api.
+     */
     public static class Builder {
         private final URL fxmlURL;
         private final ToggleButton button;
@@ -93,6 +99,11 @@ public class MFXLoaderBean {
             this.button = button;
         }
 
+        /**
+         * Convenience static method to avoid using the new keyword.
+         *
+         * @return a new {@code Builder} instance with the specified parameters
+         */
         public static Builder build(ToggleButton button, URL fxmlURL) {
             return new Builder(button, fxmlURL);
         }
@@ -107,6 +118,9 @@ public class MFXLoaderBean {
             return this;
         }
 
+        /**
+         * @return the new {@code MFXLoaderBean} instance
+         */
         public MFXLoaderBean get() {
             return new MFXLoaderBean(button, fxmlURL, defaultRoot, controllerFactory);
         }

+ 26 - 35
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXButton.java

@@ -95,37 +95,18 @@ public class MFXButton extends Button {
     //================================================================================
     // Ripple properties
     //================================================================================
-
-    /**
-     * Specifies the ripples color of this control.
-     *
-     * @see Color
-     */
     private final ObjectProperty<Paint> rippleColor = new SimpleObjectProperty<>();
-
-    /**
-     * Specifies the ripples radius of this control.
-     */
     private final DoubleProperty rippleRadius = new SimpleDoubleProperty();
-
-    /**
-     * Specifies the ripples in animation duration of this control.
-     *
-     * @see Duration
-     */
     private final ObjectProperty<Duration> rippleInDuration = new SimpleObjectProperty<>();
-
-    /**
-     * Specifies the ripples out animation duration of this control.
-     *
-     * @see Duration
-     */
     private final ObjectProperty<Duration> rippleOutDuration = new SimpleObjectProperty<>();
 
     public final Paint getRippleColor() {
         return rippleColor.get();
     }
 
+    /**
+     * Specifies the ripples color of this control.
+     */
     public final ObjectProperty<Paint> rippleColorProperty() {
         return this.rippleColor;
     }
@@ -138,6 +119,9 @@ public class MFXButton extends Button {
         return rippleRadius.get();
     }
 
+    /**
+     * Specifies the ripples radius of this control.
+     */
     public DoubleProperty rippleRadiusProperty() {
         return rippleRadius;
     }
@@ -150,6 +134,9 @@ public class MFXButton extends Button {
         return rippleInDuration.get();
     }
 
+    /**
+     * Specifies the ripples in animation duration of this control.
+     */
     public ObjectProperty<Duration> rippleInDurationProperty() {
         return rippleInDuration;
     }
@@ -162,6 +149,9 @@ public class MFXButton extends Button {
         return rippleOutDuration.get();
     }
 
+    /**
+     * Specifies the ripples out animation duration of this control.
+     */
     public ObjectProperty<Duration> rippleOutDurationProperty() {
         return rippleOutDuration;
     }
@@ -173,12 +163,6 @@ public class MFXButton extends Button {
     //================================================================================
     // Styleable Properties
     //================================================================================
-
-    /**
-     * Specifies how intense is the {@code DropShadow} effect applied to this control.
-     * <p>
-     * The {@code DropShadow} effect is used to make the control appear {@code RAISED}.
-     */
     private final StyleableObjectProperty<DepthLevel> depthLevel = new SimpleStyleableObjectProperty<>(
             StyleableProperties.DEPTH_LEVEL,
             this,
@@ -186,13 +170,6 @@ public class MFXButton extends Button {
             DepthLevel.LEVEL2
     );
 
-    /**
-     * Specifies the appearance of this control. According to material design there are two types of buttons:
-     * <p>
-     * - {@code FLAT}
-     * <p>
-     * - {@code RAISED}
-     */
     private final StyleableObjectProperty<ButtonType> buttonType = new SimpleStyleableObjectProperty<>(
             StyleableProperties.BUTTON_TYPE,
             this,
@@ -204,6 +181,13 @@ public class MFXButton extends Button {
         return depthLevel.get();
     }
 
+    /**
+     * Specifies how intense is the {@code DropShadow} effect applied to this control.
+     * <p>
+     * The {@code DropShadow} effect is used to make the control appear {@code RAISED}.
+     *
+     * @see io.github.palexdev.materialfx.effects.MFXDepthManager
+     */
     public StyleableObjectProperty<DepthLevel> depthLevelProperty() {
         return depthLevel;
     }
@@ -216,6 +200,13 @@ public class MFXButton extends Button {
         return buttonType.get();
     }
 
+    /**
+     * Specifies the appearance of this control. According to material design there are two types of buttons:
+     * <p>
+     * - {@code FLAT}
+     * <p>
+     * - {@code RAISED}
+     */
     public StyleableObjectProperty<ButtonType> buttonTypeProperty() {
         return buttonType;
     }

+ 101 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXContextMenu.java

@@ -42,7 +42,18 @@ import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 
+/**
+ * This control is a context menu built from scratch which extends {@code VBox}.
+ * <p>
+ * It easily styleable and allows to add separators between the context menu nodes.
+ * The context menu is shown in a {@code PopupControl}.
+ * <p></p>
+ * It is <b>highly recommended</b> to use the {@link Builder} class to create a context menu.
+ */
 public class MFXContextMenu extends VBox {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final String STYLE_CLASS = "mfx-context-menu";
     private final String STYLESHEET = MFXResourcesLoader.load("css/mfx-contextmenu.css");
 
@@ -56,6 +67,9 @@ public class MFXContextMenu extends VBox {
     private final EventHandler<MouseEvent> openHandler;
     private final EventHandler<KeyEvent> keyHandler;
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXContextMenu() {
         this(0);
     }
@@ -102,6 +116,13 @@ public class MFXContextMenu extends VBox {
         };
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
+
+    /**
+     * Installs the context menu to the given node.
+     */
     public void install(Node node) {
         node.sceneProperty().addListener((observable, oldValue, newValue) -> {
             if (newValue != null) {
@@ -122,6 +143,10 @@ public class MFXContextMenu extends VBox {
         installBehavior();
     }
 
+    /**
+     * Installs the context menu behavior to the given node.
+     * Used in {@link #install(Node)}.
+     */
     private void installBehavior() {
         if (nodeReference != null) {
             Node node = nodeReference.get();
@@ -133,6 +158,10 @@ public class MFXContextMenu extends VBox {
         }
     }
 
+    /**
+     * If the node reference is not null and {@link #install(Node)} is called again, this method is called to
+     * remove the context menu from the previous node.
+     */
     private void dispose() {
         if (nodeReference != null) {
             Node node = nodeReference.get();
@@ -168,10 +197,16 @@ public class MFXContextMenu extends VBox {
         });
     }
 
+    /**
+     * Shows the context menu' popup.
+     */
     public void show(Node ownerNode, double anchorX, double anchorY) {
         popupControl.show(ownerNode, anchorX, anchorY);
     }
 
+    /**
+     * Hides the context menu' popup.
+     */
     public void hide() {
         popupControl.hide();
     }
@@ -192,28 +227,87 @@ public class MFXContextMenu extends VBox {
         popupControl.removeEventFilter(eventType, eventHandler);
     }
 
+    /**
+     * Utils class that facilitates the creation of context menus with fluent api.
+     * <p>
+     * Example from {@code MFXTableView Skin}:
+     * <p></p>
+     * <pre>
+     * {@code
+     * MFXContextMenuItem restoreWidthThis = new MFXContextMenuItem(
+     *      "Restore this column width",
+     *      event -> column.setMinWidth(column.getInitialWidth())
+     * );
+     *
+     * MFXContextMenuItem restoreWidthAll = new MFXContextMenuItem(
+     *      "Restore all columns width",
+     *      event -> columnsContainer.getChildren().stream()
+     *          .filter(node -> node instanceof MFXTableColumnCell)
+     *          .map(node -> (MFXTableColumnCell<T>) node)
+     *          .forEach(c -> c.setMinWidth(c.getInitialWidth()))
+     * );
+     *
+     * MFXContextMenuItem autoSizeThis = new MFXContextMenuItem(
+     *      "Autosize this column",
+     *      event -> autoSizeColumn(column)
+     *  );
+     *
+     * MFXContextMenuItem autoSizeAll = new MFXContextMenuItem(
+     *      "Autosize all columns",
+     *      event -> columnsContainer.getChildren().stream()
+     *          .filter(node -> node instanceof MFXTableColumnCell)
+     *          .map(node -> (MFXTableColumnCell<T>) node)
+     *          .forEach(this::autoSizeColumn)
+     * );
+     *
+     * new MFXContextMenu.Builder()
+     *      .addMenuItem(autoSizeAll)
+     *      .addMenuItem(autoSizeThis)
+     *      .addSeparator()
+     *      .addMenuItem(restoreWidthAll)
+     *      .addMenuItem(restoreWidthThis)
+     *      .install(column);
+     * }
+     * </pre>
+     */
     public static class Builder {
         private final MFXContextMenu contextMenu;
 
+        /**
+         * Creates a new Builder with a new MFXContextMenu instance.
+         */
         public Builder() {
             contextMenu = new MFXContextMenu();
         }
 
+        /**
+         * Creates a new Builder with a new MFXContextMenu instance that has
+         * the spacing set to the given value.
+         */
         public Builder(double spacing) {
             contextMenu = new MFXContextMenu(spacing);
         }
 
+        /**
+         * Adds a new node to the context menu with the specified action on mouse pressed.
+         */
         public Builder addMenuItem(Node node, EventHandler<MouseEvent> action) {
             node.addEventHandler(MouseEvent.MOUSE_PRESSED, action);
             contextMenu.getChildren().add(node);
             return this;
         }
 
+        /**
+         * Adds the specified {@link MFXContextMenuItem} to the context menu.
+         */
         public Builder addMenuItem(MFXContextMenuItem item) {
             contextMenu.getChildren().add(item.getNode());
             return this;
         }
 
+        /**
+         * Adds a separator to the context menu.
+         */
         public Builder addSeparator() {
             Line separator = new Line();
             separator.getStyleClass().add("separator");
@@ -223,10 +317,17 @@ public class MFXContextMenu extends VBox {
             return this;
         }
 
+        /**
+         * @return the built context menu instance
+         */
         public MFXContextMenu get() {
             return contextMenu;
         }
 
+        /**
+         * Installs the context menu to the given node and returns the
+         * context menu instance.
+         */
         public MFXContextMenu install(Node node) {
             contextMenu.install(node);
             return contextMenu;

+ 4 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXFilterComboBox.java

@@ -66,6 +66,10 @@ public class MFXFilterComboBox<T> extends MFXComboBox<T> {
         return editorFocused.get();
     }
 
+    /**
+     * Bound to the editor focus property. This allows to keep the focused style specified
+     * by css when the focus is acquired by the editor. The pseudo class to use in css is ":editor"
+     */
     public BooleanProperty editorFocusedProperty() {
         return editorFocused;
     }

+ 23 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXFlowlessCheckListView.java

@@ -28,10 +28,27 @@ import javafx.collections.FXCollections;
 import javafx.collections.ObservableList;
 import javafx.scene.control.Skin;
 
+/**
+ * Implementation of a check list view based on Flowless.
+ * <p>
+ * Extends {@link AbstractFlowlessListView}.
+ * <p></p>
+ * Default cell: {@link MFXFlowlessCheckListCell}.
+ * <p>
+ * Default selection model: {@link ListCheckModel}.
+ * <p>
+ * Default skin: {@link MFXFlowlessListViewSkin}.
+ */
 public class MFXFlowlessCheckListView<T> extends AbstractFlowlessListView<T, MFXFlowlessCheckListCell<T>, IListCheckModel<T>> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final String STYLE_CLASS = "mfx-check-list-view";
     private final String STYLESHEET = MFXResourcesLoader.load("css/mfx-flowless-check-listview.css");
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXFlowlessCheckListView() {
         this(FXCollections.observableArrayList());
     }
@@ -41,10 +58,16 @@ public class MFXFlowlessCheckListView<T> extends AbstractFlowlessListView<T, MFX
         initialize();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     protected void setDefaultCellFactory() {
         setCellFactory(item -> new MFXFlowlessCheckListCell<>(this, item));

+ 23 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXFlowlessListView.java

@@ -29,10 +29,27 @@ import javafx.collections.FXCollections;
 import javafx.collections.ObservableList;
 import javafx.scene.control.Skin;
 
+/**
+ * Implementation of a list view based on Flowless.
+ * <p>
+ * Extends {@link AbstractFlowlessListView}.
+ * <p></p>
+ * Default cell: {@link MFXFlowlessListCell}.
+ * <p>
+ * Default selection model: {@link ListSelectionModel}.
+ * <p>
+ * Default skin: {@link MFXFlowlessListViewSkin}.
+ */
 public class MFXFlowlessListView<T> extends AbstractFlowlessListView<T, AbstractMFXFlowlessListCell<T>, IListSelectionModel<T>> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final String STYLE_CLASS = "mfx-list-view";
     private final String STYLESHEET = MFXResourcesLoader.load("css/mfx-flowless-listview.css");
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXFlowlessListView() {
         this(FXCollections.observableArrayList());
     }
@@ -42,10 +59,16 @@ public class MFXFlowlessListView<T> extends AbstractFlowlessListView<T, Abstract
         initialize();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     protected void setDefaultCellFactory() {
         setCellFactory(item -> new MFXFlowlessListCell<>(this, item));

+ 81 - 29
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXHLoader.java

@@ -27,7 +27,6 @@ import javafx.beans.property.*;
 import javafx.fxml.FXMLLoader;
 import javafx.geometry.Pos;
 import javafx.scene.Node;
-import javafx.scene.control.ToggleButton;
 import javafx.scene.control.ToggleGroup;
 import javafx.scene.layout.HBox;
 import javafx.scene.layout.Pane;
@@ -39,25 +38,27 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 /**
  * Convenience class for creating dashboards, no more hassle on managing multiple views.
  * <p>
- * This control extends {@code HBox} and has a {@code ThreadExecutorService} for loading fxml files in background
- * leaving the UI responsive
+ * This control extends {@code HBox} and relies on {@link LoaderUtils} for loading fxml files in the background
+ * leaving the UI responsive.
  * <p></p>
- * Every time an fxml file is submitted with '{@code addItem}' a wrapper class (MFXItem) is created,
- * then it's sent to the '{@code load}' method which creates a {@code Task} and submits it to the executor.
- * <p>
- * Everytime an MFXItem is loaded, a new ToggleButton is added to the {@code HBox}, the button already
- * has a listener on the selectedProperty for switching the view and since nodes are cached the transition is faster
- * than loading the fxml again.
+ * Once everything is set up and the fxml files have been added with the various {@code addItem} methods
+ * to start loading the views invoke the {@link #start()} method. That method then will get all the
+ * {@link MFXLoaderBean}s in the views map and for each of them checks if the root has not been loaded yet,
+ * creates the load callable by calling {@link #buildLoadCallable(MFXLoaderBean)} and submits it to the executor in
+ * {@link LoaderUtils}.
  * <p></p>
- * Every toggle button is part of a ToggleGroup which is modified with
- * the {@code ToggleButtonsUtil} class  to add 'always one selected' support
+ * Once everything is loaded: {@link ToggleButtonsUtil#addAlwaysOneSelectedSupport(ToggleGroup)} is called, the loaded
+ * toggles are added to the children list and {@link #setDefault()} is called.
+ *
+ * @see LoaderUtils
+ * @see MFXLoaderBean
+ * @see ToggleButtonsUtil
  */
 public class MFXHLoader extends HBox {
     //================================================================================
@@ -109,6 +110,11 @@ public class MFXHLoader extends HBox {
         addListeners();
     }
 
+    /**
+     * Adds a listener to loadedItems to check when all the views have been loaded.
+     * Then: calls {@link ToggleButtonsUtil#addAlwaysOneSelectedSupport(ToggleGroup)},
+     * adds all the toggles to the children list, calls {@link #setDefault()}
+     */
     private void addListeners() {
         loadedItems.addListener((observable, oldValue, newValue) -> {
             if (newValue.intValue() == idViewMap.size()) {
@@ -122,41 +128,68 @@ public class MFXHLoader extends HBox {
         });
     }
 
-    public void addItem(ToggleButton button, URL fxmlFile) {
-        addItem(LoaderUtils.generateKey(fxmlFile), button, fxmlFile, false);
-    }
-
-    public void addItem(ToggleButton button, URL fxmlFile, boolean defaultRoot) {
-        addItem(LoaderUtils.generateKey(fxmlFile), button, fxmlFile, defaultRoot);
+    /**
+     * Gets the built {@code MFXLoaderBean} from the builder,
+     * adds the toggle to the loader's toggle group and puts
+     * the bean in the {@code idViewMap} with a key generated by
+     * {@link LoaderUtils#generateKey(URL)}.
+     */
+    public void addItem(MFXLoaderBean.Builder builder) {
+        MFXLoaderBean loaderBean = builder.get();
+        LoaderUtils.checkFxmlFile(loaderBean.getFxmlURL());
+        loaderBean.getButton().setToggleGroup(toggleGroup);
+        idViewMap.put(LoaderUtils.generateKey(loaderBean.getFxmlURL()), loaderBean);
     }
 
-    public void addItem(String key, ToggleButton button, URL fxmlFile, boolean defaultRoot) {
-        LoaderUtils.checkFxmlFile(fxmlFile);
-        MFXLoaderBean loaderBean = new MFXLoaderBean(button, fxmlFile, defaultRoot);
+    /**
+     * Gets the built {@code MFXLoaderBean} from the builder,
+     * adds the toggle to the loader's toggle group and puts
+     * the bean in the {@code idViewMap} with the specified key.
+     */
+    public void addItem(String key, MFXLoaderBean.Builder builder) {
+        MFXLoaderBean loaderBean = builder.get();
+        LoaderUtils.checkFxmlFile(loaderBean.getFxmlURL());
         loaderBean.getButton().setToggleGroup(toggleGroup);
         idViewMap.put(key, loaderBean);
     }
 
+    /**
+     * Checks if there is a {@code MFXLoaderBean} which has the defaultRoot flag set to true
+     * and sets the bean's toggle state to selected so that the view is shown, this is handled on
+     * the JavaFX's thread.
+     */
     private void setDefault() {
         idViewMap.values().stream()
                 .filter(MFXLoaderBean::isDefault)
                 .findFirst().ifPresent(loaderBean -> Platform.runLater(() -> loaderBean.getButton().setSelected(true)));
     }
 
+    /**
+     * Starts the loading process.
+     * <p></p>
+     * Retrieves the {@link MFXLoaderBean}s in the idViewMa, for each of them
+     * checks if the node has been already loaded, if not then calls {@link #buildLoadCallable(MFXLoaderBean)},
+     * submit the callable to {@link LoaderUtils#submit(Callable)}, then increments the loadedItems counter.
+     */
     public void start() {
+        if (contentPane == null) {
+            throw new NullPointerException("Content pane has not been set!");
+        }
+
         List<MFXLoaderBean> loaderBeans = new ArrayList<>(idViewMap.values());
         for (MFXLoaderBean loaderBean : loaderBeans) {
-            if (loaderBean.getRoot() == null){
-                try {
-                    LoaderUtils.submit(buildLoadCallable(loaderBean)).get();
-                } catch (InterruptedException | ExecutionException ex) {
-                    ex.printStackTrace();
-                }
+            if (loaderBean.getRoot() == null) {
+                LoaderUtils.submit(buildLoadCallable(loaderBean));
                 loadedItems.set(loadedItems.get() + 1);
             }
         }
     }
 
+    /**
+     * Builds the callable which loads the fxmlFile with {@link LoaderUtils#fxmlLoad(FXMLLoader, MFXLoaderBean)}
+     * or {@link LoaderUtils#fxmlLoad(MFXLoaderBean)} if the FXMLLoader supplier is null.
+     * When the file is loaded adds a listener to the toggle's selected property to handle the view switching.
+     */
     private Callable<Node> buildLoadCallable(MFXLoaderBean loaderBean) {
         return () -> {
             Node root;
@@ -168,8 +201,8 @@ public class MFXHLoader extends HBox {
             loaderBean.setRoot(root);
 
             loaderBean.getButton().selectedProperty().addListener((observable, oldValue, newValue) -> {
-                if (isAnimated.get()) {
-                    animationType.build(loaderBean.getRoot(), animationMillis.doubleValue()).play();
+                if (isIsAnimated()) {
+                    getAnimationType().build(loaderBean.getRoot(), getAnimationMillis()).play();
                 }
                 if (newValue) {
                     try {
@@ -183,14 +216,24 @@ public class MFXHLoader extends HBox {
         };
     }
 
+    /**
+     * @return the {@code MFXLoaderBean} to which the specified key is mapped,
+     * or null if this map contains no mapping for the key.
+     */
     public MFXLoaderBean getLoadItem(String key) {
         return this.idViewMap.get(key);
     }
 
+    /**
+     * @return the pane on which the views are switched.
+     */
     public Pane getContentPane() {
         return contentPane;
     }
 
+    /**
+     * Sets the pane on which the views are switched.
+     */
     public void setContentPane(Pane contentPane) {
         this.contentPane = contentPane;
     }
@@ -211,6 +254,9 @@ public class MFXHLoader extends HBox {
         return isAnimated.get();
     }
 
+    /**
+     * Specifies if the view switching is animated.
+     */
     public BooleanProperty isAnimatedProperty() {
         return isAnimated;
     }
@@ -223,6 +269,9 @@ public class MFXHLoader extends HBox {
         return animationMillis.get();
     }
 
+    /**
+     * Specified the switch animation duration.
+     */
     public DoubleProperty animationMillisProperty() {
         return animationMillis;
     }
@@ -235,6 +284,9 @@ public class MFXHLoader extends HBox {
         return animationType;
     }
 
+    /**
+     * Sets the switch animation type.
+     */
     public void setAnimationType(MFXAnimationFactory animationType) {
         this.animationType = animationType;
     }

+ 27 - 24
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXLabel.java

@@ -86,7 +86,7 @@ public class MFXLabel extends Control {
         editorFocused.addListener(invalidated ->pseudoClassStateChanged(EDITOR_FOCUSED_PSEUDO_CLASS, editorFocused.get()));
 
         /* Makes possible to choose the control style without depending on the constructor,
-         *  it seems to work well but to be honest it would be way better if JavaFX would give us
+         * it seems to work well but to be honest it would be way better if JavaFX would give us
          * the possibility to change the user agent stylesheet at runtime (I mean by re-calling getUserAgentStylesheet)
          */
         labelStyle.addListener((observable, oldValue, newValue) -> {
@@ -198,11 +198,15 @@ public class MFXLabel extends Control {
         return editorFocused.get();
     }
 
+    /**
+     * Bound to the editor focus property. This allows to keep the focused style specified
+     * by css when the focus is acquired by the editor. The pseudo class to use in css is ":editor"
+     */
     public BooleanProperty editorFocusedProperty() {
         return editorFocused;
     }
 
-//================================================================================
+    //================================================================================
     // Styleable Properties
     //================================================================================
 
@@ -220,9 +224,6 @@ public class MFXLabel extends Control {
             Color.BLACK
     );
 
-    /**
-     * Specifies the style of the MFXLabel.
-     */
     private final StyleableObjectProperty<LabelStyles> labelStyle = new SimpleStyleableObjectProperty<>(
             StyleableProperties.STYLE,
             this,
@@ -230,9 +231,6 @@ public class MFXLabel extends Control {
             LabelStyles.STYLE1
     );
 
-    /**
-     * Specifies the space between the icons and the text.
-     */
     private final StyleableDoubleProperty graphicTextGap = new SimpleStyleableDoubleProperty(
             StyleableProperties.GRAPHIC_TEXT_GAP,
             this,
@@ -240,9 +238,6 @@ public class MFXLabel extends Control {
             5.0
     );
 
-    /**
-     * Specifies whether the label can be edited or not.
-     */
     private final StyleableBooleanProperty editable = new SimpleStyleableBooleanProperty(
             StyleableProperties.EDITABLE,
             this,
@@ -250,9 +245,6 @@ public class MFXLabel extends Control {
             false
     );
 
-    /**
-     * Specifies if focus lines should be animated.
-     */
     private final StyleableBooleanProperty animateLines = new SimpleStyleableBooleanProperty(
             StyleableProperties.ANIMATE_LINES,
             this,
@@ -260,9 +252,6 @@ public class MFXLabel extends Control {
             true
     );
 
-    /**
-     * Specifies the focusedLine color.
-     */
     private final StyleableObjectProperty<Paint> lineColor = new SimpleStyleableObjectProperty<>(
             StyleableProperties.LINE_COLOR,
             this,
@@ -270,9 +259,6 @@ public class MFXLabel extends Control {
             Color.rgb(82, 0, 237)
     );
 
-    /**
-     * Specifies the unfocusedLine color.
-     */
     private final StyleableObjectProperty<Paint> unfocusedLineColor = new SimpleStyleableObjectProperty<>(
             StyleableProperties.UNFOCUSED_LINE_COLOR,
             this,
@@ -280,9 +266,6 @@ public class MFXLabel extends Control {
             Color.rgb(159, 159, 159)
     );
 
-    /**
-     * Specifies the lines' stroke width.
-     */
     private final StyleableDoubleProperty lineStrokeWidth = new SimpleStyleableDoubleProperty(
             StyleableProperties.LINE_STROKE_WIDTH,
             this,
@@ -324,6 +307,9 @@ public class MFXLabel extends Control {
         return labelStyle.get();
     }
 
+    /**
+     * Specifies the label css style.
+     */
     public StyleableObjectProperty<LabelStyles> labelStyleProperty() {
         return labelStyle;
     }
@@ -336,6 +322,9 @@ public class MFXLabel extends Control {
         return graphicTextGap.get();
     }
 
+    /**
+     * Specifies the space between the label's leading and trailing icons.
+     */
     public StyleableDoubleProperty graphicTextGapProperty() {
         return graphicTextGap;
     }
@@ -348,6 +337,9 @@ public class MFXLabel extends Control {
         return editable.get();
     }
 
+    /**
+     * Specifies whether the label is editable or not.
+     */
     public StyleableBooleanProperty editableProperty() {
         return editable;
     }
@@ -360,6 +352,9 @@ public class MFXLabel extends Control {
         return animateLines.get();
     }
 
+    /**
+     * Specifies if the line should be animated when focus changes. (works only with STYLE1)
+     */
     public StyleableBooleanProperty animateLinesProperty() {
         return animateLines;
     }
@@ -372,6 +367,9 @@ public class MFXLabel extends Control {
         return lineColor.get();
     }
 
+    /**
+     * Specifies the focused line color.
+     */
     public StyleableObjectProperty<Paint> lineColorProperty() {
         return lineColor;
     }
@@ -384,6 +382,9 @@ public class MFXLabel extends Control {
         return unfocusedLineColor.get();
     }
 
+    /**
+     * Specifies the unfocused line color.
+     */
     public StyleableObjectProperty<Paint> unfocusedLineColorProperty() {
         return unfocusedLineColor;
     }
@@ -396,6 +397,9 @@ public class MFXLabel extends Control {
         return lineStrokeWidth.get();
     }
 
+    /**
+     * Specifies the lines stroke width.
+     */
     public StyleableDoubleProperty lineStrokeWidthProperty() {
         return lineStrokeWidth;
     }
@@ -482,7 +486,6 @@ public class MFXLabel extends Control {
         }
     }
 
-
     public static List<CssMetaData<? extends Styleable, ?>> getControlCssMetaDataList() {
         return StyleableProperties.cssMetaDataList;
     }

+ 6 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableView.java

@@ -96,6 +96,9 @@ public class MFXTableView<T> extends Control {
         return selectionModel.get();
     }
 
+    /**
+     * Specifies the selection model used by the control.
+     */
     public ObjectProperty<ITableSelectionModel<T>> selectionModelProperty() {
         return selectionModel;
     }
@@ -138,6 +141,9 @@ public class MFXTableView<T> extends Control {
         return fixedRowsHeight.get();
     }
 
+    /**
+     * Specifies the max height of all rows in the table.
+     */
     public DoubleProperty fixedRowsHeightProperty() {
         return fixedRowsHeight;
     }

+ 16 - 16
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXToggleNode.java

@@ -135,6 +135,10 @@ public class MFXToggleNode extends ToggleButton {
         NodeUtils.makeRegionCircular(this);
     }
 
+    /**
+     * Initializes the ripple generator's properties and
+     * adds the handler for ripple generation to the control.
+     */
     protected void setupRippleGenerator() {
         rippleGenerator.setAnimateBackground(false);
         rippleGenerator.setRippleColor(Color.GRAY);
@@ -151,9 +155,6 @@ public class MFXToggleNode extends ToggleButton {
     // Styleable Properties
     //================================================================================
 
-    /**
-     * Specifies the size (both width and height) of the control.
-     */
     private final StyleableDoubleProperty size = new SimpleStyleableDoubleProperty(
             StyleableProperties.SIZE,
             this,
@@ -161,9 +162,6 @@ public class MFXToggleNode extends ToggleButton {
             40.0
     );
 
-    /**
-     * Specifies the shape of the control
-     */
     private final StyleableObjectProperty<ToggleNodeShape> toggleShape = new SimpleStyleableObjectProperty<>(
             StyleableProperties.SHAPE,
             this,
@@ -171,11 +169,6 @@ public class MFXToggleNode extends ToggleButton {
             ToggleNodeShape.CIRCLE
     );
 
-    /**
-     * Specifies the background color when selected.
-     *
-     * @see Color
-     */
     private final StyleableObjectProperty<Paint> selectedColor = new SimpleStyleableObjectProperty<>(
             StyleableProperties.SELECTED_COLOR,
             this,
@@ -183,11 +176,6 @@ public class MFXToggleNode extends ToggleButton {
             Color.rgb(190, 190, 190, 0.5)
     );
 
-    /**
-     * Specifies the background color when unselected.
-     *
-     * @see Color
-     */
     private final StyleableObjectProperty<Paint> unSelectedColor = new SimpleStyleableObjectProperty<>(
             StyleableProperties.UNSELECTED_COLOR,
             this,
@@ -199,6 +187,9 @@ public class MFXToggleNode extends ToggleButton {
         return size.get();
     }
 
+    /**
+     * Specifies the size (both width and height) of the control.
+     */
     public StyleableDoubleProperty sizeProperty() {
         return size;
     }
@@ -211,6 +202,9 @@ public class MFXToggleNode extends ToggleButton {
         return toggleShape.get();
     }
 
+    /**
+     * Specifies the shape of the control
+     */
     public StyleableObjectProperty<ToggleNodeShape> toggleShapeProperty() {
         return toggleShape;
     }
@@ -223,6 +217,9 @@ public class MFXToggleNode extends ToggleButton {
         return selectedColor.get();
     }
 
+    /**
+     * Specifies the background color when selected.
+     */
     public StyleableObjectProperty<Paint> selectedColorProperty() {
         return selectedColor;
     }
@@ -235,6 +232,9 @@ public class MFXToggleNode extends ToggleButton {
         return unSelectedColor.get();
     }
 
+    /**
+     * Specifies the background color when unselected.
+     */
     public StyleableObjectProperty<Paint> unSelectedColorProperty() {
         return unSelectedColor;
     }

+ 74 - 18
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXVLoader.java

@@ -32,30 +32,33 @@ import javafx.scene.layout.Pane;
 import javafx.scene.layout.Region;
 import javafx.scene.layout.VBox;
 
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 /**
  * Convenience class for creating dashboards, no more hassle on managing multiple views.
  * <p>
- * This control extends {@code VBox} and has a {@code ThreadExecutorService} for loading fxml files in background
- * leaving the UI responsive
+ * This control extends {@code VBox} and relies on {@link LoaderUtils} for loading fxml files in the background
+ * leaving the UI responsive.
  * <p></p>
- * Every time an fxml file is submitted with '{@code addItem}' a wrapper class (MFXItem) is created,
- * then it's sent to the '{@code load}' method which creates a {@code Task} and submits it to the executor.
- * <p>
- * Everytime an MFXItem is loaded, a new ToggleButton is added to the {@code VBox}, the button already
- * has a listener on the selectedProperty for switching the view and since nodes are cached the transition is faster
- * than loading the fxml again.
+ * Once everything is set up and the fxml files have been added with the various {@code addItem} methods
+ * to start loading the views invoke the {@link #start()} method. That method then will get all the
+ * {@link MFXLoaderBean}s in the views map and for each of them checks if the root has not been loaded yet,
+ * creates the load callable by calling {@link #buildLoadCallable(MFXLoaderBean)} and submits it to the executor in
+ * {@link LoaderUtils}.
  * <p></p>
- * Every toggle button is part of a ToggleGroup which is modified with
- * the {@code ToggleButtonsUtil} class  to add 'always one selected' support
+ * Once everything is loaded: {@link ToggleButtonsUtil#addAlwaysOneSelectedSupport(ToggleGroup)} is called, the loaded
+ * toggles are added to the children list and {@link #setDefault()} is called.
+ *
+ * @see LoaderUtils
+ * @see MFXLoaderBean
+ * @see ToggleButtonsUtil
  */
 public class MFXVLoader extends VBox {
     //================================================================================
@@ -106,7 +109,12 @@ public class MFXVLoader extends VBox {
         getStyleClass().add(STYLE_CLASS);
         addListeners();
     }
-    
+
+    /**
+     * Adds a listener to loadedItems to check when all the views have been loaded.
+     * Then: calls {@link ToggleButtonsUtil#addAlwaysOneSelectedSupport(ToggleGroup)},
+     * adds all the toggles to the children list, calls {@link #setDefault()}
+     */
     private void addListeners() {
         loadedItems.addListener((observable, oldValue, newValue) -> {
             if (newValue.intValue() == idViewMap.size()) {
@@ -119,6 +127,13 @@ public class MFXVLoader extends VBox {
             }
         });
     }
+
+    /**
+     * Gets the built {@code MFXLoaderBean} from the builder,
+     * adds the toggle to the loader's toggle group and puts
+     * the bean in the {@code idViewMap} with a key generated by
+     * {@link LoaderUtils#generateKey(URL)}.
+     */
     public void addItem(MFXLoaderBean.Builder builder) {
         MFXLoaderBean loaderBean = builder.get();
         LoaderUtils.checkFxmlFile(loaderBean.getFxmlURL());
@@ -126,6 +141,11 @@ public class MFXVLoader extends VBox {
         idViewMap.put(LoaderUtils.generateKey(loaderBean.getFxmlURL()), loaderBean);
     }
 
+    /**
+     * Gets the built {@code MFXLoaderBean} from the builder,
+     * adds the toggle to the loader's toggle group and puts
+     * the bean in the {@code idViewMap} with the specified key.
+     */
     public void addItem(String key, MFXLoaderBean.Builder builder) {
         MFXLoaderBean loaderBean = builder.get();
         LoaderUtils.checkFxmlFile(loaderBean.getFxmlURL());
@@ -133,26 +153,43 @@ public class MFXVLoader extends VBox {
         idViewMap.put(key, loaderBean);
     }
 
+    /**
+     * Checks if there is a {@code MFXLoaderBean} which has the defaultRoot flag set to true
+     * and sets the bean's toggle state to selected so that the view is shown, this is handled on
+     * the JavaFX's thread.
+     */
     private void setDefault() {
         idViewMap.values().stream()
                 .filter(MFXLoaderBean::isDefault)
                 .findFirst().ifPresent(loaderBean -> Platform.runLater(() -> loaderBean.getButton().setSelected(true)));
     }
 
+    /**
+     * Starts the loading process.
+     * <p></p>
+     * Retrieves the {@link MFXLoaderBean}s in the idViewMa, for each of them
+     * checks if the node has been already loaded, if not then calls {@link #buildLoadCallable(MFXLoaderBean)},
+     * submit the callable to {@link LoaderUtils#submit(Callable)}, then increments the loadedItems counter.
+     */
     public void start() {
+        if (contentPane == null) {
+            throw new NullPointerException("Content pane has not been set!");
+        }
+
         List<MFXLoaderBean> loaderBeans = new ArrayList<>(idViewMap.values());
         for (MFXLoaderBean loaderBean : loaderBeans) {
             if (loaderBean.getRoot() == null) {
-                try {
-                    LoaderUtils.submit(buildLoadCallable(loaderBean)).get();
-                } catch (InterruptedException | ExecutionException ex) {
-                    ex.printStackTrace();
-                }
+                LoaderUtils.submit(buildLoadCallable(loaderBean));
                 loadedItems.set(loadedItems.get() + 1);
             }
         }
     }
 
+    /**
+     * Builds the callable which loads the fxmlFile with {@link LoaderUtils#fxmlLoad(FXMLLoader, MFXLoaderBean)}
+     * or {@link LoaderUtils#fxmlLoad(MFXLoaderBean)} if the FXMLLoader supplier is null.
+     * When the file is loaded adds a listener to the toggle's selected property to handle the view switching.
+     */
     private Callable<Node> buildLoadCallable(MFXLoaderBean loaderBean) {
         return () -> {
             Node root;
@@ -178,15 +215,25 @@ public class MFXVLoader extends VBox {
             return root;
         };
     }
-    
+
+    /**
+     * @return the {@code MFXLoaderBean} to which the specified key is mapped,
+     * or null if this map contains no mapping for the key.
+     */
     public MFXLoaderBean getLoadItem(String key) {
         return this.idViewMap.get(key);
     }
 
+    /**
+     * @return the pane on which the views are switched.
+     */
     public Pane getContentPane() {
         return contentPane;
     }
 
+    /**
+     * Sets the pane on which the views are switched.
+     */
     public void setContentPane(Pane contentPane) {
         this.contentPane = contentPane;
     }
@@ -207,6 +254,9 @@ public class MFXVLoader extends VBox {
         return isAnimated.get();
     }
 
+    /**
+     * Specifies if the view switching is animated.
+     */
     public BooleanProperty isAnimatedProperty() {
         return isAnimated;
     }
@@ -219,6 +269,9 @@ public class MFXVLoader extends VBox {
         return animationMillis.get();
     }
 
+    /**
+     * Specified the switch animation duration.
+     */
     public DoubleProperty animationMillisProperty() {
         return animationMillis;
     }
@@ -231,6 +284,9 @@ public class MFXVLoader extends VBox {
         return animationType;
     }
 
+    /**
+     * Sets the switch animation type.
+     */
     public void setAnimationType(MFXAnimationFactory animationType) {
         this.animationType = animationType;
     }

+ 70 - 43
materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractFlowlessListView.java

@@ -37,12 +37,27 @@ import javafx.util.Duration;
 
 import java.util.List;
 
+/**
+ * Base class for all list views based on Flowless, defines common properties and behavior.
+ * <p>
+ * Extends {@link Control} and implements {@link IListView}.
+ *
+ * @param <T> the type of data within the ListView
+ * @param <C> the type of cells that will be used
+ * @param <S> the type of selection model
+ */
 public abstract class AbstractFlowlessListView<T, C extends AbstractMFXFlowlessListCell<T>, S extends IListSelectionModel<T>> extends Control implements IListView<T, C, S> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private static final StyleablePropertyFactory<AbstractFlowlessListView<?, ?, ?>> FACTORY = new StyleablePropertyFactory<>(Control.getClassCssMetaData());
     protected final ReadOnlyObjectWrapper<ObservableList<T>> items = new ReadOnlyObjectWrapper<>(FXCollections.observableArrayList());
     protected final ObjectProperty<Callback<T, C>> celFactory = new SimpleObjectProperty<>();
     protected final ObjectProperty<S> selectionModel = new SimpleObjectProperty<>();
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public AbstractFlowlessListView() {
         this(FXCollections.observableArrayList());
     }
@@ -54,6 +69,23 @@ public abstract class AbstractFlowlessListView<T, C extends AbstractMFXFlowlessL
         addBarsListeners();
     }
 
+    //================================================================================
+    // Abstract Methods
+    //================================================================================
+
+    /**
+     * Abstract method called by the constructor to set a default factory for the cells.
+     */
+    protected abstract void setDefaultCellFactory();
+
+    /**
+     * Abstract method called by the constructor to set a default selection model.
+     */
+    protected abstract void setDefaultSelectionModel();
+
+    //================================================================================
+    // Methods
+    //================================================================================
     protected void addBarsListeners() {
         this.trackColor.addListener((observable, oldValue, newValue) -> {
             if (!newValue.equals(oldValue)) {
@@ -74,9 +106,6 @@ public abstract class AbstractFlowlessListView<T, C extends AbstractMFXFlowlessL
         });
     }
 
-    protected abstract void setDefaultCellFactory();
-    protected abstract void setDefaultSelectionModel();
-
     /**
      * Sets the CSS looked-up colors
      */
@@ -89,6 +118,9 @@ public abstract class AbstractFlowlessListView<T, C extends AbstractMFXFlowlessL
         setStyle(sb.toString());
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
 
     @Override
     public ObservableList<T> getItems() {
@@ -141,55 +173,18 @@ public abstract class AbstractFlowlessListView<T, C extends AbstractMFXFlowlessL
     //================================================================================
     // ScrollBars Properties
     //================================================================================
-
-    /**
-     * Specifies the color of the scrollbars' track.
-     */
     private final ObjectProperty<Paint> trackColor = new SimpleObjectProperty<>(Color.rgb(132, 132, 132));
-
-    /**
-     * Specifies the color of the scrollbars' thumb.
-     */
     private final ObjectProperty<Paint> thumbColor = new SimpleObjectProperty<>(Color.rgb(137, 137, 137));
-
-    /**
-     * Specifies the color of the scrollbars' thumb when mouse hover.
-     */
     private final ObjectProperty<Paint> thumbHoverColor = new SimpleObjectProperty<>(Color.rgb(89, 88, 91));
-
-    /**
-     * Specifies the time after which the scrollbars are hidden.
-     */
     private final ObjectProperty<Duration> hideAfter = new SimpleObjectProperty<>(Duration.seconds(1));
 
-    //================================================================================
-    // Styleable Properties
-    //================================================================================
-
-    /**
-     * Specifies if the scrollbars should be hidden when the mouse is not on the list.
-     */
-    private final StyleableBooleanProperty hideScrollBars = new SimpleStyleableBooleanProperty(
-            StyleableProperties.HIDE_SCROLLBARS,
-            this,
-            "hideScrollBars",
-            false
-    );
-
-    /**
-     * Specifies the shadow strength around the control.
-     */
-    private final StyleableObjectProperty<DepthLevel> depthLevel = new SimpleStyleableObjectProperty<>(
-            StyleableProperties.DEPTH_LEVEL,
-            this,
-            "depthLevel",
-            DepthLevel.LEVEL2
-    );
-
     public Paint getTrackColor() {
         return trackColor.get();
     }
 
+    /**
+     * Specifies the color of the scrollbars' track.
+     */
     public ObjectProperty<Paint> trackColorProperty() {
         return trackColor;
     }
@@ -202,6 +197,9 @@ public abstract class AbstractFlowlessListView<T, C extends AbstractMFXFlowlessL
         return thumbColor.get();
     }
 
+    /**
+     * Specifies the color of the scrollbars' thumb.
+     */
     public ObjectProperty<Paint> thumbColorProperty() {
         return thumbColor;
     }
@@ -214,6 +212,9 @@ public abstract class AbstractFlowlessListView<T, C extends AbstractMFXFlowlessL
         return thumbHoverColor.get();
     }
 
+    /**
+     * Specifies the color of the scrollbars' thumb when mouse hover.
+     */
     public ObjectProperty<Paint> thumbHoverColorProperty() {
         return thumbHoverColor;
     }
@@ -226,6 +227,9 @@ public abstract class AbstractFlowlessListView<T, C extends AbstractMFXFlowlessL
         return hideAfter.get();
     }
 
+    /**
+     * Specifies the time after which the scrollbars are hidden.
+     */
     public ObjectProperty<Duration> hideAfterProperty() {
         return hideAfter;
     }
@@ -234,10 +238,30 @@ public abstract class AbstractFlowlessListView<T, C extends AbstractMFXFlowlessL
         this.hideAfter.set(hideAfter);
     }
 
+    //================================================================================
+    // Styleable Properties
+    //================================================================================
+    private final StyleableBooleanProperty hideScrollBars = new SimpleStyleableBooleanProperty(
+            StyleableProperties.HIDE_SCROLLBARS,
+            this,
+            "hideScrollBars",
+            false
+    );
+
+    private final StyleableObjectProperty<DepthLevel> depthLevel = new SimpleStyleableObjectProperty<>(
+            StyleableProperties.DEPTH_LEVEL,
+            this,
+            "depthLevel",
+            DepthLevel.LEVEL2
+    );
+
     public boolean isHideScrollBars() {
         return hideScrollBars.get();
     }
 
+    /**
+     * Specifies if the scrollbars should be hidden when the mouse is not on the list.
+     */
     public StyleableBooleanProperty hideScrollBarsProperty() {
         return hideScrollBars;
     }
@@ -250,6 +274,9 @@ public abstract class AbstractFlowlessListView<T, C extends AbstractMFXFlowlessL
         return depthLevel.get();
     }
 
+    /**
+     * Specifies the shadow strength around the control.
+     */
     public StyleableObjectProperty<DepthLevel> depthLevelProperty() {
         return depthLevel;
     }

+ 99 - 24
materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXFlowlessListCell.java

@@ -30,7 +30,18 @@ import javafx.scene.Scene;
 import javafx.scene.input.MouseEvent;
 import javafx.scene.layout.HBox;
 
+/**
+ * Base class for all cells used in list views based on Flowless,
+ * defines common properties and behavior.
+ * <p>
+ * Extends {@link HBox} and implements {@link Cell}.
+ *
+ * @param <T> the type of data within the ListView
+ */
 public abstract class AbstractMFXFlowlessListCell<T> extends HBox implements Cell<T, HBox> {
+    //================================================================================
+    // Properties
+    //================================================================================
     protected final AbstractFlowlessListView<T, ?, ?> listView;
     private final ReadOnlyObjectWrapper<T> data;
     private final ReadOnlyIntegerWrapper index = new ReadOnlyIntegerWrapper(-1);
@@ -39,6 +50,9 @@ public abstract class AbstractMFXFlowlessListCell<T> extends HBox implements Cel
     private static final PseudoClass SELECTED_PSEUDO_CLASS = PseudoClass.getPseudoClass("selected");
     private final BooleanProperty selected = new SimpleBooleanProperty(false);
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public AbstractMFXFlowlessListCell(AbstractFlowlessListView<T, ?, ?> listView, T data) {
         this(listView, data, 32);
     }
@@ -55,6 +69,18 @@ public abstract class AbstractMFXFlowlessListCell<T> extends HBox implements Cel
         initialize();
     }
 
+    //================================================================================
+    // Abstract Methods
+    //================================================================================
+
+    /**
+     * Abstract method which defines how the cell should process and show the given data.
+     */
+    protected abstract void render(T data);
+
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         setAlignment(Pos.CENTER_LEFT);
         setSpacing(5);
@@ -62,6 +88,15 @@ public abstract class AbstractMFXFlowlessListCell<T> extends HBox implements Cel
         addListeners();
     }
 
+    /**
+     * Adds listeners to:
+     * <p>
+     *  - selected property to update the pseudo class state.<p>
+     *  - scene property to call the {@link #render(T)} method the first time.<p>
+     *  - selection model's selected items property to properly update the state of the selected property.<p>
+     *  <p>
+     * Adds a filter for MOUSE_PRESSED which calls {@link #updateModel(MouseEvent)}.
+     */
     private void addListeners() {
         selected.addListener(invalidate -> pseudoClassStateChanged(SELECTED_PSEUDO_CLASS, selected.get()));
 
@@ -87,6 +122,9 @@ public abstract class AbstractMFXFlowlessListCell<T> extends HBox implements Cel
         return data.get();
     }
 
+    /**
+     * Data property of the cell.
+     */
     public ReadOnlyObjectProperty<T> dataProperty() {
         return data.getReadOnlyProperty();
     }
@@ -99,6 +137,9 @@ public abstract class AbstractMFXFlowlessListCell<T> extends HBox implements Cel
         return index.get();
     }
 
+    /**
+     * Index property of the cell.
+     */
     public ReadOnlyIntegerProperty indexProperty() {
         return index.getReadOnlyProperty();
     }
@@ -107,6 +148,9 @@ public abstract class AbstractMFXFlowlessListCell<T> extends HBox implements Cel
         this.index.set(index);
     }
 
+    /**
+     * Specifies the fixed height of the cell.
+     */
     public DoubleProperty fixedCellSizeProperty() {
         return fixedCellSize;
     }
@@ -119,6 +163,9 @@ public abstract class AbstractMFXFlowlessListCell<T> extends HBox implements Cel
         return selected.get();
     }
 
+    /**
+     * Selection state of the cell.
+     */
     public BooleanProperty selectedProperty() {
         return selected;
     }
@@ -127,13 +174,10 @@ public abstract class AbstractMFXFlowlessListCell<T> extends HBox implements Cel
         this.selected.set(selected);
     }
 
-    protected abstract void render(T data);
-
-    @Override
-    public HBox getNode() {
-        return this;
-    }
-
+    /**
+     * Updates the selection state of the cell and the state
+     * of the selection model as well.
+     */
     public void updateModel(MouseEvent event) {
         setSelected(!isSelected());
         if (isSelected()) {
@@ -143,29 +187,18 @@ public abstract class AbstractMFXFlowlessListCell<T> extends HBox implements Cel
         }
     }
 
-    @Override
-    public void updateIndex(int index) {
-        setIndex(index);
-        if (containsEqualsBoth() && !isSelected()) {
-            setSelected(true);
-            return;
-        }
-        if (containsNotEqualsIndex()) {
-            listView.getSelectionModel().updateIndex(getData(), index);
-            setSelected(true);
-            return;
-        }
-        if (containsNotEqualsData()) {
-            listView.getSelectionModel().clearSelectedItem(index);
-        }
-    }
-
+    /**
+     * Checks if the selection model contains the index and the data of this cell.
+     */
     protected boolean containsEqualsBoth() {
         IListSelectionModel<T> selectionModel = listView.getSelectionModel();
         return selectionModel.selectedItemsProperty().containsKey(getIndex()) &&
                 selectionModel.selectedItemsProperty().get(getIndex()).equals(getData());
     }
 
+    /**
+     * Checks if the selection model contains the data of the cell but the index is not the same.
+     */
     protected boolean containsNotEqualsIndex() {
         IListSelectionModel<T> selectionModel = listView.getSelectionModel();
         return selectionModel.selectedItemsProperty().containsValue(getData()) &&
@@ -174,9 +207,51 @@ public abstract class AbstractMFXFlowlessListCell<T> extends HBox implements Cel
                         .anyMatch(entry -> entry.getKey() != getIndex() && entry.getValue().equals(getData()));
     }
 
+    /**
+     * Checks if the selection model contains the index of the cell but the data is not the same.
+     */
     protected boolean containsNotEqualsData() {
         IListSelectionModel<T> selectionModel = listView.getSelectionModel();
         return selectionModel.selectedItemsProperty().containsKey(getIndex()) &&
                 !selectionModel.selectedItemsProperty().get(getIndex()).equals(getData());
     }
+
+    //================================================================================
+    // Override Methods
+    //================================================================================
+    @Override
+    public HBox getNode() {
+        return this;
+    }
+
+    /**
+     * Inherited doc:
+     * <p>
+     * {@inheritDoc}
+     *
+     * <p></p>
+     * Updates the index property of the cell with the given index parameter
+     * (which is provided by Flowless) then checks and fixes inconsistencies in the
+     * selection model.
+     *
+     *{@link #containsEqualsBoth()},
+     *{@link #containsNotEqualsIndex()},
+     *{@link #containsNotEqualsData()},
+     */
+    @Override
+    public void updateIndex(int index) {
+        setIndex(index);
+        if (containsEqualsBoth() && !isSelected()) {
+            setSelected(true);
+            return;
+        }
+        if (containsNotEqualsIndex()) {
+            listView.getSelectionModel().updateIndex(getData(), index);
+            setSelected(true);
+            return;
+        }
+        if (containsNotEqualsData()) {
+            listView.getSelectionModel().clearSelectedItem(index);
+        }
+    }
 }

+ 42 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/IListView.java

@@ -24,16 +24,58 @@ import javafx.beans.property.ReadOnlyObjectProperty;
 import javafx.collections.ObservableList;
 import javafx.util.Callback;
 
+/**
+ * Interface that defines the public api for all the list views based on Flowless.
+ *
+ * @param <T> the type of data within the ListView
+ * @param <C> the type of cells that will be used
+ * @param <S> the type of selection model
+ */
 public interface IListView<T, C extends AbstractMFXFlowlessListCell<T>, S extends IListSelectionModel<T>> {
+
+    /**
+     * @return the items observable list
+     */
     ObservableList<T> getItems();
+
+    /**
+     * @return the items observable list wrapped in a read-only property,
+     * to change the list items use {@link #setItems(ObservableList)} or {@link #getItems()}
+     */
     ReadOnlyObjectProperty<ObservableList<T>> itemsProperty();
+
+    /**
+     * Set all the items to the specified list.
+     */
     void setItems(ObservableList<T> items);
 
+    /**
+     * @return the callback used to build the list cells
+     */
     Callback<T, C> getCellFactory();
+
+    /**
+     * @return the cell factory property
+     */
     ObjectProperty<Callback<T, C>> cellFactoryProperty();
+
+    /**
+     * Replaces the cell factory with the given one
+     */
     void setCellFactory(Callback<T, C> cellFactory);
 
+    /**
+     * @return the list view selection model
+     */
     S getSelectionModel();
+
+    /**
+     * @return the list view selection model property
+     */
     ObjectProperty<S> selectionModelProperty();
+
+    /**
+     * Replaces the selection model with the given one.
+     */
     void setSelectionModel(S selectionModel);
 }

+ 66 - 2
materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXFlowlessCheckListCell.java

@@ -33,7 +33,15 @@ import javafx.scene.control.Label;
 import javafx.scene.input.MouseEvent;
 import javafx.util.Duration;
 
+/**
+ * Implementation of an {@link AbstractMFXFlowlessListCell} which has a combo box
+ * for usage in {@link MFXFlowlessCheckListCell}, has the checked property and pseudo class
+ * ":checked" for usage in CSS.
+ */
 public class MFXFlowlessCheckListCell<T> extends AbstractMFXFlowlessListCell<T> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final String STYLE_CLASS = "mfx-check-list-cell";
     private final String STYLESHHET = MFXResourcesLoader.load("css/mfx-flowless-check-listcell.css");
     protected final RippleGenerator rippleGenerator = new RippleGenerator(this);
@@ -45,6 +53,9 @@ public class MFXFlowlessCheckListCell<T> extends AbstractMFXFlowlessListCell<T>
 
     private boolean clearSelectionOnCheck = false;
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXFlowlessCheckListCell(MFXFlowlessCheckListView<T> listView, T data) {
         this(listView, data, 32);
     }
@@ -55,9 +66,25 @@ public class MFXFlowlessCheckListCell<T> extends AbstractMFXFlowlessListCell<T>
         checkbox = new MFXCheckbox("");
         initialize();
     }
-    
+
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
+        addListeners();
+        setupRippleGenerator();
+    }
+
+    /**
+     * Adds listeners to:
+     *  - checked property to update the pseudo class state.<p>
+     *  - binds the checked property to the selected property of the checkbox.<p>
+     *  - checkbox' selected property to update the check model and also checks if the behavior
+     *      is set to clear selection.<p>
+     *  - check model's checked items property to properly update the state of the check box's selected property.
+     */
+    private void addListeners() {
         checked.addListener(invalidated -> pseudoClassStateChanged(CHECKED_PSEUDO_CLASS, checked.get()));
         checked.bind(checkbox.selectedProperty());
 
@@ -73,9 +100,11 @@ public class MFXFlowlessCheckListCell<T> extends AbstractMFXFlowlessListCell<T>
             }
         });
 
-        setupRippleGenerator();
     }
 
+    /**
+     * Sets up the properties of the ripple generator and adds the mouse pressed filter.
+     */
     protected void setupRippleGenerator() {
         rippleGenerator.setManaged(false);
         rippleGenerator.rippleRadiusProperty().bind(widthProperty().divide(2.0));
@@ -92,10 +121,21 @@ public class MFXFlowlessCheckListCell<T> extends AbstractMFXFlowlessListCell<T>
         return clearSelectionOnCheck;
     }
 
+    /**
+     * Sets the behavior of the cell when an item is checked.
+     * <p>
+     * Selection and check are handled separately, this means that you can check and select items
+     * at the same time. By setting this flag to true when an item is checked the selection
+     * will be cleared.
+     */
     public void setClearSelectionOnCheck(boolean clearSelectionOnCheck) {
         this.clearSelectionOnCheck = clearSelectionOnCheck;
     }
 
+    /**
+     * Updates the state of the check model according to the cell's
+     * check state.
+     */
     public void updateCheckModel(boolean checked) {
         IListCheckModel<T> checkModel = (IListCheckModel<T>) listView.getSelectionModel();
         if (checked) {
@@ -105,12 +145,18 @@ public class MFXFlowlessCheckListCell<T> extends AbstractMFXFlowlessListCell<T>
         }
     }
 
+    /**
+     * Checks if the check model contains the index and the data of this cell.
+     */
     protected boolean containsEqualsBothCheck() {
         IListCheckModel<T> checkModel = (IListCheckModel<T>) listView.getSelectionModel();
         return checkModel.checkedItemsProperty().containsKey(getIndex()) &&
                 checkModel.checkedItemsProperty().get(getIndex()).equals(getData());
     }
 
+    /**
+     * Checks if the check model contains the data of the cell but the index is not the same.
+     */
     protected boolean containsNotEqualsIndexCheck() {
         IListCheckModel<T> checkModel = (IListCheckModel<T>) listView.getSelectionModel();
         return checkModel.checkedItemsProperty().containsValue(getData()) &&
@@ -119,12 +165,30 @@ public class MFXFlowlessCheckListCell<T> extends AbstractMFXFlowlessListCell<T>
                         .anyMatch(entry -> entry.getKey() != getIndex() && entry.getValue().equals(getData()));
     }
 
+    /**
+     * Checks if the check model contains the index of the cell but the data is not the same.
+     */
     protected boolean containsNotEqualsDataCheck() {
         IListCheckModel<T> checkModel = (IListCheckModel<T>) listView.getSelectionModel();
         return checkModel.checkedItemsProperty().containsKey(getIndex()) &&
                 !checkModel.checkedItemsProperty().get(getIndex()).equals(getData());
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
+
+    /**
+     * Inherited doc:
+     * <p>
+     * {@inheritDoc}
+     * <p></p>
+     *
+     * If the given data is instance of Node then the data is cast
+     * to Node and added to the children list with the checkbox as well.
+     * Otherwise a Label is created and toString is called on the data.
+     * The label has style class: "data-label"
+     */
     @Override
     protected void render(T data) {
         if (data instanceof Node) {

+ 30 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXFlowlessListCell.java

@@ -27,11 +27,21 @@ import javafx.scene.control.Label;
 import javafx.scene.input.MouseEvent;
 import javafx.util.Duration;
 
+/**
+ * Simple implementation of {@link AbstractMFXFlowlessListCell},
+ * includes a ripple generator for ripple effects on mouse pressed.
+ */
 public class MFXFlowlessListCell<T> extends AbstractMFXFlowlessListCell<T> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final String STYLE_CLASS = "mfx-list-cell";
     private final String STYLESHEET = MFXResourcesLoader.load("css/mfx-flowless-listcell.css");
     protected final RippleGenerator rippleGenerator = new RippleGenerator(this);
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXFlowlessListCell(AbstractFlowlessListView<T, ?, ?> listView, T  data) {
         super(listView, data);
         initialize();
@@ -42,11 +52,17 @@ public class MFXFlowlessListCell<T> extends AbstractMFXFlowlessListCell<T> {
         initialize();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
         setupRippleGenerator();
     }
 
+    /**
+     * Sets up the properties of the ripple generator and adds the mouse pressed filter.
+     */
     protected void setupRippleGenerator() {
         rippleGenerator.setManaged(false);
         rippleGenerator.rippleRadiusProperty().bind(widthProperty().divide(2.0));
@@ -59,6 +75,20 @@ public class MFXFlowlessListCell<T> extends AbstractMFXFlowlessListCell<T> {
         });
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
+
+    /**
+     * Inherited doc:
+     * <p>
+     * {@inheritDoc}
+     * <p></p>
+     *
+     * If the given data is instance of Node then the data is cast
+     * to Node and added to the children list. Otherwise a Label is created
+     * and toString is called on the data. The label has style class: "data-label"
+     */
     @Override
     protected void render(T data) {
         if (data instanceof Node) {

+ 8 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXTableColumnCell.java

@@ -102,6 +102,11 @@ public class MFXTableColumnCell<T> extends Label {
         return initialWidth.get();
     }
 
+    /**
+     * Specifies what was the initial width assigned to the control by JavaFX.
+     * We keep this value to use it the the context menu of the column,
+     * see {@link io.github.palexdev.materialfx.skins.MFXTableViewSkin}
+     */
     public ReadOnlyDoubleProperty initialWidthProperty() {
         return initialWidth.getReadOnlyProperty();
     }
@@ -114,6 +119,9 @@ public class MFXTableColumnCell<T> extends Label {
         return rowCellFactory.get();
     }
 
+    /**
+     * Specifies the callback which is used to build the row cell of the column.
+     */
     public ObjectProperty<Callback<T, ? extends MFXTableRowCell>> rowCellFactoryProperty() {
         return rowCellFactory;
     }

+ 31 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/selection/ComboSelectionModelMock.java

@@ -50,11 +50,18 @@ public class ComboSelectionModelMock<T> {
     //================================================================================
     // Methods
     //================================================================================
+
+    /**
+     * Clears the selection.
+     */
     public void clearSelection() {
         selectedItem.set(null);
         selectedIndex.set(-1);
     }
 
+    /**
+     * Selects the given item if present in the combo items list.
+     */
     public void selectItem(T item) {
         if (!comboBox.getItems().contains(item)) {
             return;
@@ -63,10 +70,16 @@ public class ComboSelectionModelMock<T> {
         selectedItem.set(item);
     }
 
+    /**
+     * Selects the first item in the combo items list.
+     */
     public void selectFirst() {
         selectedIndex.set(0);
     }
 
+    /**
+     * Selects the next item in the combo items list.
+     */
     public void selectNext() {
         if (getSelectedIndex() == (comboBox.getItems().size() - 1)) {
             return;
@@ -74,10 +87,16 @@ public class ComboSelectionModelMock<T> {
         selectedIndex.add(1);
     }
 
+    /**
+     * Selects the last item in the combo items list.
+     */
     public void selectLast() {
         selectedIndex.set(comboBox.getItems().size());
     }
 
+    /**
+     * Selects the previous item in the combo items list.
+     */
     public void selectPrevious() {
         if (getSelectedIndex() == -1) {
             return;
@@ -85,18 +104,30 @@ public class ComboSelectionModelMock<T> {
         selectedIndex.subtract(1);
     }
 
+    /**
+     * Returns the current selected item's index.
+     */
     public int getSelectedIndex() {
         return selectedIndex.get();
     }
 
+    /**
+     * Returns the selected index property as a read only.
+     */
     public ReadOnlyIntegerProperty selectedIndexProperty() {
         return selectedIndex.getReadOnlyProperty();
     }
 
+    /**
+     * Returns the current selected item.
+     */
     public T getSelectedItem() {
         return selectedItem.get();
     }
 
+    /**
+     * Returns the selected item property as a read only.
+     */
     public ReadOnlyObjectProperty<T> selectedItemProperty() {
         return selectedItem.getReadOnlyProperty();
     }

+ 39 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/selection/ListCheckModel.java

@@ -7,14 +7,33 @@ import javafx.beans.property.SimpleMapProperty;
 import java.util.List;
 import java.util.Map;
 
+/**
+ * Concrete implementation of the {@code IListCheckModel} interface.
+ * <p>
+ * Extends {@link ListSelectionModel}.
+ */
 public class ListCheckModel<T> extends ListSelectionModel<T> implements IListCheckModel<T> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final MapProperty<Integer, T> checkedItems = new SimpleMapProperty<>(getObservableTreeMap());
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
+
+    /**
+     * Puts the specified entry in the map.
+     */
     @Override
     public void check(int index, T data) {
         checkedItems.put(index, data);
     }
 
+    /**
+     * This method is called when the cell finds the data in the check model
+     * but the index changed so it needs to be updated.
+     */
     @Override
     public void updateIndex(T data, int index) {
         super.updateIndex(data, index);
@@ -30,11 +49,18 @@ public class ListCheckModel<T> extends ListSelectionModel<T> implements IListChe
         }
     }
 
+    /**
+     * Removes the mapping for the given index.
+     */
     @Override
     public void clearCheckedItem(int index) {
         checkedItems.remove(index);
     }
 
+    /**
+     * Retrieves the index for the given data, if preset
+     * removes the mapping for that index.
+     */
     @Override
     public void clearCheckedItem(T data) {
         checkedItems.entrySet().stream()
@@ -43,11 +69,18 @@ public class ListCheckModel<T> extends ListSelectionModel<T> implements IListChe
                 .ifPresent(entry -> checkedItems.remove(entry.getKey()));
     }
 
+    /**
+     * Removes all the entries from the map.
+     */
     @Override
     public void clearChecked() {
         checkedItems.clear();
     }
 
+    /**
+     * @return the checked item in the map with the given index or null
+     * if not found
+     */
     @Override
     public T getCheckedItem(int index) {
         if (checkedItems.isEmpty()) {
@@ -62,11 +95,17 @@ public class ListCheckModel<T> extends ListSelectionModel<T> implements IListChe
         }
     }
 
+    /**
+     * @return an unmodifiable list of all the checked items
+     */
     @Override
     public List<T> getCheckedItems() {
         return List.copyOf(checkedItems.values());
     }
 
+    /**
+     * @return the map property used for the check
+     */
     @Override
     public MapProperty<Integer, T> checkedItemsProperty() {
         return checkedItems;

+ 78 - 13
materialfx/src/main/java/io/github/palexdev/materialfx/selection/ListSelectionModel.java

@@ -29,10 +29,25 @@ import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 
+/**
+ * Concrete implementation of the {@code IListSelectionModel} interface.
+ */
 public class ListSelectionModel<T> implements IListSelectionModel<T> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final MapProperty<Integer, T> selectedItems = new SimpleMapProperty<>(getObservableTreeMap());
     private boolean allowsMultipleSelection = false;
 
+    //================================================================================
+    // Methods
+    //================================================================================
+
+    /**
+     * This method is called when the mouse event passed to {@link #select(int, Object, MouseEvent)}
+     * is null. Since it's null there's no check for isShiftDown() or isControlDown(), so in case
+     * of multiple selection enabled the passed index and data will always be added to the map.
+     */
     protected void select(int index, T data) {
         if (allowsMultipleSelection) {
             selectedItems.put(index, data);
@@ -43,6 +58,33 @@ public class ListSelectionModel<T> implements IListSelectionModel<T> {
         }
     }
 
+    /**
+     * Builds a new observable map backed by a TreeMap.
+     */
+    protected ObservableMap<Integer, T> getObservableTreeMap() {
+        return FXCollections.observableMap(new TreeMap<>());
+    }
+
+    //================================================================================
+    // Override Methods
+    //================================================================================
+
+    /**
+     * Called by the list cells when the mouse is pressed.
+     * The mouse event is needed in case of multiple selection allowed because
+     * we check if the Shift key or Ctrl key were pressed.
+     * <p>
+     * If the mouseEvent is null we call the other {@link #select(int, T)} method.
+     * <p>
+     * If the selection is multiple and Shift or Ctrl are pressed the new entry
+     * is put in the map.
+     * <p>
+     * If the selection is single the map is replaced by a new one that contains only the
+     * passed entry.
+     * <p>
+     * Note that if the item is already selected it is removed from the map, this behavior though is
+     * managed by the cells.
+     */
     @Override
     public void select(int index, T data, MouseEvent mouseEvent) {
         if (mouseEvent == null) {
@@ -50,21 +92,19 @@ public class ListSelectionModel<T> implements IListSelectionModel<T> {
             return;
         }
 
-        if (!allowsMultipleSelection) {
+        if (allowsMultipleSelection && (mouseEvent.isShiftDown() || mouseEvent.isControlDown())) {
+            selectedItems.put(index, data);
+        } else {
             ObservableMap<Integer, T> tmpMap = getObservableTreeMap();
             tmpMap.put(index, data);
             selectedItems.set(tmpMap);
-        } else {
-            if (mouseEvent.isShiftDown() || mouseEvent.isControlDown()) {
-                selectedItems.put(index, data);
-            } else {
-                ObservableMap<Integer, T> tmpMap = getObservableTreeMap();
-                tmpMap.put(index, data);
-                selectedItems.set(tmpMap);
-            }
         }
     }
 
+    /**
+     * This method is called when the cell finds the data in the selection model
+     * but the index changed so it needs to be updated.
+     */
     @Override
     public void updateIndex(T data, int index) {
         int mapIndex = selectedItems.entrySet()
@@ -78,11 +118,18 @@ public class ListSelectionModel<T> implements IListSelectionModel<T> {
         }
     }
 
+    /**
+     * Removes the mapping for the given index.
+     */
     @Override
     public void clearSelectedItem(int index) {
         selectedItems.remove(index);
     }
 
+    /**
+     * Retrieves the index for the given data, if preset
+     * removes the mapping for that index.
+     */
     @Override
     public void clearSelectedItem(T data) {
         selectedItems.entrySet().stream()
@@ -91,16 +138,26 @@ public class ListSelectionModel<T> implements IListSelectionModel<T> {
                 .ifPresent(entry -> selectedItems.remove(entry.getKey()));
     }
 
+    /**
+     * Removes all the entries from the map.
+     */
     @Override
     public void clearSelection() {
         selectedItems.clear();
     }
 
+    /**
+     * @return the first selected item in the map
+     */
     @Override
     public T getSelectedItem() {
         return getSelectedItem(0);
     }
 
+    /**
+     * @return the selected item in the map with the given index or null
+     * if not found
+     */
     @Override
     public T getSelectedItem(int index) {
         if (selectedItems.isEmpty()) {
@@ -115,27 +172,35 @@ public class ListSelectionModel<T> implements IListSelectionModel<T> {
         }
     }
 
+    /**
+     * @return an unmodifiable list of all the selected items
+     */
     @Override
     public List<T> getSelectedItems() {
         return List.copyOf(selectedItems.values());
     }
 
+    /**
+     * @return the map property used for the selection
+     */
     @Override
     public MapProperty<Integer, T> selectedItemsProperty() {
         return this.selectedItems;
     }
 
+    /**
+     * @return true if allows multiple selection, false if not.
+     */
     @Override
     public boolean allowsMultipleSelection() {
         return allowsMultipleSelection;
     }
 
+    /**
+     * Sets the selection mode of the model, single or multiple.
+     */
     @Override
     public void setAllowsMultipleSelection(boolean multipleSelection) {
         this.allowsMultipleSelection = multipleSelection;
     }
-
-    protected ObservableMap<Integer, T> getObservableTreeMap() {
-        return FXCollections.observableMap(new TreeMap<>());
-    }
 }

+ 4 - 4
materialfx/src/main/java/io/github/palexdev/materialfx/selection/TableSelectionModel.java

@@ -51,14 +51,14 @@ public class TableSelectionModel<T> implements ITableSelectionModel<T> {
      * If the model is set to not allow multiple selection then we clear the list
      * and then add the item to it.
      *
-     * @param item the item to select
+     * @param row the row to select
      */
     @SuppressWarnings("unchecked")
-    protected void select(MFXTableRow<T> item) {
+    protected void select(MFXTableRow<T> row) {
         if (!allowsMultipleSelection) {
-            selectedItems.setAll(item);
+            selectedItems.setAll(row);
         } else {
-            selectedItems.add(item);
+            selectedItems.add(row);
         }
     }
 

+ 3 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/IListCheckModel.java

@@ -22,6 +22,9 @@ import javafx.beans.property.MapProperty;
 
 import java.util.List;
 
+/**
+ * Public API used by any {@code MFXFlowlessCheckListView}.
+ */
 public interface IListCheckModel<T> extends IListSelectionModel<T> {
     void check(int index, T data);
     void clearCheckedItem(int index);

+ 3 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/IListSelectionModel.java

@@ -23,6 +23,9 @@ import javafx.scene.input.MouseEvent;
 
 import java.util.List;
 
+/**
+ * Public API used by any {@code MFXFlowlessListView}.
+ */
 public interface IListSelectionModel<T> {
     void select(int index, T data, MouseEvent mouseEvent);
     void updateIndex(T data, int index);

+ 3 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXButtonSkin.java

@@ -47,6 +47,9 @@ public class MFXButtonSkin extends ButtonSkin {
     // Methods
     //================================================================================
 
+    /**
+     * Binds the button's ripple properties to the ripple generator ones.
+     */
     protected void setupRippleGenerator() {
         MFXButton button = (MFXButton) getSkinnable();
         RippleGenerator rippleGenerator = button.getRippleGenerator();

+ 13 - 8
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXComboBoxSkin.java

@@ -134,12 +134,10 @@ public class MFXComboBoxSkin<T> extends SkinBase<MFXComboBox<T>> {
     //================================================================================
 
     /**
-     * Adds listeners for: focus, selected value, maxPopupHeight and maxPopupWidth,
-     * selectedIndex and selectedItem properties, parent property.
+     * Calls the methods which define the control behavior.
      * <p>
-     * Adds bindings for: selected value, maxPopupHeight and maxPopupWidth,
-     * <p>
-     * Adds handlers for: focus, managePopup/hide the popup.
+     * See {@link #comboBehavior()}, {@link #selectionBehavior()},
+     * {@link #popupBehavior()}, {@link #listBehavior()}, {@link #iconBehavior()}
      */
     private void setBehavior() {
         comboBehavior();
@@ -194,7 +192,7 @@ public class MFXComboBoxSkin<T> extends SkinBase<MFXComboBox<T>> {
     }
 
     /**
-     * Specifies the behavior for selectedValue, listview selection, combo box selection and filtered list change.
+     * Specifies the behavior for combo box selection, listview selection and selectedValue.
      */
     private void selectionBehavior() {
         MFXComboBox<T> comboBox = getSkinnable();
@@ -311,7 +309,7 @@ public class MFXComboBoxSkin<T> extends SkinBase<MFXComboBox<T>> {
     }
 
     /**
-     * This method build the combo box popup and initializes the listview.
+     * This method builds the combo box popup and initializes the listview.
      */
     protected PopupControl buildPopup() {
         MFXComboBox<T> comboBox = getSkinnable();
@@ -326,6 +324,10 @@ public class MFXComboBoxSkin<T> extends SkinBase<MFXComboBox<T>> {
         return popupControl;
     }
 
+    /**
+     * Convenience method to manage the popup. If the popup is not showing
+     * gets the coordinates and calls show() otherwise hides it.
+     */
     private void managePopup() {
         MFXComboBox<T> comboBox = getSkinnable();
 
@@ -345,6 +347,9 @@ public class MFXComboBoxSkin<T> extends SkinBase<MFXComboBox<T>> {
         }
     }
 
+    /**
+     * Used to generate the ripple effect of the icon when an event filter consumes the event.
+     */
     private void forceRipple() {
         RippleGenerator rg = icon.getRippleGenerator();
         rg.setGeneratorCenterX(icon.getWidth() / 2);
@@ -382,7 +387,7 @@ public class MFXComboBoxSkin<T> extends SkinBase<MFXComboBox<T>> {
     /**
      * Sets the label text according to the combo box selected item.
      * <p>
-     * If the item is instance of {@code Labeled} then whe check if the item has a graphic != null
+     * If the item is instance of {@code Labeled} then we check if the item has a graphic != null
      * and use the item text. If that's not the case then we call toString on the item.
      */
     private void setValueLabel(T item) {

+ 0 - 1
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXDateCellSkin.java

@@ -35,7 +35,6 @@ public class MFXDateCellSkin extends DateCellSkin {
     //================================================================================
     // Properties
     //================================================================================
-
     private final RippleGenerator rippleGenerator;
 
     //================================================================================

+ 7 - 1
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXFilterComboBoxSkin.java

@@ -147,6 +147,9 @@ public class MFXFilterComboBoxSkin<T> extends SkinBase<MFXFilterComboBox<T>> {
 
     /**
      * Calls the methods which define the control behavior.
+     * <p>
+     * See {@link #comboBehavior()}, {@link #selectionBehavior()},
+     * {@link #popupBehavior()}, {@link #listBehavior()}, {@link #iconBehavior()}
      */
     private void setBehavior() {
         comboBehavior();
@@ -206,7 +209,7 @@ public class MFXFilterComboBoxSkin<T> extends SkinBase<MFXFilterComboBox<T>> {
     }
 
     /**
-     * Specifies the behavior for selectedValue, listview selection, combo box selection and filtered list change.
+     * Specifies the behavior for combo box selection, listview selection, and selectedValue.
      */
     private void selectionBehavior() {
         MFXFilterComboBox<T> comboBox = getSkinnable();
@@ -474,6 +477,9 @@ public class MFXFilterComboBoxSkin<T> extends SkinBase<MFXFilterComboBox<T>> {
         transition.play();
     }
 
+    /**
+     * Used to generate the ripple effect of the icon when an event filter consumes the event.
+     */
     private void forceRipple() {
         RippleGenerator rg = icon.getRippleGenerator();
         rg.setGeneratorCenterX(icon.getWidth() / 2);

+ 26 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXFlowlessListViewSkin.java

@@ -34,12 +34,21 @@ import javafx.scene.control.ScrollBar;
 import javafx.scene.control.SkinBase;
 import javafx.util.Duration;
 
+/**
+ * Implementation of the skin used by all list views based on Flowless.
+ */
 public class MFXFlowlessListViewSkin<T> extends SkinBase<AbstractFlowlessListView<T, ?, ?>> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final ScrollBar vBar;
     private final ScrollBar hBar;
     private Timeline hideBars;
     private Timeline showBars;
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXFlowlessListViewSkin(AbstractFlowlessListView<T, ?, ?> listView) {
         super(listView);
 
@@ -77,6 +86,13 @@ public class MFXFlowlessListViewSkin<T> extends SkinBase<AbstractFlowlessListVie
         setListeners();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
+
+    /**
+     * Calls {@link #setScrollBarHandlers()}, adds a listener to the list view's depth property.
+     */
     private void setListeners() {
         AbstractFlowlessListView<T, ?, ?> listView = getSkinnable();
 
@@ -88,6 +104,9 @@ public class MFXFlowlessListViewSkin<T> extends SkinBase<AbstractFlowlessListVie
         });
     }
 
+    /**
+     * Sets up the scroll bars behavior.
+     */
     private void setScrollBarHandlers() {
         AbstractFlowlessListView<T, ?, ?> listView = getSkinnable();
 
@@ -150,11 +169,18 @@ public class MFXFlowlessListViewSkin<T> extends SkinBase<AbstractFlowlessListVie
 
     }
 
+    /**
+     * Responsible for creating the cells contained by Flowless VirtualFlow,
+     * uses the list view's defined cell factory.
+     */
     protected AbstractMFXFlowlessListCell<T> createCell(T item) {
         AbstractFlowlessListView<T, ?, ?> listView = getSkinnable();
         return listView.getCellFactory().call(item);
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
         return leftInset + 200 + rightInset;

+ 7 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableColumnCellSkin.java

@@ -54,6 +54,9 @@ public class MFXTableColumnCellSkin<T> extends LabelSkin {
         setListeners();
     }
 
+    /**
+     * Adds listeners to the following properties: hasTooltipProperty
+     */
     @SuppressWarnings("unchecked")
     private void setListeners() {
         MFXTableColumnCell<T> column = (MFXTableColumnCell<T>) getSkinnable();
@@ -97,6 +100,10 @@ public class MFXTableColumnCellSkin<T> extends LabelSkin {
         }
     }
 
+    /**
+     * Responsible for building the column cell tooltip. By default creates
+     * a tooltip with the name of the column as text.
+     */
     @SuppressWarnings("unchecked")
     private Tooltip buildTooltip() {
         MFXTableColumnCell<T> column = (MFXTableColumnCell<T>) getSkinnable();

+ 64 - 26
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableViewSkin.java

@@ -49,6 +49,7 @@ import javafx.collections.transformation.SortedList;
 import javafx.geometry.Insets;
 import javafx.geometry.Pos;
 import javafx.scene.Node;
+import javafx.scene.control.Label;
 import javafx.scene.control.Skin;
 import javafx.scene.control.SkinBase;
 import javafx.scene.input.MouseButton;
@@ -57,6 +58,7 @@ import javafx.scene.layout.HBox;
 import javafx.scene.layout.Priority;
 import javafx.scene.layout.Region;
 import javafx.scene.layout.VBox;
+import javafx.scene.text.Font;
 import javafx.stage.Modality;
 import javafx.util.Duration;
 
@@ -204,8 +206,8 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
      * <p>
      * Adds bindings to:
      * <p>
-     * - filter icon disable property, bound to tableFiltered property.<p>
-     * - clear filter icon disable property, bound to tableFiltered.not() property.<p>
+     * - filter icon disable property, bound to tableFiltered property or listEmpty.<p>
+     * - clear filter icon disable property, bound to tableFiltered.not() property or listEmpty.<p>
      * <p>
      * Adds event handlers for:
      * <p>
@@ -217,7 +219,6 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
     private void setListeners() {
         MFXTableView<T> tableView = getSkinnable();
 
-        tableView.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> tableView.requestFocus());
         tableView.getItems().addListener((InvalidationListener) invalidated -> {
             tableView.getSelectionModel().clearSelection();
             if (tableFiltered.get()) {
@@ -227,16 +228,6 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
             sortedList = new SortedList<>(tableView.getItems(), prevComp);
             buildRows();
         });
-        tableView.addEventHandler(TableViewEvent.FORCE_UPDATE_EVENT, event -> {
-            tableView.getSelectionModel().clearSelection();
-            if (tableFiltered.get()) {
-                tableFiltered.set(false);
-            }
-            Comparator<? super T> prevComp = sortedList.getComparator();
-            sortedList = new SortedList<>(tableView.getItems(), prevComp);
-            buildRows();
-        });
-
         rowsPerPageCombo.selectedValueProperty().addListener((observable, oldValue, newValue) -> {
             if (!newValue.equals(oldValue)) {
                 index = 0;
@@ -253,6 +244,23 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
             }
         });
 
+        BooleanBinding listEmpty = Bindings.createBooleanBinding(
+                () -> tableView.getItems().isEmpty(),
+                tableView.getItems()
+        );
+        filterIcon.disableProperty().bind(tableFiltered.or(listEmpty));
+        clearFilterIcon.disableProperty().bind(tableFiltered.not().or(listEmpty));
+
+        tableView.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> tableView.requestFocus());
+        tableView.addEventHandler(TableViewEvent.FORCE_UPDATE_EVENT, event -> {
+            tableView.getSelectionModel().clearSelection();
+            if (tableFiltered.get()) {
+                tableFiltered.set(false);
+            }
+            Comparator<? super T> prevComp = sortedList.getComparator();
+            sortedList = new SortedList<>(tableView.getItems(), prevComp);
+            buildRows();
+        });
         filterIcon.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> filterDialog.show());
         clearFilterIcon.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> {
             if (tableFiltered.get()) {
@@ -260,13 +268,6 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
                 buildRows();
             }
         });
-
-        BooleanBinding listEmpty = Bindings.createBooleanBinding(
-                () -> tableView.getItems().isEmpty(),
-                tableView.getItems()
-        );
-        filterIcon.disableProperty().bind(tableFiltered.or(listEmpty));
-        clearFilterIcon.disableProperty().bind(tableFiltered.not().or(listEmpty));
     }
 
     /**
@@ -293,6 +294,17 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         }
     }
 
+    /**
+     * Adds a context menu to the columns.
+     * <p>
+     * The context menu contains the following actions:
+     * <p> - "Restore this column width"
+     * <p> - "Restore all columns width"
+     * <p> - "Autosize this column"
+     * <p> - "Autosize all columns"
+     *
+     * @see MFXContextMenu
+     */
     @SuppressWarnings("unchecked")
     protected void addContextMenu(MFXTableColumnCell<T> column) {
         MFXContextMenuItem restoreWidthThis = new MFXContextMenuItem(
@@ -330,6 +342,15 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
                 .install(column);
     }
 
+    /**
+     * Resize the given column so that all row cells' text of that column are visible.
+     * <p>
+     * Takes the column's index in the columnsContainer then takes all the shown rows,
+     * for each row gets the child at the retrieved column index (in short gets all the row cells of that column),
+     * then checks if the text is truncated with {@link LabelUtils#isLabelTruncated(Label)}, if true adds the cell
+     * to a temp list. Then calls {@link #getMaxCellWidth(List)} to compute which cell has the longest text and then sets
+     * the column minWidth to that computed value.
+     */
     @SuppressWarnings("unchecked")
     protected void autoSizeColumn(MFXTableColumnCell<T> column) {
         int index = columnsContainer.getChildren().indexOf(column);
@@ -352,6 +373,11 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         }
     }
 
+    /**
+     * Given a list of row cells computes which cell would be the widest if the text was not truncated.
+     * This width is computed with {@link LabelUtils#computeTextWidth(Font, String)}. To this value both
+     * right and left insets of the cell are added.
+     */
     protected double getMaxCellWidth(List<MFXTableRowCell> rowCells) {
         double max = -1;
         for (MFXTableRowCell rowCell : rowCells) {
@@ -393,7 +419,7 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         int i;
         int size = items.size();
         int pageIndex = tableView.getMaxRows() + index;
-        computeRowsContainerHeight(items.size() - index);
+        computeRowsContainerHeight(size - index);
 
         for (i = index; i < pageIndex && size > 0 && i < size; i++) {
             T item = items.get(i);
@@ -590,9 +616,11 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
     }
 
     /**
-     * Gets the selected items from that list, gets the row nodes in the rowsContainer,
-     * if the selected items contains the row item
-     * them the reference in the model is updated.
+     * Gets the selected items from the selection model, gets the row nodes in the rowsContainer,
+     * if the selected items contains the row item then the reference in the model is updated.
+     * <p></p>
+     * Unfortunately this kind of solution is necessary since the rows are rebuilt every time the page
+     * is changed.
      */
     @SuppressWarnings("unchecked")
     private void updateSelection() {
@@ -744,12 +772,22 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         filterDialog.close();
     }
 
-    private void computeRowsContainerHeight(int index) {
+    /**
+     * Ensures that the rows container has always a minimum height so that the table
+     * doesn't "collapse". The height computation is done when the items list is empty
+     * or there aren't enough rows to fill the page.
+     * <p>
+     * The height is computed like this: (topInset + fixedRowsHeight + bottomInset) * nrows.
+     * <p></p>
+     * Used by {@link #buildRows(List)}, the param is the number of rows that will be shown,
+     * and it's calculated as the passed list size minus the current row index.
+     */
+    private void computeRowsContainerHeight(int shownRows) {
         MFXTableView<T> tableView = getSkinnable();
 
         int nrows = rowsPerPageCombo.getSelectedValue() != null ? rowsPerPageCombo.getSelectedValue() : 5;
         double value = -1;
-        if (tableView.getItems().isEmpty() || index < nrows) {
+        if (tableView.getItems().isEmpty() || shownRows < nrows) {
             value = (rowsContainer.snappedTopInset() +
                     tableView.getFixedRowsHeight() +
                     rowsContainer.snappedBottomInset()) * nrows;