diff --git a/api/applib/src/main/java/org/apache/causeway/applib/value/semantics/ValueSemanticsAbstract.java b/api/applib/src/main/java/org/apache/causeway/applib/value/semantics/ValueSemanticsAbstract.java index de39393fc21..70902a46fec 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/value/semantics/ValueSemanticsAbstract.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/value/semantics/ValueSemanticsAbstract.java @@ -32,6 +32,7 @@ import java.util.Optional; import java.util.function.Function; import java.util.function.Supplier; +import java.util.function.UnaryOperator; import jakarta.inject.Provider; @@ -39,6 +40,7 @@ import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.annotation.Autowired; + import org.apache.causeway.applib.annotation.TimePrecision; import org.apache.causeway.applib.exceptions.recoverable.TextEntryParseException; import org.apache.causeway.applib.locale.UserLocale; @@ -130,6 +132,14 @@ protected String renderHtml(final T value, final Function toString) { .orElseGet(()->getPlaceholderRenderService().asHtml(PlaceholderLiteral.NULL_REPRESENTATION)); } + protected String renderHtml(final T value, final Function toString, final UnaryOperator htmlPostprocessor) { + return Optional.ofNullable(value) + .map(toString) + .map(htmlPostprocessor) + .orElseGet(()->getPlaceholderRenderService().asHtml(PlaceholderLiteral.NULL_REPRESENTATION)); + } + + // -- COMPOSITION UTILS protected ValueDecomposition decomposeAsString( @@ -198,7 +208,6 @@ protected T composeFromNullable( * this is typically overruled later by implementations of * {@link #configureDecimalFormat(org.apache.causeway.applib.adapters.ValueSemanticsProvider.Context, DecimalFormat) configureDecimalFormat} */ - @SuppressWarnings("javadoc") protected DecimalFormat getNumberFormat( final ValueSemanticsProvider.@Nullable Context context) { return getNumberFormat(context, FormatUsageFor.RENDERING); @@ -218,9 +227,8 @@ protected Optional parseInteger( final ValueSemanticsProvider.@Nullable Context context, final @Nullable String text) { var input = _Strings.blankToNullOrTrim(text); - if(input==null) { + if(input==null) return Optional.empty(); - } try { return parseDecimal(context, input, GroupingSeparatorPolicy.ALLOW) .map(BigDecimal::toBigIntegerExact); @@ -240,17 +248,15 @@ protected Optional parseDecimal( final @Nullable String text, final GroupingSeparatorPolicy groupingSeparatorPolicy) { var input = _Strings.blankToNullOrTrim(text); - if(input==null) { + if(input==null) return Optional.empty(); - } if (groupingSeparatorPolicy == GroupingSeparatorPolicy.DISALLOW) { var userLocale = getUserLocale(context); var decimalFormatSymbols = new DecimalFormatSymbols(userLocale.numberFormatLocale()); var groupingSeparatorChar = decimalFormatSymbols.getGroupingSeparator(); - if (input.contains(""+groupingSeparatorChar)) { + if (input.contains(""+groupingSeparatorChar)) throw new TextEntryParseException("Invalid value '" + input + "'; do not use the '" + groupingSeparatorChar + "' grouping separator"); - } } var format = getNumberFormat(context, FormatUsageFor.PARSING); @@ -259,19 +265,17 @@ protected Optional parseDecimal( var position = new ParsePosition(0); try { var number = (BigDecimal)format.parse(input, position); - if (position.getErrorIndex() != -1) { + if (position.getErrorIndex() != -1) throw new ParseException("could not parse input='" + input + "'", position.getErrorIndex()); - } else if (position.getIndex() < input.length()) { + else if (position.getIndex() < input.length()) throw new ParseException("input='" + input + "' was not processed completely", position.getIndex()); - } // check for maxFractionDigits if required ... final int maxFractionDigits = format.getMaximumFractionDigits(); if(maxFractionDigits>-1 - && number.scale()>format.getMaximumFractionDigits()) { + && number.scale()>format.getMaximumFractionDigits()) throw new TextEntryParseException(String.format( "No more than %d digits can be entered after the decimal separator, " + "got %d in '%s'.", maxFractionDigits, number.scale(), input)); - } return Optional.of(number); } catch (final NumberFormatException | ParseException e) { throw new TextEntryParseException(String.format( @@ -304,27 +308,17 @@ protected DateTimeFormatter getTemporalNoZoneRenderingFormat( final @Nullable String datePattern, final @Nullable String dateTimePattern) { - final DateTimeFormatter noZoneOutputFormat; - - switch (temporalCharacteristic) { - case DATE_TIME: - noZoneOutputFormat = - dateTimePattern != null - ? DateTimeFormatter.ofPattern(dateTimePattern) - : DateTimeFormatter.ofLocalizedDateTime(dateFormatStyle, timeFormatStyle); - break; - case DATE_ONLY: - noZoneOutputFormat = - datePattern != null - ? DateTimeFormatter.ofPattern(datePattern) - : DateTimeFormatter.ofLocalizedDate(dateFormatStyle); - break; - case TIME_ONLY: - noZoneOutputFormat = DateTimeFormatter.ofLocalizedTime(timeFormatStyle); - break; - default: - throw _Exceptions.unmatchedCase(temporalCharacteristic); - } + final DateTimeFormatter noZoneOutputFormat = switch (temporalCharacteristic) { + case DATE_TIME -> dateTimePattern != null + ? DateTimeFormatter.ofPattern(dateTimePattern) + : DateTimeFormatter.ofLocalizedDateTime(dateFormatStyle, timeFormatStyle); + case DATE_ONLY -> datePattern != null + ? DateTimeFormatter.ofPattern(datePattern) + : DateTimeFormatter.ofLocalizedDate(dateFormatStyle); + case TIME_ONLY -> DateTimeFormatter.ofLocalizedTime(timeFormatStyle); + default -> throw _Exceptions.unmatchedCase(temporalCharacteristic); + }; + return noZoneOutputFormat .withLocale(getUserLocale(context).timeFormatLocale()); } @@ -334,16 +328,12 @@ protected Optional getTemporalZoneOnlyRenderingFormat( final TemporalValueSemantics.@NonNull TemporalCharacteristic temporalCharacteristic, final TemporalValueSemantics.@NonNull OffsetCharacteristic offsetCharacteristic) { - switch (offsetCharacteristic) { - case LOCAL: - return Optional.empty(); - case OFFSET: - return Optional.of(_Temporals.ISO_OFFSET_ONLY_FORMAT); - case ZONED: - return Optional.of(_Temporals.DEFAULT_ZONEID_ONLY_FORMAT); - default: - throw _Exceptions.unmatchedCase(offsetCharacteristic); - } + return switch (offsetCharacteristic) { + case LOCAL -> Optional.empty(); + case OFFSET -> Optional.of(_Temporals.ISO_OFFSET_ONLY_FORMAT); + case ZONED -> Optional.of(_Temporals.DEFAULT_ZONEID_ONLY_FORMAT); + default -> throw _Exceptions.unmatchedCase(offsetCharacteristic); + }; } // -- TEMPORAL FORMATTING/PARSING @@ -367,22 +357,18 @@ protected DateTimeFormatter getTemporalIsoFormat( final TemporalValueSemantics.@NonNull TemporalCharacteristic temporalCharacteristic, final TemporalValueSemantics.@NonNull OffsetCharacteristic offsetCharacteristic) { - switch (temporalCharacteristic) { - case DATE_TIME: - return offsetCharacteristic.isLocal() - ? DateTimeFormatter.ISO_LOCAL_DATE_TIME - : DateTimeFormatter.ISO_DATE_TIME; - case DATE_ONLY: - return offsetCharacteristic.isLocal() - ? DateTimeFormatter.ISO_LOCAL_DATE - : DateTimeFormatter.ISO_DATE; - case TIME_ONLY: - return offsetCharacteristic.isLocal() - ? DateTimeFormatter.ISO_LOCAL_TIME - : DateTimeFormatter.ISO_TIME; - default: - throw _Exceptions.unmatchedCase(temporalCharacteristic); - } + return switch (temporalCharacteristic) { + case DATE_TIME -> offsetCharacteristic.isLocal() + ? DateTimeFormatter.ISO_LOCAL_DATE_TIME + : DateTimeFormatter.ISO_DATE_TIME; + case DATE_ONLY -> offsetCharacteristic.isLocal() + ? DateTimeFormatter.ISO_LOCAL_DATE + : DateTimeFormatter.ISO_DATE; + case TIME_ONLY -> offsetCharacteristic.isLocal() + ? DateTimeFormatter.ISO_LOCAL_TIME + : DateTimeFormatter.ISO_TIME; + default -> throw _Exceptions.unmatchedCase(temporalCharacteristic); + }; } // -- TRANSLATION SUPPORT @@ -403,4 +389,22 @@ protected PlaceholderRenderService getPlaceholderRenderService() { return placeholderRenderService.map(Provider::get).orElseGet(PlaceholderRenderService::fallback); } + // -- UTILS + + /** + * Uses bootstrap CSS. + */ + protected final String toMonospace(final String html) { + return """ + %s""".formatted(html); + } + + /** + * Uses Fontawesome. + */ + protected final String faIconAndTitle(final String faClasses, final String titleHtml) { + return """ + %s""".formatted(faClasses, titleHtml); + } + } diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectDisplayDto.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectDisplayDto.java index 569fd231eef..9e3dab78182 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectDisplayDto.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectDisplayDto.java @@ -19,30 +19,31 @@ package org.apache.causeway.core.metamodel.objectmanager.memento; import java.io.Serializable; -import org.jspecify.annotations.Nullable; import org.apache.causeway.commons.internal.base._Strings; import org.apache.causeway.commons.io.JsonUtils; /** * Provides a summary of the domain object for rendering, - * having (translated) title and icon. + * having (translated) pre-rendered HTML (typically icon and title). * * @implSpec works hand in hand with select2 (third-party) java-script * and org.apache.causeway.viewer.wicket.ui.components.widgets.select2.Select2 template configuration. + * + * @apiNote SECURITY ADVICE: when using this DTO make sure its content is populated from a trusted source */ public record ObjectDisplayDto( Class correspondingClass, String bookmark, String title, - @Nullable String iconHtml) implements Serializable { + String html) implements Serializable { - public static ObjectDisplayDto fromJson(String json) { + public static ObjectDisplayDto fromJson(final String json) { return JsonUtils.tryRead(ObjectDisplayDto.class, json) .valueAsNonNullElseFail(); } - public static ObjectDisplayDto fromJsonBase64(String base64EncodedJson) { + public static ObjectDisplayDto fromJsonBase64(final String base64EncodedJson) { return fromJson(_Strings.base64UrlDecode(base64EncodedJson)); } diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMemento.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMemento.java index 282a099294b..7ac1bcba8a3 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMemento.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMemento.java @@ -31,8 +31,6 @@ import org.apache.causeway.applib.id.LogicalType; import org.apache.causeway.applib.services.bookmark.Bookmark; import org.apache.causeway.applib.services.i18n.TranslationContext; -import org.apache.causeway.applib.services.render.PlaceholderRenderService; -import org.apache.causeway.applib.services.render.PlaceholderRenderService.PlaceholderLiteral; import org.apache.causeway.commons.internal.assertions._Assert; import org.apache.causeway.commons.internal.collections._Lists; import org.apache.causeway.commons.internal.exceptions._Exceptions; @@ -41,6 +39,7 @@ import org.apache.causeway.core.metamodel.object.MmAssertionUtils; import org.apache.causeway.core.metamodel.object.MmHintUtils; import org.apache.causeway.core.metamodel.object.MmTitleUtils; +import org.apache.causeway.core.metamodel.object.MmValueUtils; /** * @since 2.0 @@ -53,7 +52,7 @@ public sealed interface ObjectMemento Bookmark bookmark(); /** - * The object's title for rendering (before translation). + * The object's title for rendering. * Corresponds to {@link ManagedObject#getTitle()}. * *

