Przeglądaj źródła

Update documentation

MFXTableView: added a way to manually update the table displayed data. This is necessary especially when the model is not built with JavaFX's properties.
MFXTableColumnCellSkin: renamed icon methods, moved isRightAlignment method to NodeUtils class.
MFXTableViewSkin: added event handler for FORCE_UPDATE_EVENT, added listener to the columns rowCellFactory property in case it changes, moved isRightAlignment method to NodeUtils class, fixed updateSelection method.
MFXFilterDialog: removed useless isOr method.

NodeUtils: added new method and moved computeTextWidth method to LabelUtils
Signed-off-by: PAlex404 <alessandro.parisi406@gmail.com>
PAlex404 4 lat temu
rodzic
commit
8725640848
27 zmienionych plików z 795 dodań i 41 usunięć
  1. 56 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXComboBox.java
  2. 71 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXLabel.java
  3. 17 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXProgressBar.java
  4. 18 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableRow.java
  5. 51 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableView.java
  6. 21 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXTableColumnCell.java
  7. 34 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXTableRowCell.java
  8. 6 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/Styles.java
  9. 4 2
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyComboBox.java
  10. 14 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyTableRow.java
  11. 17 0
      materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyTableView.java
  12. 5 0
      materialfx/src/main/java/io/github/palexdev/materialfx/filter/IFilterable.java
  13. 93 4
      materialfx/src/main/java/io/github/palexdev/materialfx/filter/MFXFilterDialog.java
  14. 17 0
      materialfx/src/main/java/io/github/palexdev/materialfx/selection/ComboSelectionModelMock.java
  15. 3 0
      materialfx/src/main/java/io/github/palexdev/materialfx/selection/ITableSelectionModel.java
  16. 60 0
      materialfx/src/main/java/io/github/palexdev/materialfx/selection/TableSelectionModel.java
  17. 1 1
      materialfx/src/main/java/io/github/palexdev/materialfx/selection/TreeCheckModel.java
  18. 1 1
      materialfx/src/main/java/io/github/palexdev/materialfx/selection/TreeSelectionModel.java
  19. 31 2
      materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXComboBoxSkin.java
  20. 34 2
      materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXLabelSkin.java
  21. 32 2
      materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXProgressBarSkin.java
  22. 17 11
      materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableColumnCellSkin.java
  23. 155 8
      materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableViewSkin.java
  24. 9 0
      materialfx/src/main/java/io/github/palexdev/materialfx/utils/DragResizer.java
  25. 15 0
      materialfx/src/main/java/io/github/palexdev/materialfx/utils/LabelUtils.java
  26. 6 8
      materialfx/src/main/java/io/github/palexdev/materialfx/utils/NodeUtils.java
  27. 7 0
      materialfx/src/main/java/io/github/palexdev/materialfx/utils/StringUtils.java

+ 56 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXComboBox.java

@@ -35,7 +35,19 @@ import java.util.List;
 
 import static io.github.palexdev.materialfx.controls.enums.Styles.ComboBoxStyles;
 
