Code refactoring and bugfixes (#13)

* Popover: fixed a bug that a node value was not being set
* PlatformUtils: fixed a bug that MacOS can be an OS with name darwin
* Optimized switch statements
* Code formatting and cleanup
* Removed unused imports
* Reformat markdown tables
* Use try-with-resources
* Improve Javadoc
* Enforce Git compliance
* Better NPE error messages
* Fixed spelling errors
This commit is contained in:
CodeDead 2022-10-05 07:05:18 +02:00 committed by GitHub
parent 4261e5be1d
commit aa294eb773
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 341 additions and 231 deletions

@ -55,7 +55,7 @@ Check the [docs](https://mkpaz.github.io/atlantafx/) for more information.
* SASS * SASS
JavaFX standard themes, namely Modena and Caspian, maintained as a huge single CSS file, which is an overwhelmingly hard task. This alone makes creating a new JavaFX theme from scratch hardly possible. Also, JavaFX styling is based on CSS v2.1 specification which does not provide, nor variables, nor mixins, nor modules nor any other goodies that are default for modern front-end development. AtlantaFX themes are written in SASS with each component in a separate module and use recent [Dart SASS](https://sass-lang.com/dart-sass) implementation for CSS compilation. It also follows [Github Primer](https://primer.style/design/foundations/color) color system to make creating new themes more simple. JavaFX standard themes, namely Modena and Caspian, maintained as a huge single CSS file, which is an overwhelmingly hard task. This alone makes creating a new JavaFX theme from scratch hardly possible. Also, JavaFX styling is based on CSS v2.1 specification which does not provide, nor variables, nor mixins, nor modules nor any other goodies that are default for modern front-end development. AtlantaFX themes are written in SASS with each component in a separate module and use recent [Dart SASS](https://sass-lang.com/dart-sass) implementation for CSS compilation. It also follows [GitHub Primer](https://primer.style/design/foundations/color) color system to make creating new themes more simple.
* Additional controls * Additional controls

@ -120,7 +120,7 @@ public class BreadcrumbsSkin<T> extends SkinBase<Breadcrumbs<T>> {
if (i > 0) { if (i > 0) {
// we have to position the bread crumbs slightly overlapping // we have to position the bread crumbs slightly overlapping
double ins = n instanceof Breadcrumbs.BreadCrumbButton ? ((Breadcrumbs.BreadCrumbButton) n).getArrowWidth() : 0; double ins = n instanceof Breadcrumbs.BreadCrumbButton d ? d.getArrowWidth() : 0;
x = snapPositionX(x - ins); x = snapPositionX(x - ins);
} }

@ -238,7 +238,7 @@ public class InlineDatePickerSkin extends BehaviorSkinBase<InlineDatePicker, Inl
backButton = new Button(); backButton = new Button();
backButton.getStyleClass().addAll("back-button"); backButton.getStyleClass().addAll("back-button");
backButton.setOnMouseClicked(e -> behavior.moveBackward(e)); backButton.setOnMouseClicked(behavior::moveBackward);
StackPane leftArrow = new StackPane(); StackPane leftArrow = new StackPane();
leftArrow.getStyleClass().add("left-arrow"); leftArrow.getStyleClass().add("left-arrow");
@ -256,7 +256,7 @@ public class InlineDatePickerSkin extends BehaviorSkinBase<InlineDatePicker, Inl
forwardButton = new Button(); forwardButton = new Button();
forwardButton.getStyleClass().addAll("forward-button"); forwardButton.getStyleClass().addAll("forward-button");
forwardButton.setOnMouseClicked(e -> behavior.moveForward(e)); forwardButton.setOnMouseClicked(behavior::moveForward);
StackPane rightArrow = new StackPane(); StackPane rightArrow = new StackPane();
rightArrow.getStyleClass().add("right-arrow"); rightArrow.getStyleClass().add("right-arrow");
@ -564,8 +564,8 @@ public class InlineDatePickerSkin extends BehaviorSkinBase<InlineDatePicker, Inl
public void rememberFocusedDayCell() { public void rememberFocusedDayCell() {
Node node = getControl().getScene().getFocusOwner(); Node node = getControl().getScene().getFocusOwner();
if (node instanceof DateCell) { if (node instanceof DateCell dc) {
lastFocusedDayCell = (DateCell) node; lastFocusedDayCell = dc;
} }
} }

@ -79,7 +79,9 @@ public class Popover extends PopupControl {
private final ObjectProperty<Duration> fadeInDuration = new SimpleObjectProperty<>(DEFAULT_FADE_DURATION); private final ObjectProperty<Duration> fadeInDuration = new SimpleObjectProperty<>(DEFAULT_FADE_DURATION);
private final ObjectProperty<Duration> fadeOutDuration = new SimpleObjectProperty<>(DEFAULT_FADE_DURATION); private final ObjectProperty<Duration> fadeOutDuration = new SimpleObjectProperty<>(DEFAULT_FADE_DURATION);
/** Creates a popover with a label as the content node. */ /**
* Creates a popover with a label as the content node.
*/
public Popover() { public Popover() {
super(); super();
@ -134,7 +136,7 @@ public class Popover extends PopupControl {
/** /**
* The root pane stores the content node of the popover. It is accessible * The root pane stores the content node of the popover. It is accessible
* via this method in order to support proper styling. * via this method in order to support proper styling.
* * <p>
* Example: * Example:
* *
* <pre> * <pre>
@ -151,7 +153,10 @@ public class Popover extends PopupControl {
private final ObjectProperty<Node> contentNode = new SimpleObjectProperty<>(this, "contentNode") { private final ObjectProperty<Node> contentNode = new SimpleObjectProperty<>(this, "contentNode") {
@Override @Override
public void setValue(Node node) { public void setValue(Node node) {
if (node == null) { throw new IllegalArgumentException("content node can not be null"); } if (node == null) {
throw new NullPointerException("Node cannot be null!");
}
this.set(node);
} }
}; };
@ -168,7 +173,6 @@ public class Popover extends PopupControl {
* Returns the value of the content property * Returns the value of the content property
* *
* @return the content node * @return the content node
*
* @see #contentNodeProperty() * @see #contentNodeProperty()
*/ */
public final Node getContentNode() { public final Node getContentNode() {
@ -179,7 +183,6 @@ public class Popover extends PopupControl {
* Sets the value of the content property. * Sets the value of the content property.
* *
* @param content the new content node value * @param content the new content node value
*
* @see #contentNodeProperty() * @see #contentNodeProperty()
*/ */
public final void setContentNode(Node content) { public final void setContentNode(Node content) {
@ -262,7 +265,9 @@ public class Popover extends PopupControl {
} }
} }
/** {@inheritDoc} */ /**
* {@inheritDoc}
*/
@Override @Override
public final void show(Window owner) { public final void show(Window owner) {
super.show(owner); super.show(owner);
@ -275,7 +280,9 @@ public class Popover extends PopupControl {
ownerWindow.addEventFilter(WindowEvent.WINDOW_HIDING, closePopoverOnOwnerWindowClose); ownerWindow.addEventFilter(WindowEvent.WINDOW_HIDING, closePopoverOnOwnerWindowClose);
} }
/** {@inheritDoc} */ /**
* {@inheritDoc}
*/
@Override @Override
public final void show(Window ownerWindow, double anchorX, double anchorY) { public final void show(Window ownerWindow, double anchorX, double anchorY) {
super.show(ownerWindow, anchorX, anchorY); super.show(ownerWindow, anchorX, anchorY);
@ -326,7 +333,7 @@ public class Popover extends PopupControl {
targetY = y; targetY = y;
if (owner == null) { if (owner == null) {
throw new IllegalArgumentException("owner can not be null"); throw new NullPointerException("Owner Node cannot be null!");
} }
// this is all needed because children windows do not get their x and y // this is all needed because children windows do not get their x and y
@ -348,8 +355,8 @@ public class Popover extends PopupControl {
// the user clicked somewhere into the transparent background, // the user clicked somewhere into the transparent background,
// if this is the case then hide the window (when attached) // if this is the case then hide the window (when attached)
getScene().addEventHandler(MOUSE_CLICKED, mouseEvent -> { getScene().addEventHandler(MOUSE_CLICKED, mouseEvent -> {
if (mouseEvent.getTarget().equals(getScene().getRoot())) { if (mouseEvent.getTarget().equals(getScene().getRoot()) && !isDetached()) {
if (!isDetached()) { hide(); } hide();
} }
}); });
@ -519,7 +526,6 @@ public class Popover extends PopupControl {
* Sets the value of the headerAlwaysVisible property. * Sets the value of the headerAlwaysVisible property.
* *
* @param visible if true, then the header is visible even while attached * @param visible if true, then the header is visible even while attached
*
* @see #headerAlwaysVisibleProperty() * @see #headerAlwaysVisibleProperty()
*/ */
public final void setHeaderAlwaysVisible(boolean visible) { public final void setHeaderAlwaysVisible(boolean visible) {
@ -530,7 +536,6 @@ public class Popover extends PopupControl {
* Returns the value of the detachable property. * Returns the value of the detachable property.
* *
* @return true if the header is visible even while attached * @return true if the header is visible even while attached
*
* @see #headerAlwaysVisibleProperty() * @see #headerAlwaysVisibleProperty()
*/ */
public final boolean isHeaderAlwaysVisible() { public final boolean isHeaderAlwaysVisible() {
@ -550,7 +555,6 @@ public class Popover extends PopupControl {
* Sets the value of the closeButtonEnabled property. * Sets the value of the closeButtonEnabled property.
* *
* @param enabled if false, the popover will not be closeable by the header's close button * @param enabled if false, the popover will not be closeable by the header's close button
*
* @see #closeButtonEnabledProperty() * @see #closeButtonEnabledProperty()
*/ */
public final void setCloseButtonEnabled(boolean enabled) { public final void setCloseButtonEnabled(boolean enabled) {
@ -561,7 +565,6 @@ public class Popover extends PopupControl {
* Returns the value of the closeButtonEnabled property. * Returns the value of the closeButtonEnabled property.
* *
* @return true if the header's close button is enabled * @return true if the header's close button is enabled
*
* @see #closeButtonEnabledProperty() * @see #closeButtonEnabledProperty()
*/ */
public final boolean isCloseButtonEnabled() { public final boolean isCloseButtonEnabled() {
@ -581,7 +584,6 @@ public class Popover extends PopupControl {
* Sets the value of the detachable property. * Sets the value of the detachable property.
* *
* @param detachable if true then the user can detach / tear off the popover * @param detachable if true then the user can detach / tear off the popover
*
* @see #detachableProperty() * @see #detachableProperty()
*/ */
public final void setDetachable(boolean detachable) { public final void setDetachable(boolean detachable) {
@ -592,7 +594,6 @@ public class Popover extends PopupControl {
* Returns the value of the detachable property. * Returns the value of the detachable property.
* *
* @return true if the user is allowed to detach / tear off the popover * @return true if the user is allowed to detach / tear off the popover
*
* @see #detachableProperty() * @see #detachableProperty()
*/ */
public final boolean isDetachable() { public final boolean isDetachable() {
@ -617,7 +618,6 @@ public class Popover extends PopupControl {
* *
* @param detached if true the popover will change its appearance to "detached" * @param detached if true the popover will change its appearance to "detached"
* mode * mode
*
* @see #detachedProperty() * @see #detachedProperty()
*/ */
public final void setDetached(boolean detached) { public final void setDetached(boolean detached) {
@ -628,7 +628,6 @@ public class Popover extends PopupControl {
* Returns the value of the detached property. * Returns the value of the detached property.
* *
* @return true if the popover is currently detached. * @return true if the popover is currently detached.
*
* @see #detachedProperty() * @see #detachedProperty()
*/ */
public final boolean isDetached() { public final boolean isDetached() {
@ -650,7 +649,6 @@ public class Popover extends PopupControl {
* Returns the value of the arrow size property. * Returns the value of the arrow size property.
* *
* @return the arrow size property value * @return the arrow size property value
*
* @see #arrowSizeProperty() * @see #arrowSizeProperty()
*/ */
public final double getArrowSize() { public final double getArrowSize() {
@ -661,7 +659,6 @@ public class Popover extends PopupControl {
* Sets the value of the arrow size property. * Sets the value of the arrow size property.
* *
* @param size the new value of the arrow size property * @param size the new value of the arrow size property
*
* @see #arrowSizeProperty() * @see #arrowSizeProperty()
*/ */
public final void setArrowSize(double size) { public final void setArrowSize(double size) {
@ -684,7 +681,6 @@ public class Popover extends PopupControl {
* Returns the value of the arrow indent property. * Returns the value of the arrow indent property.
* *
* @return the arrow indent value * @return the arrow indent value
*
* @see #arrowIndentProperty() * @see #arrowIndentProperty()
*/ */
public final double getArrowIndent() { public final double getArrowIndent() {
@ -695,7 +691,6 @@ public class Popover extends PopupControl {
* Sets the value of the arrow indent property. * Sets the value of the arrow indent property.
* *
* @param size the arrow indent value * @param size the arrow indent value
*
* @see #arrowIndentProperty() * @see #arrowIndentProperty()
*/ */
public final void setArrowIndent(double size) { public final void setArrowIndent(double size) {
@ -717,7 +712,6 @@ public class Popover extends PopupControl {
* Returns the value of the corner radius property. * Returns the value of the corner radius property.
* *
* @return the corner radius * @return the corner radius
*
* @see #cornerRadiusProperty() * @see #cornerRadiusProperty()
*/ */
public final double getCornerRadius() { public final double getCornerRadius() {
@ -728,7 +722,6 @@ public class Popover extends PopupControl {
* Sets the value of the corner radius property. * Sets the value of the corner radius property.
* *
* @param radius the corner radius * @param radius the corner radius
*
* @see #cornerRadiusProperty() * @see #cornerRadiusProperty()
*/ */
public final void setCornerRadius(double radius) { public final void setCornerRadius(double radius) {
@ -750,7 +743,6 @@ public class Popover extends PopupControl {
* Returns the value of the title property. * Returns the value of the title property.
* *
* @return the detached title * @return the detached title
*
* @see #titleProperty() * @see #titleProperty()
*/ */
public final String getTitle() { public final String getTitle() {
@ -761,12 +753,11 @@ public class Popover extends PopupControl {
* Sets the value of the title property. * Sets the value of the title property.
* *
* @param title the title to use when detached * @param title the title to use when detached
*
* @see #titleProperty() * @see #titleProperty()
*/ */
public final void setTitle(String title) { public final void setTitle(String title) {
if (title == null) { if (title == null) {
throw new IllegalArgumentException("title can not be null"); throw new NullPointerException("Title cannot be null!");
} }
titleProperty().set(title); titleProperty().set(title);
} }
@ -778,7 +769,6 @@ public class Popover extends PopupControl {
* location of the arrow if auto fix is enabled. * location of the arrow if auto fix is enabled.
* *
* @return the arrow location property * @return the arrow location property
*
* @see #setAutoFix(boolean) * @see #setAutoFix(boolean)
*/ */
public final ObjectProperty<ArrowLocation> arrowLocationProperty() { public final ObjectProperty<ArrowLocation> arrowLocationProperty() {
@ -789,7 +779,6 @@ public class Popover extends PopupControl {
* Sets the value of the arrow location property. * Sets the value of the arrow location property.
* *
* @param location the requested location * @param location the requested location
*
* @see #arrowLocationProperty() * @see #arrowLocationProperty()
*/ */
public final void setArrowLocation(ArrowLocation location) { public final void setArrowLocation(ArrowLocation location) {
@ -800,14 +789,15 @@ public class Popover extends PopupControl {
* Returns the value of the arrow location property. * Returns the value of the arrow location property.
* *
* @return the preferred arrow location * @return the preferred arrow location
*
* @see #arrowLocationProperty() * @see #arrowLocationProperty()
*/ */
public final ArrowLocation getArrowLocation() { public final ArrowLocation getArrowLocation() {
return arrowLocationProperty().get(); return arrowLocationProperty().get();
} }
/** All possible arrow locations */ /**
* All possible arrow locations
*/
public enum ArrowLocation { public enum ArrowLocation {
LEFT_TOP, LEFT_TOP,
LEFT_CENTER, LEFT_CENTER,
@ -845,7 +835,6 @@ public class Popover extends PopupControl {
* Returns the value of the fade-in duration property. * Returns the value of the fade-in duration property.
* *
* @return the fade-in duration * @return the fade-in duration
*
* @see #fadeInDurationProperty() * @see #fadeInDurationProperty()
*/ */
public final Duration getFadeInDuration() { public final Duration getFadeInDuration() {
@ -857,7 +846,6 @@ public class Popover extends PopupControl {
* Popover.show(..). * Popover.show(..).
* *
* @param duration the requested fade-in duration * @param duration the requested fade-in duration
*
* @see #fadeInDurationProperty() * @see #fadeInDurationProperty()
*/ */
public final void setFadeInDuration(Duration duration) { public final void setFadeInDuration(Duration duration) {
@ -868,7 +856,6 @@ public class Popover extends PopupControl {
* Returns the value of the fade-out duration property. * Returns the value of the fade-out duration property.
* *
* @return the fade-out duration * @return the fade-out duration
*
* @see #fadeOutDurationProperty() * @see #fadeOutDurationProperty()
*/ */
public final Duration getFadeOutDuration() { public final Duration getFadeOutDuration() {
@ -879,7 +866,6 @@ public class Popover extends PopupControl {
* Sets the value of the fade-out duration property. * Sets the value of the fade-out duration property.
* *
* @param duration the requested fade-out duration * @param duration the requested fade-out duration
*
* @see #fadeOutDurationProperty() * @see #fadeOutDurationProperty()
*/ */
public final void setFadeOutDuration(Duration duration) { public final void setFadeOutDuration(Duration duration) {
@ -900,7 +886,6 @@ public class Popover extends PopupControl {
* Returns the value of the "animated" property. * Returns the value of the "animated" property.
* *
* @return true if the Popover will be shown and hidden with a short fade animation * @return true if the Popover will be shown and hidden with a short fade animation
*
* @see #animatedProperty() * @see #animatedProperty()
*/ */
public final boolean isAnimated() { public final boolean isAnimated() {
@ -911,7 +896,6 @@ public class Popover extends PopupControl {
* Sets the value of the "animated" property. * Sets the value of the "animated" property.
* *
* @param animated if true the Popover will be shown and hidden with a short fade animation * @param animated if true the Popover will be shown and hidden with a short fade animation
*
* @see #animatedProperty() * @see #animatedProperty()
*/ */
public final void setAnimated(boolean animated) { public final void setAnimated(boolean animated) {

@ -31,17 +31,18 @@ public class ProgressSliderSkin extends SliderSkin {
protected void layoutChildren(double x, double y, double w, double h) { protected void layoutChildren(double x, double y, double w, double h) {
super.layoutChildren(x, y, w, h); super.layoutChildren(x, y, w, h);
double progressX, progressY, progressWidth, progressHeight; double progressX = track.getLayoutX();
double progressY;
double progressWidth;
double progressHeight;
// intentionally ignore background radius in calculation, // intentionally ignore background radius in calculation,
// because slider looks better this way // because slider looks better this way
if (getSkinnable().getOrientation() == Orientation.HORIZONTAL) { if (getSkinnable().getOrientation() == Orientation.HORIZONTAL) {
progressX = track.getLayoutX();
progressY = track.getLayoutY(); progressY = track.getLayoutY();
progressWidth = thumb.getLayoutX() - snappedLeftInset(); progressWidth = thumb.getLayoutX() - snappedLeftInset();
progressHeight = track.getHeight(); progressHeight = track.getHeight();
} else { } else {
progressX = track.getLayoutX();
progressY = thumb.getLayoutY(); progressY = thumb.getLayoutY();
progressWidth = track.getWidth(); progressWidth = track.getWidth();
progressHeight = track.getLayoutBounds().getMaxY() + track.getLayoutY() - thumb.getLayoutY() - snappedBottomInset(); progressHeight = track.getLayoutBounds().getMaxY() + track.getLayoutY() - thumb.getLayoutY() - snappedBottomInset();

@ -3,7 +3,12 @@ package atlantafx.base.theme;
public final class NordDark implements Theme { public final class NordDark implements Theme {
public NordDark() { } /**
* Initialize a new NordDark
*/
public NordDark() {
// Default constructor
}
@Override @Override
public String getName() { public String getName() {

@ -3,7 +3,12 @@ package atlantafx.base.theme;
public final class NordLight implements Theme { public final class NordLight implements Theme {
public NordLight() { } /**
* Initialize a new NordLight
*/
public NordLight() {
// Default constructor
}
@Override @Override
public String getName() { public String getName() {

@ -3,7 +3,12 @@ package atlantafx.base.theme;
public final class PrimerDark implements Theme { public final class PrimerDark implements Theme {
public PrimerDark() { } /**
* Initialize a new PrimerDark
*/
public PrimerDark() {
// Default constructor
}
@Override @Override
public String getName() { public String getName() {

@ -3,7 +3,12 @@ package atlantafx.base.theme;
public final class PrimerLight implements Theme { public final class PrimerLight implements Theme {
public PrimerLight() { } /**
* Initialize a new PrimerLight
*/
public PrimerLight() {
// Default constructor
}
@Override @Override
public String getName() { public String getName() {

@ -4,8 +4,6 @@ package atlantafx.base.theme;
import javafx.css.PseudoClass; import javafx.css.PseudoClass;
import javafx.scene.Node; import javafx.scene.Node;
import java.util.Objects;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class Styles { public final class Styles {
@ -77,11 +75,20 @@ public final class Styles {
public static final String TEXT_UNDERLINED = "text-underlined"; public static final String TEXT_UNDERLINED = "text-underlined";
public static final String TEXT_MUTED = "text-muted"; public static final String TEXT_MUTED = "text-muted";
/**
* Initialize a new Styles
*/
private Styles() {
// Default constructor
}
// @formatter:on // @formatter:on
public static void toggleStyleClass(Node node, String styleClass) { public static void toggleStyleClass(Node node, String styleClass) {
Objects.requireNonNull(node); if (node == null)
Objects.requireNonNull(styleClass); throw new NullPointerException("Node cannot be null!");
if (styleClass == null)
throw new NullPointerException("Style class cannot be null!");
int idx = node.getStyleClass().indexOf(styleClass); int idx = node.getStyleClass().indexOf(styleClass);
if (idx > 0) { if (idx > 0) {
@ -92,8 +99,10 @@ public final class Styles {
} }
public static void addStyleClass(Node node, String styleClass, String... excludes) { public static void addStyleClass(Node node, String styleClass, String... excludes) {
Objects.requireNonNull(node); if (node == null)
Objects.requireNonNull(styleClass); throw new NullPointerException("Node cannot be null!");
if (styleClass == null)
throw new NullPointerException("Style class cannot be null!");
if (excludes != null && excludes.length > 0) { if (excludes != null && excludes.length > 0) {
node.getStyleClass().removeAll(excludes); node.getStyleClass().removeAll(excludes);
@ -102,8 +111,10 @@ public final class Styles {
} }
public static void activatePseudoClass(Node node, PseudoClass pseudoClass, PseudoClass... excludes) { public static void activatePseudoClass(Node node, PseudoClass pseudoClass, PseudoClass... excludes) {
Objects.requireNonNull(node); if (node == null)
Objects.requireNonNull(pseudoClass); throw new NullPointerException("Node cannot be null!");
if (pseudoClass == null)
throw new NullPointerException("PseudoClass cannot be null!");
if (excludes != null && excludes.length > 0) { if (excludes != null && excludes.length > 0) {
for (PseudoClass exclude : excludes) { for (PseudoClass exclude : excludes) {

@ -1,8 +1,6 @@
/* SPDX-License-Identifier: MIT */ /* SPDX-License-Identifier: MIT */
package atlantafx.base.theme; package atlantafx.base.theme;
import java.util.Objects;
import static javafx.application.Application.STYLESHEET_CASPIAN; import static javafx.application.Application.STYLESHEET_CASPIAN;
import static javafx.application.Application.STYLESHEET_MODENA; import static javafx.application.Application.STYLESHEET_MODENA;
@ -17,9 +15,11 @@ public interface Theme {
boolean isDarkMode(); boolean isDarkMode();
static Theme of(String name, String userAgentStylesheet, boolean darkMode) { static Theme of(final String name, final String userAgentStylesheet, final boolean darkMode) {
Objects.requireNonNull(name); if (name == null)
Objects.requireNonNull(userAgentStylesheet); throw new NullPointerException("Name cannot be null!");
if (userAgentStylesheet == null)
throw new NullPointerException("User agent stylesheet cannot be null!");
return new Theme() { return new Theme() {

@ -7,17 +7,32 @@ package atlantafx.base.theme;
*/ */
public final class Tweaks { public final class Tweaks {
/** Removes or hides dropdown arrow button */ /**
* Initialize a new Tweaks
*/
private Tweaks() {
// Default constructor
}
/**
* Removes or hides dropdown arrow button
*/
public static final String NO_ARROW = "no-arrow"; public static final String NO_ARROW = "no-arrow";
/** Removes external control borders */ /**
* Removes external control borders
*/
public static final String EDGE_TO_EDGE = "edge-to-edge"; public static final String EDGE_TO_EDGE = "edge-to-edge";
/** Alignment */ /**
* Alignment
*/
public static final String ALIGN_LEFT = "align-left"; public static final String ALIGN_LEFT = "align-left";
public static final String ALIGN_CENTER = "align-center"; public static final String ALIGN_CENTER = "align-center";
public static final String ALIGN_RIGHT = "align-right"; public static final String ALIGN_RIGHT = "align-right";
/** Forces a control to use alternative icon, if available */ /**
* Forces a control to use alternative icon, if available
*/
public static final String ALT_ICON = "alt-icon"; public static final String ALT_ICON = "alt-icon";
} }

@ -26,15 +26,17 @@ import java.text.DecimalFormat;
*/ */
public class DoubleStringConverter extends StringConverter<Double> { public class DoubleStringConverter extends StringConverter<Double> {
private final DecimalFormat _format = new DecimalFormat("0.##"); private final DecimalFormat decimalFormat = new DecimalFormat("0.##");
private Runnable _reset; private Runnable reset;
/** /**
* Creates a {@link DoubleStringConverter}. * Creates a {@link DoubleStringConverter}.
* Swallows {@link NumberFormatException} but does nothing * Swallows {@link NumberFormatException} but does nothing
* in response until {@link #setReset} is defined. * in response until {@link #setReset} is defined.
*/ */
public DoubleStringConverter() { } public DoubleStringConverter() {
// Default constructor
}
/** /**
* Creates a {@link DoubleStringConverter} with an editor reset callback. * Creates a {@link DoubleStringConverter} with an editor reset callback.
@ -43,7 +45,7 @@ public class DoubleStringConverter extends StringConverter<Double> {
* @param reset the {@link Runnable} to call upon {@link NumberFormatException} * @param reset the {@link Runnable} to call upon {@link NumberFormatException}
*/ */
public DoubleStringConverter(Runnable reset) { public DoubleStringConverter(Runnable reset) {
_reset = reset; this.reset = reset;
} }
/** /**
@ -59,10 +61,12 @@ public class DoubleStringConverter extends StringConverter<Double> {
* @throws NullPointerException if {@code input} is {@code null} * @throws NullPointerException if {@code input} is {@code null}
*/ */
public DoubleStringConverter(TextField input, double min, double max) { public DoubleStringConverter(TextField input, double min, double max) {
if (input == null) { throw new NullPointerException("input"); } if (input == null) {
throw new NullPointerException("Input cannot be null!");
}
final double resetValue = Math.min(Math.max(0, min), max); final double resetValue = Math.min(Math.max(0, min), max);
_reset = () -> input.setText(_format.format(resetValue)); reset = () -> input.setText(decimalFormat.format(resetValue));
// bound JavaFX properties cannot be explicitly set // bound JavaFX properties cannot be explicitly set
// if (!input.tooltipProperty().isBound()) { // if (!input.tooltipProperty().isBound()) {
@ -71,11 +75,15 @@ public class DoubleStringConverter extends StringConverter<Double> {
// restrict direct input to valid numerical characters // restrict direct input to valid numerical characters
input.textProperty().addListener((ov, oldValue, newValue) -> { input.textProperty().addListener((ov, oldValue, newValue) -> {
if (newValue == null || newValue.isEmpty()) { return; } if (newValue == null || newValue.isEmpty()) {
return;
}
// special case: minus sign if negative values allowed // special case: minus sign if negative values allowed
if (min < 0 && newValue.endsWith("-")) { if (min < 0 && newValue.endsWith("-")) {
if (newValue.length() > 1) { Platform.runLater(() -> input.setText("-")); } if (newValue.length() > 1) {
Platform.runLater(() -> input.setText("-"));
}
return; return;
} }
@ -95,10 +103,14 @@ public class DoubleStringConverter extends StringConverter<Double> {
// redundant for Spinner but not harmful // redundant for Spinner but not harmful
final double restricted = Math.min(Math.max(value, min), max); final double restricted = Math.min(Math.max(value, min), max);
if (value != restricted) { input.setText(_format.format(restricted)); } if (value != restricted) {
input.setText(decimalFormat.format(restricted));
}
// required for Spinner which handles onAction // required for Spinner which handles onAction
if (oldHandler != null) { oldHandler.handle(t); } if (oldHandler != null) {
oldHandler.handle(t);
}
}); });
} }
@ -139,7 +151,7 @@ public class DoubleStringConverter extends StringConverter<Double> {
* @see #fromString * @see #fromString
*/ */
public void setReset(Runnable reset) { public void setReset(Runnable reset) {
_reset = reset; this.reset = reset;
} }
/** /**
@ -154,14 +166,18 @@ public class DoubleStringConverter extends StringConverter<Double> {
@Override @Override
public Double fromString(String s) { public Double fromString(String s) {
if (s == null || s.isEmpty()) { if (s == null || s.isEmpty()) {
if (_reset != null) { _reset.run(); } if (reset != null) {
reset.run();
}
return 0.0; return 0.0;
} }
try { try {
return Double.valueOf(s); return Double.valueOf(s);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
if (_reset != null) { _reset.run(); } if (reset != null) {
reset.run();
}
return 0.0; return 0.0;
} }
} }
@ -175,7 +191,9 @@ public class DoubleStringConverter extends StringConverter<Double> {
*/ */
@Override @Override
public String toString(Double value) { public String toString(Double value) {
if (value == null) { return "0"; } if (value == null) {
return _format.format(value); return "0";
}
return decimalFormat.format(value);
} }
} }

@ -21,14 +21,15 @@ import javafx.util.StringConverter;
*/ */
public class IntegerStringConverter extends StringConverter<Integer> { public class IntegerStringConverter extends StringConverter<Integer> {
private Runnable _reset; private Runnable reset;
/** /**
* Creates an {@link IntegerStringConverter}. * Creates an {@link IntegerStringConverter}.
* Swallows {@link NumberFormatException} but does nothing * Swallows {@link NumberFormatException} but does nothing
* in response until {@link #setReset} is defined. * in response until {@link #setReset} is defined.
*/ */
public IntegerStringConverter() { } public IntegerStringConverter() {
}
/** /**
* Creates an {@link IntegerStringConverter} with an editor reset callback. * Creates an {@link IntegerStringConverter} with an editor reset callback.
@ -37,7 +38,7 @@ public class IntegerStringConverter extends StringConverter<Integer> {
* @param reset the {@link Runnable} to call upon {@link NumberFormatException} * @param reset the {@link Runnable} to call upon {@link NumberFormatException}
*/ */
public IntegerStringConverter(Runnable reset) { public IntegerStringConverter(Runnable reset) {
_reset = reset; this.reset = reset;
} }
/** /**
@ -53,10 +54,12 @@ public class IntegerStringConverter extends StringConverter<Integer> {
* @throws NullPointerException if {@code input} is {@code null} * @throws NullPointerException if {@code input} is {@code null}
*/ */
public IntegerStringConverter(TextField input, int min, int max) { public IntegerStringConverter(TextField input, int min, int max) {
if (input == null) { throw new NullPointerException("input"); } if (input == null) {
throw new NullPointerException("Input cannot be null!");
}
final int resetValue = Math.min(Math.max(0, min), max); final int resetValue = Math.min(Math.max(0, min), max);
_reset = () -> input.setText(Integer.toString(resetValue)); reset = () -> input.setText(Integer.toString(resetValue));
// bound JavaFX properties cannot be explicitly set // bound JavaFX properties cannot be explicitly set
// if (!input.tooltipProperty().isBound()) { // if (!input.tooltipProperty().isBound()) {
@ -65,11 +68,15 @@ public class IntegerStringConverter extends StringConverter<Integer> {
// restrict direct input to valid numerical characters // restrict direct input to valid numerical characters
input.textProperty().addListener((ov, oldValue, newValue) -> { input.textProperty().addListener((ov, oldValue, newValue) -> {
if (newValue == null || newValue.isEmpty()) { return; } if (newValue == null || newValue.isEmpty()) {
return;
}
// special case: minus sign if negative values allowed // special case: minus sign if negative values allowed
if (min < 0 && newValue.endsWith("-")) { if (min < 0 && newValue.endsWith("-")) {
if (newValue.length() > 1) { Platform.runLater(() -> input.setText("-")); } if (newValue.length() > 1) {
Platform.runLater(() -> input.setText("-"));
}
return; return;
} }
@ -89,10 +96,14 @@ public class IntegerStringConverter extends StringConverter<Integer> {
// redundant for Spinner but not harmful // redundant for Spinner but not harmful
final int restricted = Math.min(Math.max(value, min), max); final int restricted = Math.min(Math.max(value, min), max);
if (value != restricted) { input.setText(Integer.toString(restricted)); } if (value != restricted) {
input.setText(Integer.toString(restricted));
}
// required for Spinner which handles onAction // required for Spinner which handles onAction
if (oldHandler != null) { oldHandler.handle(t); } if (oldHandler != null) {
oldHandler.handle(t);
}
}); });
} }
@ -133,7 +144,7 @@ public class IntegerStringConverter extends StringConverter<Integer> {
* @see #fromString * @see #fromString
*/ */
public void setReset(Runnable reset) { public void setReset(Runnable reset) {
_reset = reset; this.reset = reset;
} }
/** /**
@ -148,14 +159,18 @@ public class IntegerStringConverter extends StringConverter<Integer> {
@Override @Override
public Integer fromString(String s) { public Integer fromString(String s) {
if (s == null || s.isEmpty()) { if (s == null || s.isEmpty()) {
if (_reset != null) { _reset.run(); } if (reset != null) {
reset.run();
}
return 0; return 0;
} }
try { try {
return Integer.valueOf(s); return Integer.valueOf(s);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
if (_reset != null) { _reset.run(); } if (reset != null) {
reset.run();
}
return 0; return 0;
} }
} }
@ -169,7 +184,9 @@ public class IntegerStringConverter extends StringConverter<Integer> {
*/ */
@Override @Override
public String toString(Integer value) { public String toString(Integer value) {
if (value == null) { return "0"; } if (value == null) {
return "0";
}
return Integer.toString(value); return Integer.toString(value);
} }
} }

@ -27,9 +27,12 @@ public class PasswordTextFormatter extends TextFormatter<String> {
char bullet) { char bullet) {
super(valueConverter, null, filter); super(valueConverter, null, filter);
Objects.requireNonNull(valueConverter); if (valueConverter == null)
Objects.requireNonNull(filter); throw new NullPointerException("StringConverter cannot be null!");
Objects.requireNonNull(textField); if (filter == null)
throw new NullPointerException("UnaryOperator cannot be null!");
if (textField == null)
throw new NullPointerException("TextField cannot be null!");
PasswordFilter passwordFilter = (PasswordFilter) getFilter(); PasswordFilter passwordFilter = (PasswordFilter) getFilter();
passwordFilter.setBullet(bullet); passwordFilter.setBullet(bullet);
@ -39,7 +42,9 @@ public class PasswordTextFormatter extends TextFormatter<String> {
// Force text field update, because converter is only called on focus // Force text field update, because converter is only called on focus
// events by default. Don't use commitValue() here because caret position // events by default. Don't use commitValue() here because caret position
// won't be correct due to #javafx-bug (https://bugs.openjdk.org/browse/JDK-8248914). // won't be correct due to #javafx-bug (https://bugs.openjdk.org/browse/JDK-8248914).
if (val == null) { return; } if (val == null) {
return;
}
textField.setText(passwordProperty().get()); textField.setText(passwordProperty().get());
}); });
@ -90,7 +95,9 @@ public class PasswordTextFormatter extends TextFormatter<String> {
@Override @Override
public String toString(String s) { public String toString(String s) {
if (s == null) { return ""; } if (s == null) {
return "";
}
return filter.revealPassword.get() ? filter.password.get() : filter.maskText(s.length()); return filter.revealPassword.get() ? filter.password.get() : filter.maskText(s.length());
} }

@ -3,8 +3,15 @@ package atlantafx.base.util;
public final class PlatformUtils { public final class PlatformUtils {
private static final String OS = System.getProperty("os.name"); /**
private static final boolean MAC = OS.startsWith("Mac"); * Initialize a new PlatformUtils
*/
private PlatformUtils() {
// Default constructor
}
private static final String OS = System.getProperty("os.name", "generic").toLowerCase();
private static final boolean MAC = OS.contains("mac") || OS.contains("darwin");
public static boolean isMac() { public static boolean isMac() {
return MAC; return MAC;

@ -4,16 +4,16 @@ parent: Colors
nav_order: 2 nav_order: 2
--- ---
Global variables are defined at the Scene root level. You can preview all of the them in the Sampler app. Global variables are defined at the Scene root level. You can preview all of them in the Sampler app.
AtlantaFX is based on GitHub Primer color system. You can check [GitHub Primer interface guidelines](https://primer.style/design/foundations/color) for more detailed instructions. There'are functional color variables and color scale variables. AtlantaFX is based on GitHub Primer color system. You can check [GitHub Primer interface guidelines](https://primer.style/design/foundations/color) for more detailed instructions. There are functional color variables and color scale variables.
## Functional colors ## Functional colors
Foreground colors. Foreground colors.
| Color | Usage | | Color | Usage |
|-------|-------| |----------------------|----------------------------------------------------------------------------------------------------------------------------------|
| `-color-fg-default` | Primary color for text and icons. It should be used for body content, titles and labels. | | `-color-fg-default` | Primary color for text and icons. It should be used for body content, titles and labels. |
| `-color-fg-muted` | For content that is secondary or that provides additional context but is not critical to understanding the flow of an interface. | | `-color-fg-muted` | For content that is secondary or that provides additional context but is not critical to understanding the flow of an interface. |
| `-color-fg-subtle` | For placeholders or decorative foregrounds. | | `-color-fg-subtle` | For placeholders or decorative foregrounds. |
@ -22,7 +22,7 @@ Foreground colors.
Background colors. Background colors.
| Color | Usage | | Color | Usage |
|-------|-------| |---------------------|--------------------------------------------------------------------|
| `-color-bg-default` | Primary background color. | | `-color-bg-default` | Primary background color. |
| `-color-bg-overlay` | Background color for popup controls such as popovers and tooltips. | | `-color-bg-overlay` | Background color for popup controls such as popovers and tooltips. |
| `-color-bg-subtle` | Provides visual rest and contrast against the default background. | | `-color-bg-subtle` | Provides visual rest and contrast against the default background. |

@ -24,7 +24,8 @@
<!-- AppDir spec compliant dir for creating AppImage --> <!-- AppDir spec compliant dir for creating AppImage -->
<build.package.appDir>${project.build.directory}${file.separator}app-dir</build.package.appDir> <build.package.appDir>${project.build.directory}${file.separator}app-dir</build.package.appDir>
<!-- jlink generated runtime image --> <!-- jlink generated runtime image -->
<build.package.runtimeImageDir>${project.build.directory}${file.separator}runtime-image</build.package.runtimeImageDir> <build.package.runtimeImageDir>${project.build.directory}${file.separator}runtime-image
</build.package.runtimeImageDir>
<!-- contains package scripts after filtering and placeholder replacement --> <!-- contains package scripts after filtering and placeholder replacement -->
<build.package.scriptsDir>${project.build.directory}${file.separator}package-scripts</build.package.scriptsDir> <build.package.scriptsDir>${project.build.directory}${file.separator}package-scripts</build.package.scriptsDir>
<!-- jpackage directory for temp artifacts --> <!-- jpackage directory for temp artifacts -->
@ -136,7 +137,9 @@
<artifactId>sass-cli-maven-plugin</artifactId> <artifactId>sass-cli-maven-plugin</artifactId>
<configuration> <configuration>
<args> <args>
<arg>${project.basedir}/src/main/resources/assets/styles/scss/index.scss:${project.build.directory}/classes/atlantafx/sampler/assets/styles/index.css</arg> <arg>
${project.basedir}/src/main/resources/assets/styles/scss/index.scss:${project.build.directory}/classes/atlantafx/sampler/assets/styles/index.css
</arg>
<arg>--no-source-map</arg> <arg>--no-source-map</arg>
</args> </args>
</configuration> </configuration>
@ -223,7 +226,9 @@
</goals> </goals>
<configuration> <configuration>
<toolName>jlink</toolName> <toolName>jlink</toolName>
<addModules>java.base,java.logging,jdk.localedata,java.desktop,java.prefs,javafx.controls,javafx.swing,javafx.web</addModules> <addModules>
java.base,java.logging,jdk.localedata,java.desktop,java.prefs,javafx.controls,javafx.swing,javafx.web
</addModules>
<modulePath>${build.platformModulesDir}</modulePath> <modulePath>${build.platformModulesDir}</modulePath>
<output>${build.package.runtimeImageDir}</output> <output>${build.package.runtimeImageDir}</output>
<args> <args>

@ -60,7 +60,9 @@ public class Launcher extends Application {
var tm = ThemeManager.getInstance(); var tm = ThemeManager.getInstance();
tm.setScene(scene); tm.setScene(scene);
tm.setTheme(tm.getDefaultTheme()); tm.setTheme(tm.getDefaultTheme());
if (IS_DEV_MODE) { startCssFX(scene); } if (IS_DEV_MODE) {
startCssFX(scene);
}
scene.getStylesheets().addAll(Resources.resolve("assets/styles/index.css")); scene.getStylesheets().addAll(Resources.resolve("assets/styles/index.css"));
@ -89,9 +91,9 @@ public class Launcher extends Application {
} }
private void loadApplicationProperties() { private void loadApplicationProperties() {
try { Properties properties = new Properties();
var properties = new Properties(); try (InputStreamReader in = new InputStreamReader(Resources.getResourceAsStream("application.properties"), UTF_8)) {
properties.load(new InputStreamReader(Resources.getResourceAsStream("application.properties"), UTF_8)); properties.load(in);
properties.forEach((key, value) -> System.setProperty( properties.forEach((key, value) -> System.setProperty(
String.valueOf(key), String.valueOf(key),
String.valueOf(value) String.valueOf(value)

@ -14,7 +14,7 @@ import java.util.function.Consumer;
* Subscribe and publish events. Events are published in channels distinguished by event type. * Subscribe and publish events. Events are published in channels distinguished by event type.
* Channels can be grouped using an event type hierarchy. * Channels can be grouped using an event type hierarchy.
* <p> * <p>
* You can use the default event bus instance {@link #getInstance}, which is a singleton * You can use the default event bus instance {@link #getInstance}, which is a singleton,
* or you can create one or multiple instances of {@link DefaultEventBus}. * or you can create one or multiple instances of {@link DefaultEventBus}.
*/ */
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})

@ -12,7 +12,6 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import static atlantafx.sampler.util.Containers.setScrollConstraints; import static atlantafx.sampler.util.Containers.setScrollConstraints;
@ -66,6 +65,7 @@ public abstract class AbstractPage extends BorderPane implements Page {
@Override @Override
public void reset() { } public void reset() { }
@Override
protected void layoutChildren() { protected void layoutChildren() {
super.layoutChildren(); super.layoutChildren();
if (isRendered) { return; } if (isRendered) { return; }
@ -81,7 +81,7 @@ public abstract class AbstractPage extends BorderPane implements Page {
} }
protected Overlay lookupOverlay() { protected Overlay lookupOverlay() {
return getScene() != null && getScene().lookup("." + Overlay.STYLE_CLASS) instanceof Overlay overlay ? overlay : null; return getScene() != null && getScene().lookup("." + Overlay.STYLE_CLASS) instanceof Overlay ov ? ov : null;
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -93,7 +93,7 @@ public abstract class AbstractPage extends BorderPane implements Page {
} }
protected <T> List<T> generate(Supplier<T> supplier, int count) { protected <T> List<T> generate(Supplier<T> supplier, int count) {
return Stream.generate(supplier).limit(count).collect(Collectors.toList()); return Stream.generate(supplier).limit(count).toList();
} }
protected Feather randomIcon() { protected Feather randomIcon() {

@ -216,10 +216,10 @@ public class TablePage extends AbstractPage {
var stockCol = new TableColumn<Product, Double>("Stock"); var stockCol = new TableColumn<Product, Double>("Stock");
stockCol.getColumns().setAll(stockCountCol, stockAvailCol); stockCol.getColumns().setAll(stockCountCol, stockAvailCol);
var table = new TableView<Product>(); var tableView = new TableView<Product>();
table.getColumns().setAll(stateCol, indexCol, iconCol, brandCol, nameCol, priceCol, stockCol); tableView.getColumns().setAll(stateCol, indexCol, iconCol, brandCol, nameCol, priceCol, stockCol);
return table; return tableView;
} }
private MenuButton createTablePropertiesMenu(TableView<Product> table) { private MenuButton createTablePropertiesMenu(TableView<Product> table) {

@ -73,7 +73,9 @@ class ColorPaletteBlock extends VBox {
var bgFill = getBgColor(); var bgFill = getBgColor();
// this happens when css isn't updated yet // this happens when css isn't updated yet
if (bgFill == null) { return; } if (bgFill == null) {
return;
}
toggleHover(true); toggleHover(true);
editIcon.setFill(getColorLuminance(flattenColor(bgBaseColor.get(), bgFill)) < LUMINANCE_THRESHOLD ? editIcon.setFill(getColorLuminance(flattenColor(bgBaseColor.get(), bgFill)) < LUMINANCE_THRESHOLD ?
@ -82,7 +84,9 @@ class ColorPaletteBlock extends VBox {
}); });
colorRectangle.setOnMouseExited(e -> toggleHover(false)); colorRectangle.setOnMouseExited(e -> toggleHover(false));
colorRectangle.setOnMouseClicked(e -> { colorRectangle.setOnMouseClicked(e -> {
if (actionHandler != null) { actionHandler.accept(this); } if (actionHandler != null) {
actionHandler.accept(this);
}
}); });
getChildren().addAll( getChildren().addAll(
@ -152,7 +156,10 @@ class ColorPaletteBlock extends VBox {
} }
static String validateColorName(String colorName) { static String validateColorName(String colorName) {
if (colorName == null || !colorName.startsWith("-color")) { if (colorName == null) {
throw new NullPointerException("Color name cannot be null!");
}
if (!colorName.startsWith("-color")) {
throw new IllegalArgumentException("Invalid color name: '" + colorName + "'."); throw new IllegalArgumentException("Invalid color name: '" + colorName + "'.");
} }
return colorName; return colorName;

@ -4,7 +4,6 @@ package atlantafx.sampler.page.showcase.filemanager;
import atlantafx.base.controls.Breadcrumbs; import atlantafx.base.controls.Breadcrumbs;
import atlantafx.base.controls.Spacer; import atlantafx.base.controls.Spacer;
import atlantafx.base.theme.Tweaks; import atlantafx.base.theme.Tweaks;
import atlantafx.sampler.page.components.BreadcrumbsPage;
import atlantafx.sampler.page.showcase.ShowcasePage; import atlantafx.sampler.page.showcase.ShowcasePage;
import atlantafx.sampler.util.Containers; import atlantafx.sampler.util.Containers;
import javafx.geometry.Insets; import javafx.geometry.Insets;

@ -7,13 +7,17 @@ import java.nio.file.Files;
import java.nio.file.LinkOption; import java.nio.file.LinkOption;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.attribute.FileTime; import java.nio.file.attribute.FileTime;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
final class Utils { final class Utils {
private Utils() {
// Default constructor
}
public static long fileSize(Path path) { public static long fileSize(Path path) {
if (path == null) { return 0; } if (path == null) {
return 0;
}
try { try {
return Files.size(path); return Files.size(path);
} catch (IOException e) { } catch (IOException e) {
@ -22,7 +26,9 @@ final class Utils {
} }
public static boolean isFileHidden(Path path) { public static boolean isFileHidden(Path path) {
if (path == null) { return false; } if (path == null) {
return false;
}
try { try {
return Files.isHidden(path); return Files.isHidden(path);
} catch (IOException e) { } catch (IOException e) {
@ -31,7 +37,9 @@ final class Utils {
} }
public static FileTime fileMTime(Path path, LinkOption... options) { public static FileTime fileMTime(Path path, LinkOption... options) {
if (path == null) { return null; } if (path == null) {
return null;
}
try { try {
return Files.getLastModifiedTime(path, options); return Files.getLastModifiedTime(path, options);
} catch (IOException e) { } catch (IOException e) {
@ -45,7 +53,7 @@ final class Utils {
try { try {
Desktop.getDesktop().open(path.toFile()); Desktop.getDesktop().open(path.toFile());
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(); throw new RuntimeException(e);
} }
}).start(); }).start();
} }

@ -28,13 +28,20 @@ public enum ContrastLevel {
public boolean satisfies(double ratio) { public boolean satisfies(double ratio) {
switch (this) { switch (this) {
case AA_NORMAL -> { return ratio >= 4.5; } case AA_NORMAL, AAA_LARGE -> {
case AA_LARGE -> { return ratio >= 3; } return ratio >= 4.5;
case AAA_NORMAL -> { return ratio >= 7; }
case AAA_LARGE -> { return ratio >= 4.5; }
} }
case AA_LARGE -> {
return ratio >= 3;
}
case AAA_NORMAL -> {
return ratio >= 7;
}
default -> {
return false; return false;
} }
}
}
public static double getContrastRatio(Color color1, Color color2) { public static double getContrastRatio(Color color1, Color color2) {
return getContrastRatio(getColorLuminance(color1), getColorLuminance(color2)); return getContrastRatio(getColorLuminance(color1), getColorLuminance(color2));
@ -67,7 +74,9 @@ public enum ContrastLevel {
return (tmp[0] * 0.2126) + (tmp[1] * 0.7152) + (tmp[2] * 0.0722); return (tmp[0] * 0.2126) + (tmp[1] * 0.7152) + (tmp[2] * 0.0722);
} }
/** @see ContrastLevel#getColorLuminance(double[]) */ /**
* @see ContrastLevel#getColorLuminance(double[])
*/
public static double getColorLuminance(Color color) { public static double getColorLuminance(Color color) {
return getColorLuminance(new double[]{color.getRed(), color.getGreen(), color.getBlue()}); return getColorLuminance(new double[]{color.getRed(), color.getGreen(), color.getBlue()});
} }

@ -219,7 +219,7 @@ public class JColorUtils {
} }
/** /**
* Convert the hex single color to a RGB integer * Convert the hex single color to an RGB integer
* *
* @param color hex single color in format FF or F * @param color hex single color in format FF or F
* @return integer color inclusively between 0 and 255 * @return integer color inclusively between 0 and 255
@ -233,7 +233,7 @@ public class JColorUtils {
} }
/** /**
* Convert the arithmetic RGB float to a RGB integer * Convert the arithmetic RGB float to an RGB integer
* *
* @param color float color inclusively between 0.0 and 1.0 * @param color float color inclusively between 0.0 and 1.0
* @return integer color inclusively between 0 and 255 * @return integer color inclusively between 0 and 255