Directly support choice rendering, without the need to (re-)fetch entire object graphs. @@ -64,17 +63,15 @@ public sealed interface ObjectMemento // -- FACTORIES static ObjectMemento empty(final LogicalType logicalType) { - return new ObjectMementoEmpty( - logicalType, - PlaceholderRenderService.fallback().asText(PlaceholderLiteral.NULL_REPRESENTATION)); + return new ObjectMementoEmpty(logicalType); } static Optional singular( - final @Nullable ManagedObject adapter) { - if(ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)) + final @Nullable ManagedObject mo) { + if(ManagedObjects.isNullOrUnspecifiedOrEmpty(mo)) return Optional.empty(); - var spec = adapter.objSpec(); + var spec = mo.objSpec(); _Assert.assertTrue(spec.isIdentifiable() || spec.isParented() @@ -86,11 +83,20 @@ static Optional singular( + "nor has 'encodable' semantics, nor is (Serializable || Externalizable)" .formatted(spec)); + var title = mo.getTranslationService().translate(TranslationContext.empty(), MmTitleUtils.titleOf(mo)); + + var prerenderedHtml = spec.isValue() + ? "%s".formatted( + MmValueUtils.htmlStringForValueType(null, mo)) // currently only the default value semantics is supported + : "%s %s".formatted( + mo.getObjectRenderService().iconToHtml(mo.getIcon(IconSize.SMALL), IconSize.SMALL), + title); + return Optional.ofNullable(new ObjectMementoSingular( - adapter.logicalType(), - MmHintUtils.bookmarkElseFail(adapter), - adapter.getTranslationService().translate(TranslationContext.empty(), MmTitleUtils.titleOf(adapter)), - adapter.getObjectRenderService().iconToHtml(adapter.getIcon(IconSize.SMALL), IconSize.SMALL))); + mo.logicalType(), + MmHintUtils.bookmarkElseFail(mo), + title, + prerenderedHtml)); } /** * returns null for null @@ -125,8 +131,8 @@ static ObjectMemento fromDto(final ObjectDisplayDto dto) { var bookmark = Bookmark.parse(dto.bookmark()).orElseThrow(); var logicalType = new LogicalType(bookmark.logicalTypeName(), dto.correspondingClass()); return bookmark.isEmpty() - ? new ObjectMementoEmpty(logicalType, dto.title()) - : new ObjectMementoSingular(logicalType, bookmark, dto.title(), dto.iconHtml()); + ? new ObjectMementoEmpty(logicalType) + : new ObjectMementoSingular(logicalType, bookmark, dto.title(), dto.html()); } static String enstringToBase64(final ObjectMemento memento) { diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoEmpty.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoEmpty.java index 967f346b545..c398e4cad1b 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoEmpty.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoEmpty.java @@ -20,10 +20,11 @@ import org.apache.causeway.applib.id.LogicalType; import org.apache.causeway.applib.services.bookmark.Bookmark; +import org.apache.causeway.applib.services.render.PlaceholderRenderService; +import org.apache.causeway.applib.services.render.PlaceholderRenderService.PlaceholderLiteral; record ObjectMementoEmpty( - LogicalType logicalType, - String title) + LogicalType logicalType) implements ObjectMemento { @Override @@ -32,7 +33,15 @@ public Bookmark bookmark() { } public ObjectDisplayDto toDto() { - return new ObjectDisplayDto(logicalType.correspondingClass(), bookmark().stringify(), title, null); + return new ObjectDisplayDto(logicalType.correspondingClass(), bookmark().stringify(), title(), html()); } + @Override + public String title() { + return PlaceholderRenderService.fallback().asText(PlaceholderLiteral.NULL_REPRESENTATION); + } + + private String html() { + return PlaceholderRenderService.fallback().asHtml(PlaceholderLiteral.NULL_REPRESENTATION); + } } diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoSingular.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoSingular.java index 7f3980bbf47..1c998426732 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoSingular.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoSingular.java @@ -18,8 +18,6 @@ */ package org.apache.causeway.core.metamodel.objectmanager.memento; -import org.jspecify.annotations.Nullable; - import org.apache.causeway.applib.id.LogicalType; import org.apache.causeway.applib.services.bookmark.Bookmark; @@ -27,11 +25,11 @@ record ObjectMementoSingular( LogicalType logicalType, Bookmark bookmark, String title, - @Nullable String iconHtml) + String prerenderedHtml) implements ObjectMemento { public ObjectDisplayDto toDto() { - return new ObjectDisplayDto(logicalType.correspondingClass(), bookmark.stringify(), title, iconHtml); + return new ObjectDisplayDto(logicalType.correspondingClass(), bookmark.stringify(), title, prerenderedHtml); } @Override public int hashCode() { return bookmark.hashCode(); } diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/ApplicationFeatureIdValueSemantics.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/ApplicationFeatureIdValueSemantics.java index 2bdbf7be084..f500c398fff 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/ApplicationFeatureIdValueSemantics.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/ApplicationFeatureIdValueSemantics.java @@ -72,6 +72,22 @@ public String titlePresentation(final ValueSemanticsProvider.Context context, fi return value == null ? "" : value.stringify(); } + @Override + public String htmlPresentation(final ValueSemanticsProvider.Context context, final ApplicationFeatureId value) { + return renderHtml(value, this::iconify); + } + + // uses font-awesome + private String iconify(final ApplicationFeatureId featureId) { + var fa = switch (featureId.getSort()) { + case NAMESPACE -> "fa-solid fa-sitemap"; + case MEMBER -> "fa-solid fa-circle-plus .col-indigo"; + case TYPE -> "fa-solid fa-circle .col-indigo"; + }; + + return faIconAndTitle(fa, toMonospace(featureId.stringify())); + } + // -- PARSER @Override diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/BigDecimalValueSemantics.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/BigDecimalValueSemantics.java index 07912c73dd5..be70f4662d0 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/BigDecimalValueSemantics.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/BigDecimalValueSemantics.java @@ -28,6 +28,8 @@ import jakarta.inject.Inject; import jakarta.inject.Named; +import org.jspecify.annotations.NonNull; + import org.springframework.stereotype.Component; import org.apache.causeway.applib.annotation.PriorityPrecedence; @@ -45,10 +47,10 @@ import org.apache.causeway.schema.common.v2.ValueType; import org.apache.causeway.schema.common.v2.ValueWithTypeDto; -import org.jspecify.annotations.NonNull; -import lombok.Setter; import static org.apache.causeway.applib.value.semantics.ValueSemanticsAbstract.FormatUsageFor.PARSING; +import lombok.Setter; + @Component @Named("causeway.metamodel.value.BigDecimalValueSemantics") @Priority(PriorityPrecedence.LATE) @@ -112,7 +114,7 @@ public String titlePresentation(final ValueSemanticsProvider.Context context, fi @Override public String htmlPresentation(final ValueSemanticsProvider.Context context, final BigDecimal value) { - return renderHtml(value, getNumberFormat(context)::format); + return renderHtml(value, getNumberFormat(context)::format, super::toMonospace); } // -- PARSER diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/BigIntegerValueSemantics.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/BigIntegerValueSemantics.java index ce9cb7a48a1..d803b94467f 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/BigIntegerValueSemantics.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/BigIntegerValueSemantics.java @@ -24,6 +24,8 @@ import jakarta.annotation.Priority; import jakarta.inject.Named; +import org.jspecify.annotations.NonNull; + import org.springframework.stereotype.Component; import org.apache.causeway.applib.annotation.PriorityPrecedence; @@ -37,8 +39,6 @@ import org.apache.causeway.schema.common.v2.ValueType; import org.apache.causeway.schema.common.v2.ValueWithTypeDto; -import org.jspecify.annotations.NonNull; - @Component @Named("causeway.metamodel.value.BigIntegerValueSemantics") @Priority(PriorityPrecedence.LATE) @@ -87,7 +87,7 @@ public String titlePresentation(final Context context, final BigInteger value) { @Override public String htmlPresentation(final Context context, final BigInteger value) { - return renderHtml(value, getNumberFormat(context)::format); + return renderHtml(value, getNumberFormat(context)::format, super::toMonospace); } // -- ID STRINGIFIER diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/ByteValueSemantics.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/ByteValueSemantics.java index 90cebc7b4cd..24833411b9e 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/ByteValueSemantics.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/ByteValueSemantics.java @@ -24,6 +24,8 @@ import jakarta.annotation.Priority; import jakarta.inject.Named; +import org.jspecify.annotations.NonNull; + import org.springframework.stereotype.Component; import org.apache.causeway.applib.annotation.PriorityPrecedence; @@ -39,8 +41,6 @@ import org.apache.causeway.schema.common.v2.ValueType; import org.apache.causeway.schema.common.v2.ValueWithTypeDto; -import org.jspecify.annotations.NonNull; - /** * due to auto-boxing also handles the primitive variant */ @@ -104,7 +104,7 @@ public String titlePresentation(final Context context, final Byte value) { @Override public String htmlPresentation(final Context context, final Byte value) { - return renderHtml(value, getNumberFormat(context)::format); + return renderHtml(value, getNumberFormat(context)::format, super::toMonospace); } // -- PARSER @@ -120,9 +120,8 @@ public String parseableTextRepresentation(final Context context, final Byte valu @Override public Byte parseTextRepresentation(final Context context, final String text) { var input = _Strings.blankToNullOrTrim(text); - if(input==null) { + if(input==null) return null; - } try { return super.parseInteger(context, input) .map(BigInteger::byteValueExact) diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/CharacterValueSemantics.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/CharacterValueSemantics.java index 3359c3c8bd1..44570a4922d 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/CharacterValueSemantics.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/CharacterValueSemantics.java @@ -26,6 +26,8 @@ import jakarta.annotation.Priority; import jakarta.inject.Named; +import org.jspecify.annotations.NonNull; + import org.springframework.stereotype.Component; import org.apache.causeway.applib.annotation.PriorityPrecedence; @@ -41,8 +43,6 @@ import org.apache.causeway.schema.common.v2.ValueDto; import org.apache.causeway.schema.common.v2.ValueType; -import org.jspecify.annotations.NonNull; - /** * due to auto-boxing also handles the primitive variant */ @@ -103,20 +103,17 @@ private Character fromString(final String data) { @Override public String enstring(final @NonNull Character id) { - if(NON_SAFE_URL_CHARS.stream().anyMatch(x -> Objects.equals(x, id))) { + if(NON_SAFE_URL_CHARS.stream().anyMatch(x -> Objects.equals(x, id))) return BASE64_PREFIX + _Strings.base64UrlEncode(""+id); - } return REGULAR_PREFIX + id; } @Override public Character destring(final @NonNull String stringified) { - if(stringified.startsWith(REGULAR_PREFIX)) { + if(stringified.startsWith(REGULAR_PREFIX)) return stringified.substring(REGULAR_PREFIX.length()).charAt(0); - } - if(stringified.startsWith(BASE64_PREFIX)) { + if(stringified.startsWith(BASE64_PREFIX)) return _Strings.base64UrlDecode(stringified.substring(BASE64_PREFIX.length())).charAt(0); - } throw new IllegalArgumentException("Could not parse '" + stringified + "'"); } @@ -129,7 +126,7 @@ public String titlePresentation(final Context context, final Character value) { @Override public String htmlPresentation(final Context context, final Character value) { - return renderHtml(value, c->""+c); + return renderHtml(value, c->""+c, super::toMonospace); } // -- PARSER @@ -142,14 +139,12 @@ public String parseableTextRepresentation(final Context context, final Character @Override public Character parseTextRepresentation(final Context context, final String text) { var input = _Strings.blankToNullOrTrim(text); - if(input==null) { + if(input==null) return null; - } - if (input.length() > 1) { + if (input.length() > 1) throw new InvalidEntryException("Only a single character is required"); - } else { + else return Character.valueOf(input.charAt(0)); - } } @Override diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/DoubleValueSemantics.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/DoubleValueSemantics.java index c21819afc7b..121816003af 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/DoubleValueSemantics.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/DoubleValueSemantics.java @@ -86,7 +86,7 @@ public String titlePresentation(final Context context, final Double value) { @Override public String htmlPresentation(final Context context, final Double value) { - return renderHtml(value, getNumberFormat(context)::format); + return renderHtml(value, getNumberFormat(context)::format, super::toMonospace); } // -- PARSER diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/FloatValueSemantics.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/FloatValueSemantics.java index cdc1e1ecb42..29db5d87a8a 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/FloatValueSemantics.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/FloatValueSemantics.java @@ -86,7 +86,7 @@ public String titlePresentation(final Context context, final Float value) { @Override public String htmlPresentation(final Context context, final Float value) { - return renderHtml(value, getNumberFormat(context)::format); + return renderHtml(value, getNumberFormat(context)::format, super::toMonospace); } // -- PARSER diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/IntValueSemantics.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/IntValueSemantics.java index 6ea407aaecb..5da1b596e95 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/IntValueSemantics.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/IntValueSemantics.java @@ -24,6 +24,8 @@ import jakarta.annotation.Priority; import jakarta.inject.Named; +import org.jspecify.annotations.NonNull; + import org.springframework.stereotype.Component; import org.apache.causeway.applib.annotation.PriorityPrecedence; @@ -39,8 +41,6 @@ import org.apache.causeway.schema.common.v2.ValueType; import org.apache.causeway.schema.common.v2.ValueWithTypeDto; -import org.jspecify.annotations.NonNull; - /** * due to auto-boxing also handles the primitive variant */ @@ -104,7 +104,7 @@ public String titlePresentation(final Context context, final Integer value) { @Override public String htmlPresentation(final Context context, final Integer value) { - return renderHtml(value, getNumberFormat(context)::format); + return renderHtml(value, getNumberFormat(context)::format, super::toMonospace); } // -- PARSER @@ -120,9 +120,8 @@ public String parseableTextRepresentation(final Context context, final Integer v @Override public Integer parseTextRepresentation(final Context context, final String text) { var input = _Strings.blankToNullOrTrim(text); - if(input==null) { + if(input==null) return null; - } try { return super.parseInteger(context, input) .map(BigInteger::intValueExact) diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/ShortValueSemantics.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/ShortValueSemantics.java index 00e4fd5dd5a..715bee827b5 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/ShortValueSemantics.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/ShortValueSemantics.java @@ -24,6 +24,8 @@ import jakarta.annotation.Priority; import jakarta.inject.Named; +import org.jspecify.annotations.NonNull; + import org.springframework.stereotype.Component; import org.apache.causeway.applib.annotation.PriorityPrecedence; @@ -39,8 +41,6 @@ import org.apache.causeway.schema.common.v2.ValueType; import org.apache.causeway.schema.common.v2.ValueWithTypeDto; -import org.jspecify.annotations.NonNull; - /** * due to auto-boxing also handles the primitive variant */ @@ -104,7 +104,7 @@ public String titlePresentation(final Context context, final Short value) { @Override public String htmlPresentation(final Context context, final Short value) { - return renderHtml(value, getNumberFormat(context)::format); + return renderHtml(value, getNumberFormat(context)::format, super::toMonospace); } // -- PARSER @@ -120,9 +120,8 @@ public String parseableTextRepresentation(final Context context, final Short val @Override public Short parseTextRepresentation(final Context context, final String text) { var input = _Strings.blankToNullOrTrim(text); - if(input==null) { + if(input==null) return null; - } try { return super.parseInteger(context, input) .map(BigInteger::shortValueExact) diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/UUIDValueSemantics.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/UUIDValueSemantics.java index 6a9e1c4d798..646a0c47bb2 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/UUIDValueSemantics.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/UUIDValueSemantics.java @@ -23,6 +23,8 @@ import jakarta.annotation.Priority; import jakarta.inject.Named; +import org.jspecify.annotations.NonNull; + import org.springframework.stereotype.Component; import org.apache.causeway.applib.annotation.PriorityPrecedence; @@ -36,8 +38,6 @@ import org.apache.causeway.commons.internal.base._Strings; import org.apache.causeway.schema.common.v2.ValueType; -import org.jspecify.annotations.NonNull; - @Component @Named("causeway.metamodel.value.UUIDValueSemantics") @Priority(PriorityPrecedence.LATE) @@ -89,6 +89,11 @@ public String titlePresentation(final ValueSemanticsProvider.Context context, fi return value == null ? "" : value.toString(); } + @Override + public String htmlPresentation(final ValueSemanticsProvider.Context context, final UUID value) { + return renderHtml(value, UUID::toString, super::toMonospace); + } + // -- PARSER @Override diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/Select2.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/Select2.java index 0eae32f863a..f79a6772cce 100644 --- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/Select2.java +++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/Select2.java @@ -64,10 +64,8 @@ static Select2 create( var dto = decodeBase64ToJson(opt.id); if(!dto) return "undefined"; if(!dto.title) return "undefined"; - if(dto.iconHtml) { - return $('' + dto.iconHtml + ' ' + dto.title + ''); - } - return dto.title; + if(!dto.html) return "undefined"; + return $(dto.html); }"""; settings.setTemplateResult(template);