+/**
+ * This is the implementation of a combo box following Google's material design guidelines in JavaFX.
+ * <p>
+ * Extends {@code Control} and provides a new skin since it is built from scratch.
+ * <p>
+ * Side note: unlike JavaFX's one this is NOT editable.
+ * @param <T> The type of the value that has been selected
+ * @see ComboSelectionModelMock
+ */
 public class MFXComboBox<T> extends Control {
+    //================================================================================
+    // Properties
+    //================================================================================
     private static final StyleablePropertyFactory<MFXComboBox<?>> FACTORY = new StyleablePropertyFactory<>(Control.getClassCssMetaData());
     private final String STYLE_CLASS = "mfx-combo-box";
     private String STYLESHEET;
@@ -50,6 +62,9 @@ public class MFXComboBox<T> extends Control {
 
     private final ComboSelectionModelMock<T> mockSelection;
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXComboBox() {
         this(FXCollections.observableArrayList());
     }
@@ -62,6 +77,9 @@ public class MFXComboBox<T> extends Control {
         initialize();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
 
@@ -81,6 +99,9 @@ public class MFXComboBox<T> extends Control {
         return selectedValue.get();
     }
 
+    /**
+     * The currently selected item.
+     */
     public ObjectProperty<T> selectedValueProperty() {
         return selectedValue;
     }
@@ -93,6 +114,9 @@ public class MFXComboBox<T> extends Control {
         return items.get();
     }
 
+    /**
+     * The list of items to show within the ComboBox popup.
+     */
     public ObjectProperty<ObservableList<T>> itemsProperty() {
         return items;
     }
@@ -105,6 +129,9 @@ public class MFXComboBox<T> extends Control {
         return maxPopupWidth.get();
     }
 
+    /**
+     * Specifies the max popup width. Set to -1 to autosize.
+     */
     public DoubleProperty maxPopupWidthProperty() {
         return maxPopupWidth;
     }
@@ -117,6 +144,9 @@ public class MFXComboBox<T> extends Control {
         return maxPopupHeight.get();
     }
 
+    /**
+     * Specifies the max popup height. Set to -1 to autosize.
+     */
     public DoubleProperty maxPopupHeightProperty() {
         return maxPopupHeight;
     }
@@ -129,6 +159,9 @@ public class MFXComboBox<T> extends Control {
         return popupXOffset.get();
     }
 
+    /**
+     * Specifies the x offset.
+     */
     public DoubleProperty popupXOffsetProperty() {
         return popupXOffset;
     }
@@ -141,6 +174,9 @@ public class MFXComboBox<T> extends Control {
         return popupYOffset.get();
     }
 
+    /**
+     * Specifies the y offset.
+     */
     public DoubleProperty popupYOffsetProperty() {
         return popupYOffset;
     }
@@ -149,10 +185,20 @@ public class MFXComboBox<T> extends Control {
         this.popupYOffset.set(popupYOffset);
     }
 
+    /**
+     * @return the selection model associated to this combo box
+     */
     public ComboSelectionModelMock<T> getSelectionModel() {
         return mockSelection;
     }
 
+    //================================================================================
+    // Styleable Properties
+    //================================================================================
+
+    /**
+     * Specifies the style of the MFXComboBox.
+     */
     private final StyleableObjectProperty<ComboBoxStyles> comboStyle = new SimpleStyleableObjectProperty<>(
             StyleableProperties.STYLE,
             this,
@@ -164,6 +210,9 @@ public class MFXComboBox<T> extends Control {
         return comboStyle.get();
     }
 
+    /**
+     * Specifies the style used by the combo box.
+     */
     public StyleableObjectProperty<ComboBoxStyles> comboStyleProperty() {
         return comboStyle;
     }
@@ -172,6 +221,10 @@ public class MFXComboBox<T> extends Control {
         this.comboStyle.set(comboStyle);
     }
 
+    //================================================================================
+    // CssMetaData
+    //================================================================================
+
     private static class StyleableProperties {
         private static final List<CssMetaData<? extends Styleable, ?>> cssMetaDataList;
 
@@ -192,6 +245,9 @@ public class MFXComboBox<T> extends Control {
         return StyleableProperties.cssMetaDataList;
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     protected Skin<?> createDefaultSkin() {
         return new MFXComboBoxSkin<>(this);

+ 71 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXLabel.java

@@ -38,7 +38,19 @@ import java.util.List;
 
 import static io.github.palexdev.materialfx.controls.enums.Styles.LabelStyles;
 
+/**
+ * This is the implementation of a label following Google's material design guidelines in JavaFX.
+ * <p>
+ * Extends {@code Control} and provides a new skin since it is built from scratch.
+ * <p>
+ * Side note: lacks some features like text wrapping, overrun and ellipsis but there are also
+ * new features like leading and trailing icons support, prompt text, changeable styles at runtime
+ * and it can also be set to editable like a text field (double click on the label to edit).
+ */
 public class MFXLabel extends Control {
+    //================================================================================
+    // Properties
+    //================================================================================
     private static final StyleablePropertyFactory<MFXLabel> FACTORY = new StyleablePropertyFactory<>(Control.getClassCssMetaData());
     private final String STYLE_CLASS = "mfx-label";
     private String STYLESHEET;
@@ -52,6 +64,9 @@ public class MFXLabel extends Control {
 
     private final ObjectProperty<Pos> alignment = new SimpleObjectProperty<>(Pos.CENTER_LEFT);
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXLabel() {
         this("");
     }
@@ -62,6 +77,9 @@ public class MFXLabel extends Control {
         initialize();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
 
@@ -77,6 +95,9 @@ public class MFXLabel extends Control {
         });
     }
 
+    /**
+     * @return the Label node wrapped by MFXLabel which has the text
+     */
     public Label getTextNode() {
         return (Label) lookup(".text-node");
     }
@@ -85,6 +106,9 @@ public class MFXLabel extends Control {
         return text.get();
     }
 
+    /**
+     * The text to display in the label.
+     */
     public StringProperty textProperty() {
         return text;
     }
@@ -97,6 +121,9 @@ public class MFXLabel extends Control {
         return promptText.get();
     }
 
+    /**
+     * The prompt text to display in case the {@link #textProperty()} is empty.
+     */
     public StringProperty promptTextProperty() {
         return promptText;
     }
@@ -109,6 +136,9 @@ public class MFXLabel extends Control {
         return font.get();
     }
 
+    /**
+     * The font to use for the text.
+     */
     public ObjectProperty<Font> fontProperty() {
         return font;
     }
@@ -121,6 +151,9 @@ public class MFXLabel extends Control {
         return labelAlignment.get();
     }
 
+    /**
+     * The alignment of the label's text.
+     */
     public ObjectProperty<Pos> labelAlignmentProperty() {
         return labelAlignment;
     }
@@ -133,6 +166,9 @@ public class MFXLabel extends Control {
         return leadingIcon.get();
     }
 
+    /**
+     * The leading icon node.
+     */
     public ObjectProperty<Node> leadingIconProperty() {
         return leadingIcon;
     }
@@ -145,6 +181,9 @@ public class MFXLabel extends Control {
         return trailingIcon.get();
     }
 
+    /**
+     * The trailing icon node.
+     */
     public ObjectProperty<Node> trailingIconProperty() {
         return trailingIcon;
     }
@@ -153,6 +192,9 @@ public class MFXLabel extends Control {
         return alignment.get();
     }
 
+    /**
+     * The alignment of the container.
+     */
     public ObjectProperty<Pos> alignmentProperty() {
         return alignment;
     }
@@ -165,6 +207,13 @@ public class MFXLabel extends Control {
         this.trailingIcon.set(trailingIcon);
     }
 
+    //================================================================================
+    // Styleable Properties
+    //================================================================================
+
+    /**
+     * Specifies the style of the MFXLabel.
+     */
     private final StyleableObjectProperty<LabelStyles> labelStyle = new SimpleStyleableObjectProperty<>(
             StyleableProperties.STYLE,
             this,
@@ -172,6 +221,9 @@ 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,
@@ -179,6 +231,9 @@ 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,
@@ -186,6 +241,9 @@ public class MFXLabel extends Control {
             false
     );
 
+    /**
+     * Specifies if focus lines should be animated.
+     */
     private final StyleableBooleanProperty animateLines = new SimpleStyleableBooleanProperty(
             StyleableProperties.ANIMATE_LINES,
             this,
@@ -193,6 +251,9 @@ public class MFXLabel extends Control {
             true
     );
 
+    /**
+     * Specifies the focusedLine color.
+     */
     private final StyleableObjectProperty<Paint> lineColor = new SimpleStyleableObjectProperty<>(
             StyleableProperties.LINE_COLOR,
             this,
@@ -200,6 +261,9 @@ 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,
@@ -279,6 +343,9 @@ public class MFXLabel extends Control {
         this.unfocusedLineColor.set(unfocusedLineColor);
     }
 
+    //================================================================================
+    // CssMetaData
+    //================================================================================
     private static class StyleableProperties {
         private static final List<CssMetaData<? extends Styleable, ?>> cssMetaDataList;
 
@@ -333,10 +400,14 @@ public class MFXLabel extends Control {
         }
     }
 
+
     public static List<CssMetaData<? extends Styleable, ?>> getControlCssMetaDataList() {
         return StyleableProperties.cssMetaDataList;
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     protected Skin<?> createDefaultSkin() {
         return new MFXLabelSkin(this);

+ 17 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXProgressBar.java

@@ -23,10 +23,21 @@ import io.github.palexdev.materialfx.skins.MFXProgressBarSkin;
 import javafx.scene.control.ProgressBar;
 import javafx.scene.control.Skin;
 
+/**
+ * This is the implementation of a progress bar following Google's material design guidelines.
+ * <p>
+ * Extends {@code ProgressBar} and redefines the style class to "mfx-progress-bar" for usage in CSS.
+ */
 public class MFXProgressBar extends ProgressBar {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final String STYLE_CLASS = "mfx-progress-bar";
     private final String STYLESHEETS = MFXResourcesLoader.load("css/mfx-progressbar.css").toString();
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXProgressBar() {
         initialize();
     }
@@ -36,11 +47,17 @@ public class MFXProgressBar extends ProgressBar {
         initialize();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
         setPrefWidth(200);
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     protected Skin<?> createDefaultSkin() {
         return new MFXProgressBarSkin(this);

+ 18 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableRow.java

@@ -26,7 +26,16 @@ import javafx.geometry.Pos;
 import javafx.scene.Node;
 import javafx.scene.layout.HBox;
 
+/**
+ * This is the implementation of the rows used in every {@link MFXTableView}.
+ * <p>
+ * This class contains the reference to the represented item and allows the selection of
+ * the row and the item.
+ */
 public class MFXTableRow<T> extends HBox {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final String STYLE_CLASS = "mfx-table-row";
     private final String STYLESHEET = MFXResourcesLoader.load("css/mfx-table-row.css").toString();
     private final T item;
@@ -34,6 +43,9 @@ public class MFXTableRow<T> extends HBox {
     private static final PseudoClass SELECTED_PSEUDO_CLASS = PseudoClass.getPseudoClass("selected");
     private final BooleanProperty selected = new SimpleBooleanProperty(false);
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXTableRow(T item) {
         this.item = item;
         initialize();
@@ -64,6 +76,9 @@ public class MFXTableRow<T> extends HBox {
         initialize();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
         addListeners();
@@ -89,6 +104,9 @@ public class MFXTableRow<T> extends HBox {
         this.selected.set(selected);
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     public String getUserAgentStylesheet() {
         return STYLESHEET;

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

@@ -29,10 +29,21 @@ import javafx.beans.property.SimpleIntegerProperty;
 import javafx.beans.property.SimpleObjectProperty;
 import javafx.collections.FXCollections;
 import javafx.collections.ObservableList;
+import javafx.event.Event;
+import javafx.event.EventType;
 import javafx.scene.control.Control;
 import javafx.scene.control.Skin;
 
+/**
+ * This is the implementation of a table view following Google's material design guidelines in JavaFX.
+ * <p>
+ * Extends {@code Control} and provides a new skin since it is built from scratch.
+ * @param <T> The type of the data within the table.
+ */
 public class MFXTableView<T> extends Control {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final String STYLE_CLASS = "mfx-table-view";
     private final String STYLESHEET = MFXResourcesLoader.load("css/mfx-tableview.css").toString();
 
@@ -44,6 +55,9 @@ public class MFXTableView<T> extends Control {
     private final IntegerProperty maxRowsCombo = new SimpleIntegerProperty(20);
     private final double fixedRowsHeight;
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXTableView() {
         installSelectionModel();
 
@@ -58,10 +72,16 @@ public class MFXTableView<T> extends Control {
         initialize();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
     }
 
+    /**
+     * Installs the default selection model in this table view.
+     */
     protected void installSelectionModel() {
         ITableSelectionModel<T> selectionModel = new TableSelectionModel<>();
         selectionModel.setAllowsMultipleSelection(true);
@@ -92,6 +112,9 @@ public class MFXTableView<T> extends Control {
         return maxRows.get();
     }
 
+    /**
+     * Specifies the max rows per page.
+     */
     public IntegerProperty maxRowsProperty() {
         return maxRows;
     }
@@ -100,6 +123,9 @@ public class MFXTableView<T> extends Control {
         return maxRowsCombo.get();
     }
 
+    /**
+     * Specifies the max value in the combo box.
+     */
     public IntegerProperty maxRowsComboProperty() {
         return maxRowsCombo;
     }
@@ -112,6 +138,9 @@ public class MFXTableView<T> extends Control {
         return fixedRowsHeight;
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     protected Skin<?> createDefaultSkin() {
         return new MFXTableViewSkin<>(this);
@@ -121,4 +150,26 @@ public class MFXTableView<T> extends Control {
     public String getUserAgentStylesheet() {
         return STYLESHEET;
     }
+
+    //================================================================================
+    // Events Class
+    //================================================================================
+
+    /**
+     * Events class for the table view.
+     * <p>
+     * Defines a new EventType:
+     * <p>
+     * - FORCE_UPDATE_EVENT: this event is captures by the table view's skin to force an update
+     * of the rows. This is useful when the model is not based on JavaFX's properties because when
+     * some item changes the data is not updated automatically, so it must be done manually.
+     * <p>
+     */
+    public static class TableViewEvent extends Event {
+        public static final EventType<TableViewEvent> FORCE_UPDATE_EVENT = new EventType<>(ANY, "FORCE_UPDATE_EVENT");
+
+        public TableViewEvent(EventType<? extends Event> eventType) {
+            super(eventType);
+        }
+    }
 }

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

@@ -31,7 +31,19 @@ import javafx.util.Callback;
 
 import java.util.Comparator;
 
+/**
+ * This is the implementation of the column cells used in the {@link io.github.palexdev.materialfx.controls.MFXTableView} columns header.
+ * <p>
+ * Each column cell is a {@code Label}, has a name and has the following responsibilities:
+ * - Has a row cell factory because each column knows how to build the corresponding row cell in each table row<p>
+ * - Has a sort state and a comparator because each column knows how to sort the rows based on the given comparator, also
+ *      retains its sort state thus allowing switching between ASCENDING, DESCENDING, UNSORTED<p>
+ *
+ */
 public class MFXTableColumnCell<T> extends Label {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final String STYLE_CLASS = "mfx-table-column-cell";
     private final String STYLESHEET = MFXResourcesLoader.load("css/mfx-table-column-cell.css").toString();
 
@@ -41,6 +53,9 @@ public class MFXTableColumnCell<T> extends Label {
     private SortState sortState = SortState.UNSORTED;
     private Comparator<T> comparator;
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXTableColumnCell(String columnName) {
         textProperty().bind(columnNameProperty());
         setColumnName(columnName);
@@ -54,6 +69,9 @@ public class MFXTableColumnCell<T> extends Label {
         initialize();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
     }
@@ -98,6 +116,9 @@ public class MFXTableColumnCell<T> extends Label {
         this.comparator = comparator;
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     protected Skin<?> createDefaultSkin() {
         return new MFXTableColumnCellSkin<>(this);

+ 34 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXTableRowCell.java

@@ -23,10 +23,38 @@ import javafx.beans.binding.StringBinding;
 import javafx.beans.property.StringProperty;
 import javafx.scene.control.Label;
 
+/**
+ * This is the implementation of the row cells used in every {@link io.github.palexdev.materialfx.controls.MFXTableView} row.
+ * The row cell is built by the corresponding {@link MFXTableColumnCell}.
+ * <p>
+ * Each row cell is a {@code Label} and provides a series of constructors offering support from simple {@code Strings} to
+ * JavaFX's {@code StringProperties} and {@code StringBindings}. This allows to use {@code MFXTableView} with models which
+ * don't use JavaFX's properties.
+ * <p></p>
+ * Beware though, the data won't be automatically updated if it changes.
+ * <p>
+ * In that case you must manually update the table firing a TableViewEvent.FORCE_UPDATE event on it.
+ * <p>
+ * After the data changed like this:
+ * <pre>
+ * {@code
+ * ObservableList<Items> list = ...;
+ * MFXTableView tableView = new MFXTableView(list);
+ *
+ * tableView.fireEvent(new MFXTableView.TableViewEvent(MFXTableView.TableViewEvent.FORCE_UPDATE_EVENT));
+ * }
+ * </pre>
+ */
 public class MFXTableRowCell extends Label {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final String STYLE_CLASS = "mfx-table-row-cell";
     private final String STYLESHEET = MFXResourcesLoader.load("css/mfx-table-row-cell.css").toString();
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXTableRowCell(String text) {
         super(text);
         initialize();
@@ -42,10 +70,16 @@ public class MFXTableRowCell extends Label {
         initialize();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     public String getUserAgentStylesheet() {
         return STYLESHEET;

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

@@ -18,6 +18,12 @@
 
 package io.github.palexdev.materialfx.controls.enums;
 
+/**
+ * This class contains various enumerators used in MaterialFX controls which
+ * support two or more styles that can be changed at runtime.
+ * <p>
+ * These emulators basically are just helpers that store the path to the right css file.
+ */
 public class Styles {
     public enum ComboBoxStyles {
         STYLE1("css/mfx-combobox-style1.css"),

+ 4 - 2
materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyComboBox.java

@@ -39,9 +39,11 @@ import javafx.scene.paint.Paint;
 import java.util.List;
 
 /**
- * This is the implementation of a combo box following Google's material design guidelines in JavaFX.
+ * This is a restyle of the JavaFX's combo box.
  * <p>
- * Extends {@code ComboBox}, redefines the style class to "mfx-combo-box" for usage in CSS and
+ * For a combo box which more closely follows the guidelines of material design see {@link io.github.palexdev.materialfx.controls.MFXComboBox}.
+ * <p>
+ * Extends {@code ComboBox}, redefines the style class to "mfx-legacy-combo-box" for usage in CSS and
  * includes a {@link MFXDialogValidator}.
  * <p></p>
  * A few notes on features and usage:

+ 14 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyTableRow.java

@@ -34,12 +34,23 @@ import javafx.util.Duration;
 
 import java.util.List;
 
+/**
+ * This is a restyle of JavaFX's {@link TableRow} control.
+ * <p>
+ * For a table view which more closely follows the guidelines of material design see {@link io.github.palexdev.materialfx.controls.MFXTableView}.
+ */
 public class MFXLegacyTableRow<T> extends TableRow<T> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private static final StyleablePropertyFactory<MFXLegacyTableRow<?>> FACTORY = new StyleablePropertyFactory<>(TableRow.getClassCssMetaData());
     private final String STYLE_CLASS = "mfx-legacy-table-row";
     private final String STYLESHEET = MFXResourcesLoader.load("css/legacy/mfx-tablerow.css").toString();
     private final RippleGenerator rippleGenerator;
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXLegacyTableRow() {
         rippleGenerator = new RippleGenerator(this);
         rippleGenerator.setRippleColor(Color.rgb(50, 150, 255));
@@ -48,6 +59,9 @@ public class MFXLegacyTableRow<T> extends TableRow<T> {
         initialize();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
 

+ 17 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyTableView.java

@@ -24,10 +24,21 @@ import javafx.collections.ObservableList;
 import javafx.scene.control.Skin;
 import javafx.scene.control.TableView;
 
+/**
+ * This is a restyle of JavaFX's {@link TableView} control.
+ * For a table view which more closely follows the guidelines of material design see {@link io.github.palexdev.materialfx.controls.MFXTableView}.
+ * @param <S>
+ */
 public class MFXLegacyTableView<S> extends TableView<S> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final String STYLE_CLASS = "mfx-legacy-table-view";
     private final String STYLESHEET = MFXResourcesLoader.load("css/legacy/mfx-tableview.css").toString();
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXLegacyTableView() {
         initialize();
     }
@@ -37,12 +48,18 @@ public class MFXLegacyTableView<S> extends TableView<S> {
         initialize();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
         setRowFactory(row -> new MFXLegacyTableRow<>());
         setFixedCellSize(27);
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     protected Skin<?> createDefaultSkin() {
         return new MFXLegacyTableViewSkin<>(this);

+ 5 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/filter/IFilterable.java

@@ -18,6 +18,11 @@
 
 package io.github.palexdev.materialfx.filter;
 
+/**
+ * This interface allows filtering a {@link io.github.palexdev.materialfx.controls.MFXTableView} without
+ * using an object {@code toString()} method but rather using a specific method.
+ *
+ */
 public interface IFilterable {
     String toFilterString();
 }

+ 93 - 4
materialfx/src/main/java/io/github/palexdev/materialfx/filter/MFXFilterDialog.java

@@ -52,7 +52,31 @@ import java.util.Map;
 import java.util.function.BiPredicate;
 import java.util.stream.Collectors;
 
+/**
+ * This dialog allows implements a filtering mechanism based on boolean
+ * expressions on strings.
+ * <p>
+ * Since {@link MFXStageDialog} can't be extended in this case because the constructors need
+ * a {@code MFXDialog}, it extends {@link MFXDialog}, builds the stage dialog passing itself as reference
+ * and overrides the open() and close() methods to use the {@link MFXStageDialog} ones.
+ * <p></p>
+ * <b>Structure</b>
+ * <p>
+ * A label allows to add a new HBox which contains: an icon to remove itself if not needed anymore,
+ * two toggles to specify if the expression should an "AND" or an "OR" condition, a combo box to choose
+ * the function to apply on the passed string and the given string, one or more text fields
+ * which contain the text used in the evaluations, and a button, {@link #getFilterButton()}.
+ * <p>
+ * <b>Functioning</b>
+ * <p>
+ * The main method is {@link #filter(String)}. It takes a string and evaluates all the given conditions
+ * on that string, returning the computed boolean result.
+ *
+ */
 public class MFXFilterDialog extends MFXDialog {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final String STYLE_CLASS = "mfx-filter-dialog";
     private final String STYLESHEET = MFXResourcesLoader.load("css/mfx-filter-dialog.css").toString();
 
@@ -63,6 +87,9 @@ public class MFXFilterDialog extends MFXDialog {
     private final MFXStageDialog stage;
     private final MFXIconWrapper closeIcon;
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXFilterDialog() {
         setTitle("Filter Dialog");
         setPrefWidth(550);
@@ -128,10 +155,16 @@ public class MFXFilterDialog extends MFXDialog {
         getChildren().add(closeIcon);
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private void initialize() {
         getStyleClass().add(STYLE_CLASS);
     }
 
+    /**
+     * Adds a new {@code FilterField} to the dialog.
+     */
     protected void addTextField() {
         FilterField filterField = new FilterField();
         filterField.getRemoveIcon().addEventHandler(MouseEvent.MOUSE_PRESSED, event -> {
@@ -143,6 +176,11 @@ public class MFXFilterDialog extends MFXDialog {
         textFieldsContainer.getChildren().add(filterField);
     }
 
+    /**
+     * Evaluates all the conditions specified by the dialog's {@code FilterFields} on
+     * the given item and returns if it meets the specified conditions or not.
+     * @param item the string on which evaluate the conditions
+     */
     public boolean filter(String item) {
         List<FilterField> filterFields = textFieldsContainer.getChildren().stream()
                 .filter(node -> node instanceof FilterField)
@@ -168,14 +206,26 @@ public class MFXFilterDialog extends MFXDialog {
         return expression != null ? expression : false;
     }
 
+    /**
+     * Returns the dialog's button reference.
+     * <p>
+     * In {@link io.github.palexdev.materialfx.skins.MFXTableViewSkin} for example, it is used
+     * to add an event handler to the button which starts the filtering and closes the dialog.
+     */
     public MFXButton getFilterButton() {
         return filterButton;
     }
 
+    /**
+     * @return the stage dialog reference.
+     */
     public MFXStageDialog getStage() {
         return stage;
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     public String getUserAgentStylesheet() {
         return STYLESHEET;
@@ -188,17 +238,34 @@ public class MFXFilterDialog extends MFXDialog {
         closeIcon.relocate(getWidth() - 17, 17);
     }
 
+    /**
+     * Shows the stage dialog.
+     */
     @Override
     public void show() {
         stage.show();
     }
 
+    /**
+     * Closes the stage dialog.
+     */
     @Override
     public void close() {
         stage.close();
     }
 
+    /**
+     * This is the class used in the filter dialog for the filter boxes.
+     * <p>
+     * It's this node which contains the remove icon, the toggles, the combo box and the text field.
+     * <p>
+     * It uses a {@code Map<String, BiPredicate<String, String>>} to map the combo box choice to the function
+     * which will we applied on the given strings, {@link MFXFilterDialog#filter(String)}.
+     */
     private class FilterField extends HBox {
+        //================================================================================
+        // Properties
+        //================================================================================
         private final Map<String, BiPredicate<String, String>> evaluators = new LinkedHashMap<>();
 
         private final MFXIconWrapper icon;
@@ -207,6 +274,9 @@ public class MFXFilterDialog extends MFXDialog {
 
         private final BooleanProperty isAnd = new SimpleBooleanProperty(true);
 
+        //================================================================================
+        // Constructors
+        //================================================================================
         public FilterField() {
             populateMap();
             getStylesheets().addAll(STYLESHEET);
@@ -239,6 +309,9 @@ public class MFXFilterDialog extends MFXDialog {
             getChildren().addAll(icon, buildOptions(), textField);
         }
 
+        //================================================================================
+        // Methods
+        //================================================================================
         private Node buildOptions() {
             HBox box = new HBox(5);
 
@@ -278,6 +351,17 @@ public class MFXFilterDialog extends MFXDialog {
             return box;
         }
 
+        /**
+         * Populates the map with:
+         * <p>
+         * - Contains -> String::contains <p>
+         * - Contains Ignore Case -> StringUtils::containsIgnoreCase <p>
+         * - Starts With -> String::startsWith <p>
+         * - Ends With -> String::endsWith <p>
+         * - Equals -> String::equals <p>
+         * - Equals Ignore Case -> String::equalsIgnoreCase <p>
+         * @see StringUtils
+         */
         private void populateMap() {
             evaluators.put("Contains", String::contains);
             evaluators.put("Contains Ignore Case", StringUtils::containsIgnoreCase);
@@ -291,16 +375,21 @@ public class MFXFilterDialog extends MFXDialog {
             return icon;
         }
 
+        /**
+         * Retrieves the BiPredicate from the map with the combo box selected value as key and
+         * applies the function to the given string.
+         */
         public Boolean callEvaluation(String item) {
             return evaluators.get(evaluationCombo.getSelectedValue()).test(item, textField.getText());
         }
 
+        /**
+         * Returns whether the selected toggle is the "And" toggle,
+         * if it is false then the selected toggle is the "Or" toggle because
+         * the toggles are in a group which uses {@link ToggleButtonsUtil#addAlwaysOneSelectedSupport(ToggleGroup)}
+         */
         public boolean isAnd() {
             return isAnd.get();
         }
-
-        public boolean isOr() {
-            return !isAnd();
-        }
     }
 }

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

@@ -22,15 +22,32 @@ import io.github.palexdev.materialfx.controls.MFXComboBox;
 import javafx.beans.property.ReadOnlyIntegerWrapper;
 import javafx.beans.property.ReadOnlyObjectWrapper;
 
+/**
+ * Rather than recreating and adapting the entire JavaFX's selection model for usage
+ * in {@link MFXComboBox} we "mock" it. The combo box listview selection model is bound to this one
+ * and vice versa.
+ * <p></p>
+ * <b>Note: if the select methods do not work try adding a listener to the skin property
+ * of the control and using the methods there.</b>
+ */
 public class ComboSelectionModelMock<T> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final MFXComboBox<T> comboBox;
     private final ReadOnlyObjectWrapper<T> selectedItem = new ReadOnlyObjectWrapper<>(null);
     private final ReadOnlyIntegerWrapper selectedIndex = new ReadOnlyIntegerWrapper(-1);
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public ComboSelectionModelMock(MFXComboBox<T> comboBox) {
         this.comboBox = comboBox;
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     public void clearSelection() {
         selectedItem.set(null);
         selectedIndex.set(-1);

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

@@ -4,6 +4,9 @@ import io.github.palexdev.materialfx.controls.MFXTableRow;
 import javafx.beans.property.ListProperty;
 import javafx.scene.input.MouseEvent;
 
+/**
+ * Public API used by any {@code MFXTableView}.
+ */
 public interface ITableSelectionModel<T> {
     void select(MFXTableRow<T> row, MouseEvent mouseEvent);
     void clearSelection();

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

@@ -10,10 +10,21 @@ import javafx.scene.input.MouseEvent;
 import java.util.ArrayList;
 import java.util.List;
 
+/**
+ * Concrete implementation of the {@code ITableSelectionModel} interface.
+ * <p>
+ * Basic selection model, allows to: clear the selection, single and multiple selection of {@link MFXTableRow}s.
+ */
 public class TableSelectionModel<T> implements ITableSelectionModel<T> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final ListProperty<MFXTableRow<T>> selectedItems = new SimpleListProperty<>(FXCollections.observableArrayList());
     private boolean allowsMultipleSelection = false;
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public TableSelectionModel() {
         selectedItems.addListener((ListChangeListener<MFXTableRow<T>>) change -> {
             List<MFXTableRow<T>> tmpRemoved = new ArrayList<>();
@@ -28,6 +39,19 @@ public class TableSelectionModel<T> implements ITableSelectionModel<T> {
         });
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
+
+    /**
+     * This method is called when the mouseEvent argument passed to
+     * {@link #select(MFXTableRow, MouseEvent)} is null.
+     * <p>
+     * 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
+     */
     @SuppressWarnings("unchecked")
     protected void select(MFXTableRow<T> item) {
         if (!allowsMultipleSelection) {
@@ -38,6 +62,25 @@ public class TableSelectionModel<T> implements ITableSelectionModel<T> {
         }
     }
 
+    //================================================================================
+    // Methods Implementation
+    //================================================================================
+
+    /**
+     * This method is called by {@link io.github.palexdev.materialfx.skins.MFXTableViewSkin} when
+     * the mouse is pressed on a row. We need the mouse event as a parameter in case multiple selection is
+     * allowed because we need to check if the Shift key or Ctrl key were pressed.
+     * <p>
+     * If the mouseEvent is null we call the other {@link #select(MFXTableRow)} method.
+     * <p>
+     * If the selection is single {@link #clearSelection()} we clear the selection
+     * and add the new selected item to the list.
+     * <p>
+     * If the selection is multiple we check if the item was already selected,
+     * if that is the case by default the item is deselected.
+     * <p>
+     * In case neither Shift nor Ctrl are pressed we clear the selection.
+     */
     @SuppressWarnings("unchecked")
     @Override
     public void select(MFXTableRow<T> row, MouseEvent mouseEvent) {
@@ -65,6 +108,9 @@ public class TableSelectionModel<T> implements ITableSelectionModel<T> {
         }
     }
 
+    /**
+     * Resets every item in the list to selected false and then clears the list.
+     */
     @Override
     public void clearSelection() {
         if (selectedItems.isEmpty()) {
@@ -75,6 +121,11 @@ public class TableSelectionModel<T> implements ITableSelectionModel<T> {
         selectedItems.clear();
     }
 
+    /**
+     * Gets the selected row. If the selection is multiple {@link #getSelectedRows()} ()} should be
+     * called instead, as this method will only return the first item of the list.
+     * @return the first selected item of the list
+     */
     @Override
     public MFXTableRow<T> getSelectedRow() {
         if (selectedItems.isEmpty()) {
@@ -83,16 +134,25 @@ public class TableSelectionModel<T> implements ITableSelectionModel<T> {
         return selectedItems.get(0);
     }
 
+    /**
+     * @return the ListProperty which contains all the selected items.
+     */
     @Override
     public ListProperty<MFXTableRow<T>> getSelectedRows() {
         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;

+ 1 - 1
materialfx/src/main/java/io/github/palexdev/materialfx/selection/TreeCheckModel.java

@@ -33,7 +33,7 @@ import java.util.stream.Collectors;
 import static io.github.palexdev.materialfx.controls.MFXCheckTreeItem.CheckTreeItemEvent;
 
 /**
- * Concrete implementation of the {@code ITreeCheckModel} class.
+ * Concrete implementation of the {@code ITreeCheckModel} interface.
  * <p>
  * This provides common methods for items check. Also, since it extends TreeSelectionModel it also provides
  * all the methods for items selection.

+ 1 - 1
materialfx/src/main/java/io/github/palexdev/materialfx/selection/TreeSelectionModel.java

@@ -31,7 +31,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 /**
- * Concrete implementation of the {@code ITreeSelectionModel} class.
+ * Concrete implementation of the {@code ITreeSelectionModel} interface.
  * <p>
  * This provides common methods for items selection.
  * <p>

+ 31 - 2
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXComboBoxSkin.java

@@ -39,7 +39,13 @@ import javafx.scene.input.MouseEvent;
 import javafx.scene.layout.HBox;
 import javafx.util.Duration;
 
+/**
+ * This is the implementation of the Skin associated with every {@code MFXComboBox}.
+ */
 public class MFXComboBoxSkin<T> extends SkinBase<MFXComboBox<T>> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final HBox container;
     private final Label valueLabel;
     private final double minWidth = 100;
@@ -51,6 +57,9 @@ public class MFXComboBoxSkin<T> extends SkinBase<MFXComboBox<T>> {
 
     private Timeline arrowAnimation;
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXComboBoxSkin(MFXComboBox<T> comboBox) {
         super(comboBox);
 
@@ -87,7 +96,19 @@ public class MFXComboBoxSkin<T> extends SkinBase<MFXComboBox<T>> {
             listView.maxWidthProperty().unbind();
         }
     }
-
+    //================================================================================
+    // Methods
+    //================================================================================
+
+    /**
+     * Adds listeners for: focus, selected value, maxPopupHeight and maxPopupWidth,
+     * selectedIndex and selectedItem properties, parent property.
+     * <p>
+     * Adds bindings for: selected value, maxPopupHeight and maxPopupWidth,
+     * <p>
+     * Adds handlers for: focus, show/hide the popup.
+     *
+     */
     private void setListeners() {
         MFXComboBox<T> comboBox = getSkinnable();
         RippleGenerator rg = icon.getRippleGenerator();
@@ -195,6 +216,9 @@ public class MFXComboBoxSkin<T> extends SkinBase<MFXComboBox<T>> {
         });
     }
 
+    /**
+     * Builds the popup content.
+     */
     protected void buildPopup() {
         MFXComboBox<T> comboBox = getSkinnable();
 
@@ -204,6 +228,9 @@ public class MFXComboBoxSkin<T> extends SkinBase<MFXComboBox<T>> {
         popup.setOnHiding(event -> buildAnimation(false).play());
     }
 
+    /**
+     * Builds the animation for the combo box arrow.
+     */
     private Timeline buildAnimation(boolean isShowing) {
         KeyFrame kf0 = new KeyFrame(Duration.millis(150),
                 new KeyValue(icon.rotateProperty(), (isShowing ? 180 : 0))
@@ -212,6 +239,9 @@ public class MFXComboBoxSkin<T> extends SkinBase<MFXComboBox<T>> {
         return arrowAnimation;
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
         return leftInset + minWidth + rightInset;
@@ -248,7 +278,6 @@ public class MFXComboBoxSkin<T> extends SkinBase<MFXComboBox<T>> {
         double iconWidth = icon.getPrefWidth();
         double iconHeight = icon.getPrefHeight();
         double center = ((snappedTopInset() + snappedBottomInset()) / 2.0) + ((contentHeight - iconHeight) / 2.0);
-        System.out.println(center);
         icon.resizeRelocate(contentWidth - iconWidth, center, iconWidth, iconHeight);
     }
 }

+ 34 - 2
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXLabelSkin.java

@@ -22,7 +22,7 @@ import io.github.palexdev.materialfx.controls.MFXLabel;
 import io.github.palexdev.materialfx.controls.MFXTextField;
 import io.github.palexdev.materialfx.controls.enums.Styles;
 import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory;
-import io.github.palexdev.materialfx.utils.NodeUtils;
+import io.github.palexdev.materialfx.utils.LabelUtils;
 import javafx.animation.ScaleTransition;
 import javafx.beans.binding.Bindings;
 import javafx.geometry.Insets;
@@ -38,13 +38,22 @@ import javafx.scene.paint.Color;
 import javafx.scene.shape.Line;
 import javafx.util.Duration;
 
+/**
+ * This is the implementation of the Skin associated with every {@code MFXLabel}.
+ */
 public class MFXLabelSkin extends SkinBase<MFXLabel> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final HBox container;
     private final Label text;
 
     private final Line unfocusedLine;
     private final Line focusedLine;
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXLabelSkin(MFXLabel label) {
         super(label);
 
@@ -68,7 +77,7 @@ public class MFXLabelSkin extends SkinBase<MFXLabel> {
         text.setText(label.getText().isEmpty() ? label.getPromptText() : label.getText());
         text.fontProperty().bind(label.fontProperty());
         text.alignmentProperty().bind(label.labelAlignmentProperty());
-        text.minWidthProperty().bind(Bindings.createDoubleBinding(() -> NodeUtils.computeTextWidth(text.getFont(), text.getText()),
+        text.minWidthProperty().bind(Bindings.createDoubleBinding(() -> LabelUtils.computeTextWidth(text.getFont(), text.getText()),
                 label.textProperty(), label.fontProperty())
         );
 
@@ -97,6 +106,15 @@ public class MFXLabelSkin extends SkinBase<MFXLabel> {
         label.setPadding(new Insets(0, 10, 0, 10));
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
+
+    /**
+     * Adds listeners for: label style, text property, leading and trailing icons, focus.
+     * <p>
+     * Adds handlers for: focus, show editor.
+     */
     private void setListeners() {
         MFXLabel label = getSkinnable();
 
@@ -167,6 +185,9 @@ public class MFXLabelSkin extends SkinBase<MFXLabel> {
 
     }
 
+    /**
+     * Builds the focus animation.
+     */
     private void buildAndPlayAnimation(boolean focused) {
         ScaleTransition scaleTransition = new ScaleTransition(Duration.millis(350), focusedLine);
         if (focused) {
@@ -180,6 +201,11 @@ public class MFXLabelSkin extends SkinBase<MFXLabel> {
         scaleTransition.play();
     }
 
+    /**
+     * If {@link MFXLabel#editableProperty()} is set to true shows the editor,
+     * ESCAPE hides the editor canceling any change, ENTER hides the editor and confirms
+     * the changes.
+     */
     private void showEditor() {
         text.setVisible(false);
         MFXTextField textField = new MFXTextField(text.getText());
@@ -205,6 +231,9 @@ public class MFXLabelSkin extends SkinBase<MFXLabel> {
         getChildren().add(textField);
     }
 
+    /**
+     * Checks if the editor is already shown.
+     */
     private boolean containsEditor() {
         Node editor = getChildren().stream()
                 .filter(node -> node.getId() != null && node.getId().equals("editor-node"))
@@ -213,6 +242,9 @@ public class MFXLabelSkin extends SkinBase<MFXLabel> {
         return editor != null;
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
         return 30;

+ 32 - 2
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXProgressBarSkin.java

@@ -25,7 +25,13 @@ import javafx.scene.layout.StackPane;
 import javafx.scene.shape.Rectangle;
 import javafx.util.Duration;
 
+/**
+ * This is the implementation of the Skin associated with every {@code MFXProgressBar}.
+ */
 public class MFXProgressBarSkin extends SkinBase<MFXProgressBar> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final StackPane track;
     private final StackPane bar1;
     private final StackPane bar2;
@@ -34,6 +40,9 @@ public class MFXProgressBarSkin extends SkinBase<MFXProgressBar> {
     private double barWidth = 0;
     private ParallelTransition indeterminateTransition;
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXProgressBarSkin(MFXProgressBar progressBar) {
         super(progressBar);
 
@@ -49,6 +58,9 @@ public class MFXProgressBarSkin extends SkinBase<MFXProgressBar> {
         getChildren().setAll(track, bar1, bar2);
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     private Rectangle buildClip() {
         MFXProgressBar progressBar = getSkinnable();
 
@@ -58,6 +70,9 @@ public class MFXProgressBarSkin extends SkinBase<MFXProgressBar> {
         return clip;
     }
 
+    /**
+     * Adds listeners for: width, visible, parent and scene properties.
+     */
     private void setListeners() {
         MFXProgressBar progressBar = getSkinnable();
 
@@ -67,6 +82,9 @@ public class MFXProgressBarSkin extends SkinBase<MFXProgressBar> {
         progressBar.sceneProperty().addListener((observable, oldValue, newValue) -> updateAnimation());
     }
 
+    /**
+     * Resets the animation.
+     */
     private void clearAnimation() {
         if (indeterminateTransition != null) {
             indeterminateTransition.stop();
@@ -75,6 +93,9 @@ public class MFXProgressBarSkin extends SkinBase<MFXProgressBar> {
         }
     }
 
+    /**
+     * Creates the animation for the indeterminate bar.
+     */
     private void createIndeterminateTimeline() {
         MFXProgressBar progressBar =  getSkinnable();
 
@@ -111,7 +132,10 @@ public class MFXProgressBarSkin extends SkinBase<MFXProgressBar> {
         indeterminateTransition.setCycleCount(Timeline.INDEFINITE);
     }
 
-    private void pauseTimeline(boolean pause) {
+    /**
+     * Pauses/Resumes the animation.
+     */
+    private void updateTimeline(boolean pause) {
         MFXProgressBar progressBar = getSkinnable();
 
         if (progressBar.isIndeterminate()) {
@@ -129,12 +153,15 @@ public class MFXProgressBarSkin extends SkinBase<MFXProgressBar> {
     private void updateAnimation() {
         final boolean isTreeVisible = isTreeVisible();
         if (indeterminateTransition != null) {
-            pauseTimeline(!isTreeVisible);
+            updateTimeline(!isTreeVisible);
         } else if (isTreeVisible) {
             createIndeterminateTimeline();
         }
     }
 
+    /**
+     * Updates the bar progress.
+     */
     private void updateProgress() {
         MFXProgressBar progressBar = getSkinnable();
 
@@ -152,6 +179,9 @@ public class MFXProgressBarSkin extends SkinBase<MFXProgressBar> {
         return progressBar.isVisible() && progressBar.getParent() != null && progressBar.getScene() != null;
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
         return Math.max(100, leftInset + bar1.prefWidth(getSkinnable().getWidth()) + rightInset);

+ 17 - 11
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableColumnCellSkin.java

@@ -23,14 +23,19 @@ import io.github.palexdev.materialfx.controls.cell.MFXTableColumnCell;
 import io.github.palexdev.materialfx.font.MFXFontIcon;
 import io.github.palexdev.materialfx.utils.NodeUtils;
 import javafx.geometry.Insets;
-import javafx.geometry.Pos;
 import javafx.scene.Node;
 import javafx.scene.control.ContentDisplay;
 import javafx.scene.control.Label;
 import javafx.scene.control.skin.LabelSkin;
 import javafx.scene.layout.Region;
 
+/**
+ * This is the implementation of the Skin associated with every {@code MFXTableColumnCell}.
+ */
 public class MFXTableColumnCellSkin<T> extends LabelSkin {
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXTableColumnCellSkin(MFXTableColumnCell<T> column) {
         super(column);
 
@@ -38,12 +43,15 @@ public class MFXTableColumnCellSkin<T> extends LabelSkin {
         column.setMaxWidth(Region.USE_PREF_SIZE);
 
         column.setPadding(new Insets(0, 5, 0, 5));
-        column.setGraphic(createLeadingIcon());
+        column.setGraphic(createSortIcon());
         column.setGraphicTextGap(5);
-        addIcons();
+        addIcon();
     }
 
-    protected Node createLeadingIcon() {
+    /**
+     * Creates the sort icon.
+     */
+    protected Node createSortIcon() {
         MFXFontIcon caret = new MFXFontIcon("mfx-caret-up", 12);
         caret.setMouseTransparent(true);
         MFXIconWrapper icon = new MFXIconWrapper(caret, 18);
@@ -52,11 +60,14 @@ public class MFXTableColumnCellSkin<T> extends LabelSkin {
         return icon;
     }
 
-    private void addIcons() {
+    /**
+     * Adds the sort icon according to the column alignment.
+     */
+    private void addIcon() {
         Label column = getSkinnable();
         Node leading = column.getGraphic();
 
-        if (isRightAlignment(column.getAlignment())) {
+        if (NodeUtils.isRightAlignment(column.getAlignment())) {
             if (leading != null) {
                 column.setContentDisplay(ContentDisplay.LEFT);
             }
@@ -66,9 +77,4 @@ public class MFXTableColumnCellSkin<T> extends LabelSkin {
             }
         }
     }
-
-    private boolean isRightAlignment(Pos alignment) {
-        return alignment == Pos.BASELINE_RIGHT || alignment == Pos.BOTTOM_RIGHT ||
-                alignment == Pos.CENTER_RIGHT || alignment == Pos.TOP_RIGHT;
-    }
 }

+ 155 - 8
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableViewSkin.java

@@ -59,7 +59,41 @@ import java.util.Comparator;
 import java.util.List;
 import java.util.stream.Collectors;
 
+import static io.github.palexdev.materialfx.controls.MFXTableView.TableViewEvent;
+
+/**
+ * This is the implementation of the Skin associated with every {@code MFXTableView}.
+ * <p>
+ * It's the main class since it handles the graphic of the control and its functionalities.
+ * <p>
+ * Builds the column header adding a column cell for each column added in the {@link MFXTableView#getColumns()} list.
+ * Each column can sort the table view using its own comparator specified by the user.
+ * <p>
+ * Then builds a certain number of rows specified by {@link MFXTableView#maxRowsProperty()}, in each row and for each column
+ * adds a row cell.
+ * <p>
+ * At the bottom of the table view there are pagination controls which include a combo box to set {@link MFXTableView#maxRowsProperty()},
+ * a label that indicates the shown rows and the total amount, change page controls. There are also filter controls.
+ * The filter feature is implemented using {@link MFXFilterDialog}.
+ * <p></p>
+ * Note: for the sort and the filter two sorted lists are used, the original items list {@link MFXTableView#getItems()} is untouched.
+ * Why two sorted lists and not a filtered list? Because when the list is filtered it's desirable to keep the sort state. For this reason
+ * it is much easier to manage two sorted lists instead of a filtered list.
+ * <p>
+ * For consistency when the table is filtered the filter icon is disabled, to filter the table again it must be reset before.
+ * <p></p>
+ * Note: another feature is about selection. It is desirable when changing pages that if there were selected rows in the previous page
+ * they should still be highlighted when switching back to that page. For this reason when re-building rows we check if in the page there are
+ * rows previously added in the selection model list, {@link io.github.palexdev.materialfx.selection.TableSelectionModel}.
+ * <p></p>
+ * <b>Warn:</b> note that the layout is way less elaborated than the JavaFX's one. Although unlikely, it's good to know that the alignment between
+ * the column cells and the row cells can be imperfect since it is very delicate. This warn is important especially when extending this class, creating
+ * your own table view layout. But as I said it is unlikely to happen.
+ */
 public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
+    //================================================================================
+    // Properties
+    //================================================================================
     private final VBox container;
     private final HBox columnsContainer;
     private final VBox rowsContainer;
@@ -78,6 +112,9 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
     private final MFXFilterDialog filterDialog;
     private final BooleanProperty tableFiltered = new SimpleBooleanProperty(false);
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     public MFXTableViewSkin(MFXTableView<T> tableView) {
         super(tableView);
 
@@ -148,6 +185,29 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         setListeners();
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
+
+    /**
+     * Adds listeners for:
+     * <p>
+     * - table view's items list: when invalidated the selection is cleared, the filter is cleared, the sort state is maintained and the rows are re-built.<p>
+     * - combo box' selected value: when the maxRows property is changes, resets the index and re-builds the rows from the first page.<p>
+     * - combo box' skin property: to select the item 10 of the combo box's list view.<p>
+     * <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>
+     * <p>
+     * Adds event handlers for:
+     * <p>
+     * - table view MOUSE_PRESSED for requesting focus.<p>
+     * - table view FORCE_UPDATE_EVENT for requesting a forced update, the selection is cleared, the filter is cleared, the sort state is maintained and the rows are re-built.<p>
+     * - filter icon MOUSE_PRESSED for showing the filter dialog.<p>
+     * - clear filter icon MOUSE_PRESSED for removing the applied filter.<p>
+     */
     private void setListeners() {
         MFXTableView<T> tableView = getSkinnable();
 
@@ -161,6 +221,15 @@ 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)) {
@@ -197,6 +266,9 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         clearFilterIcon.disableProperty().bind(tableFiltered.not());
     }
 
+    /**
+     * Builds the columns, make them resizable on the right border and adds them to the columns header.
+     */
     protected void buildColumns() {
         MFXTableView<T> tableView = getSkinnable();
 
@@ -204,10 +276,19 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
             column.setMaxHeight(Double.MAX_VALUE);
             DragResizer.makeResizable(column, DragResizer.RIGHT);
             column.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> sortColumn(column));
+            column.rowCellFactoryProperty().addListener((observable, oldValue, newValue) -> {
+                if (newValue != oldValue) {
+                    buildRows();
+                }
+            });
             columnsContainer.getChildren().add(column);
         }
     }
 
+    /**
+     * Builds a row HBox which will contain all the required cells to represent the model object
+     * and allows selection.
+     */
     protected MFXTableRow<T> buildRowBox(T item) {
         MFXTableView<T> tableView = getSkinnable();
 
@@ -218,6 +299,14 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         return row;
     }
 
+    /**
+     * Builds the rows, from the given list, from the current index up to the max rows displayable and the list size.
+     * <p>
+     * First it calls {@link #buildRowBox(T item)} then for each column in {@link MFXTableView#getColumns()} it calls the
+     * column row cell factory to build the rows cells which are added to the row box.
+     * <p>
+     * At the end the rows are added to the rows container, the showRows label's text is updated and {@link #updateSelection()} is called.
+     */
     protected void buildRows(List<T> items) {
         MFXTableView<T> tableView = getSkinnable();
 
@@ -231,7 +320,7 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
 
             for (MFXTableColumnCell<T> column : tableView.getColumns()) {
                 MFXTableRowCell rowCell = column.getRowCellFactory().call(item);
-                if (isRightAlignment(column.getAlignment())) {
+                if (NodeUtils.isRightAlignment(column.getAlignment())) {
                     rowCell.setPadding(new Insets(0, 5, 0, 0));
                     rowCell.setAlignment(Pos.CENTER_RIGHT);
                 } else {
@@ -249,6 +338,14 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         updateSelection();
     }
 
+    /**
+     * Checks if the table view is filtered or not. If it is then buildRows is called with the filteredList as argument
+     * otherwise the sortedList is passed instead.
+     * <p>
+     * Keep in mind as I said earlier that the original table view's items list is untouched. The sortedList is
+     * basically a wrapper for the original list and when its comparator is set to null, then the list is exactly the same
+     * as the original one.
+     */
     protected void buildRows() {
         if (tableFiltered.get()) {
             buildRows(filteredList);
@@ -257,6 +354,9 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         }
     }
 
+    /**
+     * Utils method to build a {@link MFXIconWrapper} from the given icon description and size.
+     */
     protected MFXIconWrapper buildIcon(String description, double size) {
         MFXIconWrapper icon = new MFXIconWrapper(new MFXFontIcon(description, size), 22).addRippleGenerator();
         RippleGenerator rippleGenerator = icon.getRippleGenerator();
@@ -268,6 +368,9 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         return icon;
     }
 
+    /**
+     * Utils method to build the filter icon.
+     */
     protected MFXIconWrapper buildFilterIcon() {
         MFXIconWrapper icon = new MFXIconWrapper(new MFXFontIcon("mfx-filter", 16), 22).addRippleGenerator();
         icon.getStylesheets().addAll(getSkinnable().getUserAgentStylesheet());
@@ -282,6 +385,9 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         return icon;
     }
 
+    /**
+     * Utils method to build the clear filter icon.
+     */
     protected MFXIconWrapper buildClearFilterIcon() {
         MFXIconWrapper icon = new MFXIconWrapper(new MFXFontIcon("mfx-filter-clear", 16), 22).addRippleGenerator();
         icon.getStylesheets().addAll(getSkinnable().getUserAgentStylesheet());
@@ -296,6 +402,9 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         return icon;
     }
 
+    /**
+     * Setups the pagination controls and adds the initialized controls to the container.
+     */
     private void setupPaginationControls() {
         MFXIconWrapper firstIcon = buildIcon("mfx-first-page", 18);
         MFXIconWrapper previousIcon = buildIcon("mfx-arrow-back", 10);
@@ -323,6 +432,12 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         );
     }
 
+    /**
+     * Changes the table view page according to the given offset. -1 -> previous page, 1 --> next page.
+     * <p>
+     * Also checks if the table view is filtered or not, setting the index from which to build the next/previous page rows
+     * accordingly.
+     */
     private void changePage(int offset) {
         MFXTableView<T> tableView = getSkinnable();
 
@@ -352,6 +467,9 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         buildRows();
     }
 
+    /**
+     * Shows the first page of the table view. The index is set to 0 and rows are re-built.
+     */
     private void goFirstPage() {
         MFXTableView<T> tableView = getSkinnable();
 
@@ -362,6 +480,11 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         buildRows();
     }
 
+    /**
+     * Shows the last page of the table view. Checks if the table view is filtered and retrieves
+     * the correct list size. Then the index is set by adding the {@link MFXTableView#maxRowsProperty()} value
+     * to it until (index + tableView.getMaxRows() < size).
+     */
     private void goLastPage() {
         MFXTableView<T> tableView = getSkinnable();
 
@@ -377,13 +500,18 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         }
 
         int tmp = index;
-        while (tmp + tableView.getMaxRows() < sortedList.size()) {
+        while (tmp + tableView.getMaxRows() < size) {
             tmp += tableView.getMaxRows();
         }
         index = tmp;
         buildRows();
     }
 
+    /**
+     * Gets the selected rows from the selection model, 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.
+     */
     @SuppressWarnings("unchecked")
     private void updateSelection() {
         MFXTableView<T> tableView = getSkinnable();
@@ -400,11 +528,15 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         }
         for (MFXTableRow<T> row : shownRows) {
             if (selectedItems.contains(row.getItem())) {
-                tableView.getSelectionModel().select(row, null);
+                int index = selectedItems.indexOf(row.getItem());
+                tableView.getSelectionModel().getSelectedRows().set(index, row);
             }
         }
     }
 
+    /**
+     * Resets the sort state of the table view to UNSORTED.
+     */
     private void clearSort(MFXTableColumnCell<T> currColumn) {
         MFXTableView<T> tableView = getSkinnable();
 
@@ -421,6 +553,9 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         buildRows();
     }
 
+    /**
+     * Animates the sort icon of the column cell.
+     */
     private void animateSortIcon(Node node, SortState sortState) {
         Timeline animation = new Timeline();
         switch (sortState) {
@@ -449,6 +584,10 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         animation.play();
     }
 
+    /**
+     * Sorts the table view using the comparator specified in the clicked column.
+     * The state flow is: ASCENDING -> DESCENDING -> UNSORTED
+     */
     protected void sortColumn(MFXTableColumnCell<T> column) {
         if (column.getComparator() == null) {
             throw new NullPointerException("Comparator has not been set for column: " + column.getColumnName());
@@ -482,6 +621,16 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         buildRows();
     }
 
+    /**
+     * Filters the table view. For each item in the sorted list a new temp list is created.
+     * For each item it checks if it is instance of {@link IFilterable} thus deciding to call
+     * {@code toFilterString()} or {@code toString()}, the returned String is used by the filter dialog
+     * in the {@link MFXFilterDialog#filter(String)} method to check if the item string meets the specified
+     * conditions. If it meets the specified conditions the item is added to the temp list. Then filteredList is
+     * set to a new FilteredList with the temp list as argument, the comparator is bound to the sortedList one.
+     * <p>
+     * Builds the rows and closes the dialog.
+     */
     private void filterTable() {
         tableFiltered.set(true);
 
@@ -507,6 +656,9 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
         filterDialog.close();
     }
 
+    //================================================================================
+    // Override Methods
+    //================================================================================
     @Override
     protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
         List<Node> rows = rowsContainer.getChildren();
@@ -517,11 +669,6 @@ public class MFXTableViewSkin<T> extends SkinBase<MFXTableView<T>> {
                 + bottomInset;
     }
 
-    private boolean isRightAlignment(Pos alignment) {
-        return alignment == Pos.BASELINE_RIGHT || alignment == Pos.BOTTOM_RIGHT ||
-                alignment == Pos.CENTER_RIGHT || alignment == Pos.TOP_RIGHT;
-    }
-
     @Override
     protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
         return computePrefHeight(width, topInset, leftInset, bottomInset, rightInset);

+ 9 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/utils/DragResizer.java

@@ -23,6 +23,9 @@ import javafx.scene.input.MouseEvent;
 import javafx.scene.layout.Region;
 
 public class DragResizer {
+    //================================================================================
+    // Properties
+    //================================================================================
 
     /**
      * The margin around the control that a user can click in to start resizing
@@ -43,11 +46,17 @@ public class DragResizer {
     public static final short LEFT = 8;
     public static final short ALL_DIRECTIONS = 15;
 
+    //================================================================================
+    // Constructors
+    //================================================================================
     private DragResizer(Region region, int allowedDirection) {
         this.region = region;
         this.allowedDirection = allowedDirection;
     }
 
+    //================================================================================
+    // Methods
+    //================================================================================
     public static void makeResizable(Region region, int allowedDirection) {
         final DragResizer resizer = new DragResizer(region, allowedDirection);
 

+ 15 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/utils/LabelUtils.java

@@ -20,6 +20,8 @@ package io.github.palexdev.materialfx.utils;
 
 import javafx.beans.property.BooleanProperty;
 import javafx.scene.control.Label;
+import javafx.scene.layout.Region;
+import javafx.scene.text.Font;
 import javafx.scene.text.Text;
 
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -63,4 +65,17 @@ public class LabelUtils {
             isTruncated.set(!actualString.isEmpty() && !originalString.equals(actualString));
         });
     }
+
+    /**
+     * Computes the min width of a label to show all the text. Uses {@link NodeUtils#getNodeWidth(Region)}.
+     * @param font the label font
+     * @param text the label text
+     */
+    public static double computeTextWidth(Font font, String text) {
+        Label helper = new Label(text);
+        helper.setMaxWidth(Double.MAX_VALUE);
+        helper.setFont(font);
+
+        return NodeUtils.getNodeWidth(helper);
+    }
 }

+ 6 - 8
materialfx/src/main/java/io/github/palexdev/materialfx/utils/NodeUtils.java

@@ -23,13 +23,11 @@ import javafx.geometry.*;
 import javafx.scene.Group;
 import javafx.scene.Node;
 import javafx.scene.Scene;
-import javafx.scene.control.Label;
 import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
 import javafx.scene.layout.*;
 import javafx.scene.paint.Paint;
 import javafx.scene.shape.Circle;
-import javafx.scene.text.Font;
 import javafx.stage.Screen;
 import javafx.stage.Stage;
 import javafx.stage.Window;
@@ -222,12 +220,12 @@ public class NodeUtils {
                 false, false, false, false, true, false, false, false, false, false, null));
     }
 
-    public static double computeTextWidth(Font font, String text) {
-        Label helper = new Label(text);
-        helper.setMaxWidth(Double.MAX_VALUE);
-        helper.setFont(font);
-
-        return getNodeWidth(helper);
+    /**
+     * Checks if the given alignment is set to RIGHT(any).
+     */
+    public static boolean isRightAlignment(Pos alignment) {
+        return alignment == Pos.BASELINE_RIGHT || alignment == Pos.BOTTOM_RIGHT ||
+                alignment == Pos.CENTER_RIGHT || alignment == Pos.TOP_RIGHT;
     }
 
     /* The following methods are copied from com.sun.javafx.scene.control.skin.Utils class

+ 7 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/utils/StringUtils.java

@@ -104,6 +104,13 @@ public class StringUtils {
         return str;
     }
 
+    /**
+     * <p>Checks if a CharSequence contains a search CharSequence irrespective of case,
+     * handling {@code null}. Case-insensitivity is defined as by
+     * {@link String#equalsIgnoreCase(String)}.
+     *
+     * <p>A {@code null} CharSequence will return {@code false}.</p>
+     */
     public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
         if (str == null || searchStr == null) {
             return false;