You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2022/03/23 05:11:27 UTC

[isis] 01/02: ISIS-2877: branching off

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch 2877_value.comps
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 5aac4338ce5a402eaeb236b1b2fdb7144402afe8
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Mar 23 05:39:09 2022 +0100

    ISIS-2877: branching off
---
 .../components/scalars/ScalarFragmentFactory.java  | 40 ++++++++---
 .../ui/components/scalars/ScalarPanelAbstract.java | 47 +++++++++++++
 .../components/scalars/ScalarPanelAbstract2.java   | 33 +++++----
 .../scalars/ScalarPanelFormFieldAbstract.html      | 22 ++++--
 .../scalars/ScalarPanelFormFieldAbstract.java      | 80 +++++++++++++++-------
 .../scalars/ScalarPanelTextFieldAbstract.java      | 10 ++-
 .../viewer/wicket/ui/components/scalars/_Util.java | 38 ++++++++++
 .../scalars/string/ScalarTitlePanel.java           | 62 +++++++++++++++++
 .../org/apache/isis/viewer/wicket/ui/util/Wkt.java | 38 +++++++---
 9 files changed, 306 insertions(+), 64 deletions(-)

diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarFragmentFactory.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarFragmentFactory.java
index 035d3e9..2ed72ad 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarFragmentFactory.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarFragmentFactory.java
@@ -30,6 +30,7 @@ import org.springframework.lang.Nullable;
 
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.viewer.wicket.ui.util.Wkt;
+import org.apache.isis.viewer.wicket.ui.util.WktComponents;
 
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
@@ -71,6 +72,18 @@ public class ScalarFragmentFactory {
         public <T extends Component> T createComponent(final Function<String, T> factory) {
             return factory.apply(containerId);
         }
+        public void permanentlyHideIn(final MarkupContainer container) {
+            container.streamChildren()
+            .filter(comp->containerId.equals(comp.getId()))
+            .findFirst()
+            .ifPresentOrElse(comp->{
+                comp.setVisibilityAllowed(false);
+                comp.setVisible(false);
+            },
+            ()->{
+                WktComponents.permanentlyHide(container, containerId);
+            });
+        }
     }
 
     // -- OUTPUT FRAGMENTS
@@ -80,11 +93,14 @@ public class ScalarFragmentFactory {
     public static enum CompactFragment {
         CHECKBOX("fragment-compact-checkbox"),
         LABEL("fragment-compact-label"),
+        BADGE("fragment-compact-badge"),
         ;
         private final String fragmentId;
-        public Fragment createFragment(final MarkupContainer container) {
-            return Wkt.fragmentAdd(
-                    container, FrameFragment.COMPACT.getContainerId(), fragmentId);
+        /**
+         * @param markupProvider - The component whose markup contains the fragment's markup
+         */
+        public Fragment createFragment(final MarkupContainer markupProvider) {
+            return Wkt.fragment(FrameFragment.COMPACT.getContainerId(), fragmentId, markupProvider);
         }
     }
 
@@ -99,9 +115,12 @@ public class ScalarFragmentFactory {
         FILE("fragment-input-file"),
         ;
         private final String fragmentId;
-        public Fragment createFragment(final MarkupContainer container, final FormComponent<?> inputComponent) {
-            val fragment = Wkt.fragmentAdd(
-                    container, RegularFrame.INPUT_FORMAT_CONTAINER.getContainerId(), fragmentId);
+        /**
+         * @param markupProvider - The component whose markup contains the fragment's markup
+         */
+        public Fragment createFragment(final MarkupContainer markupProvider, final FormComponent<?> inputComponent) {
+            val fragment = Wkt.fragment(
+                    RegularFrame.INPUT_FORMAT_CONTAINER.getContainerId(), fragmentId, markupProvider);
             fragment.add(inputComponent);
             return fragment;
         }
@@ -119,11 +138,14 @@ public class ScalarFragmentFactory {
         private final String fragmentId;
         private final Function<IModel<String>, Component> componentFactory;
 
-        public Fragment createFragment(final MarkupContainer container,
+        /**
+         * @param markupProvider - The component whose markup contains the fragment's markup
+         */
+        public Fragment createFragment(final MarkupContainer markupProvider,
                 final IModel<String> promptLabelModel,
                 final @Nullable Consumer<FormComponent<String>> onComponentCreated) {
-            val fragment = Wkt.fragmentAdd(
-                    container, RegularFrame.OUTPUT_FORMAT_CONTAINER.getContainerId(), fragmentId);
+            val fragment = Wkt.fragment(
+                    RegularFrame.OUTPUT_FORMAT_CONTAINER.getContainerId(), fragmentId, markupProvider);
             val component = componentFactory.apply(promptLabelModel);
             fragment.add(component);
             if(onComponentCreated!=null
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
index 268cba9..d3b81a7 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
@@ -108,6 +108,47 @@ implements ScalarModelSubscriber {
         NOTHING
     }
 
+    public enum RenderScenario {
+        /**
+         * Is viewing and cannot edit.
+         * But there might be associated actions with dialog feature inline-as-if-edit.
+         */
+        READONLY,
+        /**
+         * Is viewing and can edit.
+         */
+        CAN_EDIT,
+        CAN_EDIT_INLINE,
+        CAN_EDIT_INLINE_VIA_ACTION,
+        /**
+         * Is editing (either prompt form or other dialog).
+         */
+        EDITING;
+
+        public boolean isReadonly() { return this==READONLY;}
+        public boolean isCanEdit() { return this==CAN_EDIT;}
+        public boolean isEditing() { return this==EDITING;}
+
+        static RenderScenario inferFrom(final ScalarPanelAbstract scalarPanel) {
+            val scalarModel = scalarPanel.scalarModel();
+            if(!scalarModel.getRenderingHint().isRegular()) {
+                return READONLY;
+            }
+            if(scalarModel.isEditMode()) {
+                return EDITING;
+            }
+            if(_Util.canPropertyEnterInlineEditDirectly(scalarModel)) {
+                return CAN_EDIT_INLINE;
+            }
+            if(_Util.lookupPropertyActionForInlineEdit(scalarModel).isPresent()) {
+                return CAN_EDIT_INLINE_VIA_ACTION;
+            }
+            return scalarModel.isEnabled()
+                    ? CAN_EDIT
+                    : READONLY;
+        }
+    }
+
     @RequiredArgsConstructor
     public static class InlinePromptConfig {
         @Getter private final boolean supported;
@@ -179,6 +220,11 @@ implements ScalarModelSubscriber {
     private WebMarkupContainer scalarFrameContainer;
     protected final WebMarkupContainer getScalarFrameContainer() { return scalarFrameContainer; }
 
+    // -- RENDER SCENARIO
+
+    @Getter(AccessLevel.PROTECTED)
+    private final RenderScenario renderScenario;
+
     // -- CONSTRUCTION
 
     protected ScalarPanelAbstract(final String id, final ScalarModel scalarModel) {
@@ -189,6 +235,7 @@ implements ScalarModelSubscriber {
         setupFormatModifiers(formatModifiers);
 
         this.formatModifiers = ImmutableEnumSet.from(formatModifiers);
+        this.renderScenario = RenderScenario.inferFrom(this);
     }
 
     // -- INIT
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java
index 3d6b233..8bce481 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java
@@ -23,19 +23,18 @@ import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.model.IModel;
+import org.springframework.lang.Nullable;
 
 import org.apache.isis.applib.annotation.PromptStyle;
 import org.apache.isis.commons.internal.base._Refs;
-import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
+import org.apache.isis.core.metamodel.interactions.managed.PropertyNegotiationModel;
 import org.apache.isis.viewer.wicket.model.models.InlinePromptContext;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
-import org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions.LinkAndLabelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarFragmentFactory.RegularFrame;
 import org.apache.isis.viewer.wicket.ui.components.scalars.blobclob.IsisBlobOrClobPanelAbstract;
 import org.apache.isis.viewer.wicket.ui.components.scalars.primitive.BooleanPanel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.reference.ReferencePanel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.valuechoices.ValueChoicesSelect2Panel;
-import org.apache.isis.viewer.wicket.ui.components.widgets.linkandlabel.ActionLink;
 import org.apache.isis.viewer.wicket.ui.util.Wkt;
 
 import lombok.val;
@@ -108,7 +107,14 @@ extends ScalarPanelAbstract {
      * are required to override and return a non-null value.
      */
     protected IModel<String> obtainOutputFormatModel() {
-        return null;
+        return ()->{
+            val propertyNegotiationModel = (PropertyNegotiationModel)scalarModel().proposedValue();
+            return propertyNegotiationModel.isCurrentValueAbsent().booleanValue()
+                    ? ""
+                    : propertyNegotiationModel
+                        .getValueAsHtml().getValue();
+                        //.getValueAsParsableText().getValue();
+        };
     }
 
     /**
@@ -135,16 +141,18 @@ extends ScalarPanelAbstract {
     // -- HELPER
 
     private void addOnClickBehaviorTo(
-            final MarkupContainer clickReceiver,
+            final @Nullable MarkupContainer clickReceiver,
             final InlinePromptConfig inlinePromptConfig) {
+
+        if(clickReceiver==null) return;
+
         val scalarModel = scalarModel();
 
         // start off assuming that neither the property nor any of the associated actions
         // are using inline prompts
         val componentToHideRef = _Refs.<Component>objectRef(clickReceiver);
 
-        if (scalarModel.getPromptStyle().isInline()
-                && scalarModel.canEnterEditMode()) {
+        if (_Util.canPropertyEnterInlineEditDirectly(scalarModel)) {
 
             // we configure the prompt link if _this_ property is configured for inline edits...
             Wkt.behaviorAddOnClick(clickReceiver, this::onPropertyInlineEditClick);
@@ -152,16 +160,7 @@ extends ScalarPanelAbstract {
 
         } else {
 
-            val inlineActionIfAny =
-                    scalarModel.getAssociatedActions().getFirstAssociatedWithInlineAsIfEdit();
-
-            // not editable property, but maybe one of the actions is.
-            inlineActionIfAny
-            .map(LinkAndLabelFactory.forPropertyOrParameter(scalarModel))
-            .map(LinkAndLabel::getUiComponent)
-            .map(ActionLink.class::cast)
-            .filter(ActionLink::isVisible)
-            .filter(ActionLink::isEnabled)
+            _Util.lookupPropertyActionForInlineEdit(scalarModel)
             .ifPresent(actionLinkInlineAsIfEdit->{
                 Wkt.behaviorAddOnClick(clickReceiver, actionLinkInlineAsIfEdit::onClick);
                 componentToHideRef.setValue(inlinePromptConfig.getComponentToHide().orElse(null));
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelFormFieldAbstract.html b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelFormFieldAbstract.html
index 4852d2d..3559032 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelFormFieldAbstract.html
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelFormFieldAbstract.html
@@ -31,7 +31,11 @@
 				<label wicket:id="scalarName"
 					class="scalarName col-form-label">[Label text]</label> 
 				<span class="scalarValueWrapper">
+				
 					<div class="scalarPlaceholder">
+					
+						<label wicket:id="debugLabel" style="font-size: x-small; color: burlywood;">[Debug text]</label>
+					
 						<span class="scalarValueInput"> 
 							<span class="editing">
 
@@ -39,15 +43,19 @@
 									href="##" name="scalarValueInlinePromptLink"
 									class="scalarValueInlinePromptLink">
 									
+									<span style="color: blue;">λ</span>
 									<!-- output format --> 
 									<wicket:container 
 										wicket:id="container-scalarValue-outputFormat"/> 
 										 
 								</a> 
 							
-								<!-- input format (when editing or action dialog) -->
-								<wicket:container 
+								<!-- input format (when editing or action dialog or read-only) -->
+								<div>
+									<span style="color: purple;">α</span>
+									<wicket:container 
 										wicket:id="container-scalarValue-inputFormat" />
+								</div>
 								
 								<a wicket:id="editProperty"
 									href="##" class="edit btn btn-sm btn-link"> 
@@ -133,12 +141,18 @@
 		<!-- COMPACT FRAGMENTS -->
 		
 		<wicket:fragment wicket:id="fragment-compact-checkbox">
-			<input wicket:id="scalarIfCompact" type="checkbox"
+			<input wicket:id="scalarValue" type="checkbox"
 				class="form-control" />
 		</wicket:fragment>
 
 		<wicket:fragment wicket:id="fragment-compact-label">
-			<span wicket:id="scalarIfCompact"/>
+			<span wicket:id="scalarValue"/>
+		</wicket:fragment>
+		
+		<wicket:fragment wicket:id="fragment-compact-badge">
+			<div class="badge bg-info">
+				<span wicket:id="scalarValue"></span>	
+			</div>
 		</wicket:fragment>
 
 	</wicket:panel>
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelFormFieldAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelFormFieldAbstract.java
index 245d325..fa5f05a 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelFormFieldAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelFormFieldAbstract.java
@@ -31,7 +31,6 @@ import org.apache.wicket.validation.IValidator;
 import org.apache.wicket.validation.ValidationError;
 import org.springframework.lang.Nullable;
 
-import org.apache.isis.core.metamodel.interactions.managed.PropertyNegotiationModel;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.runtime.context.IsisAppCommonContext;
@@ -103,6 +102,53 @@ extends ScalarPanelAbstract2 {
 
         formComponent.add(createValidator(scalarModel));
 
+        val renderScenario = getRenderScenario();
+
+        Wkt.labelAdd(formGroup, "debugLabel", String.format("%s", renderScenario.name()));
+
+//        switch (renderScenario) {
+//        case READONLY:
+//            // setup as output-format (no links)
+//            // that is: disable links - place output-format into RegularFrame.INPUT_FORMAT_CONTAINER
+//            formGroup.add(RegularFrame.INPUT_FORMAT_CONTAINER
+//                    .createComponent(this::createComponentForOutput));
+//
+//            //RegularFrame.SCALAR_VALUE_INLINE_PROMPT_LINK.permanentlyHideIn(formGroup);
+//
+//            break;
+//        case CAN_EDIT:
+//            // setup as output-format (with links to edit)
+//            // that is: enable links - place output-format into RegularFrame.OUTPUT_FORMAT_CONTAINER
+//            // this is done by the inline prompt setup later
+//            // hide formgr comp
+//            //formComponent.setVisibilityAllowed(false);
+//            RegularFrame.INPUT_FORMAT_CONTAINER.permanentlyHideIn(formGroup);
+//
+//            break;
+//        case EDITING:
+//            // setup as input-format
+//            // that is: disable links - place input-format into RegularFrame.INPUT_FORMAT_CONTAINER
+//            getInputFragmentType()
+//                .ifPresent(inputFragmentType->
+//                    formGroup.add(inputFragmentType.createFragment(this, formComponent)));
+//            break;
+//
+//        default:
+//            break;
+//        }
+
+        if(scalarModel().isViewMode()
+                //TODO remove this non intuitive logic
+                && getFormatModifiers().contains(FormatModifier.MARKUP)) {
+            //setRegularFrame(formGroup);
+            formGroup.add(RegularFrame.INPUT_FORMAT_CONTAINER
+                    .createComponent(this::createComponentForOutput));
+        } else {
+            getInputFragmentType()
+            .ifPresent(inputFragmentType->
+                formGroup.add(inputFragmentType.createFragment(this, formComponent)));
+        }
+
         onFormGroupCreated(formGroup);
 
         return formGroup;
@@ -117,45 +163,29 @@ extends ScalarPanelAbstract2 {
     }
 
     /**
-     * Builds the component to render the model when in COMPACT format.
+     * Builds the component to render the model when in COMPACT frame,
+     * or when in REGULAR frame rendering the OUTPUT-FORMAT.
      * <p>
      * The (textual) default implementation uses a {@link Label}.
      * However, it may be overridden if required.
      */
     protected Component createComponentForOutput(final String id) {
-
         return Wkt.labelAdd(
                 CompactFragment.LABEL.createFragment(this),
                 id,
-                ()->{
-                    val propertyNegotiationModel = (PropertyNegotiationModel)scalarModel().proposedValue();
-                    return propertyNegotiationModel.isCurrentValueAbsent().booleanValue()
-                            ? ""
-                            : propertyNegotiationModel
-                                .getValueAsHtml().getValue();
-                                //.getValueAsParsableText().getValue();
-                });
+                obtainOutputFormatModel());
     }
 
-
     // -- HOOKS
 
     protected Optional<InputFragment> getInputFragmentType() {
         return Optional.empty();
     }
 
-    protected void onFormGroupCreated(final FormGroup formGroup) {
-        if(scalarModel().isViewMode()
-                //TODO remove this non intuitive logic
-                && getFormatModifiers().contains(FormatModifier.MARKUP)) {
-            formGroup.add(RegularFrame.INPUT_FORMAT_CONTAINER
-                    .createComponent(this::createComponentForOutput));
-            return;
-        }
-        getInputFragmentType()
-            .ifPresent(inputFragmentType->
-                formGroup.add(inputFragmentType.createFragment(this, getFormComponent())));
-    }
+    /**
+     * Optional hook, to eg. add additional components (like Blob which adds preview image)
+     */
+    protected void onFormGroupCreated(final FormGroup formGroup) {};
 
     protected IValidator<Object> createValidator(final ScalarModel scalarModel) {
         return new IValidator<Object>() {
@@ -262,4 +292,6 @@ extends ScalarPanelAbstract2 {
         WktTooltips.clearTooltip(inlinePromptLink);
     }
 
+
+
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
index 46538a5..0add814 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
@@ -30,6 +30,7 @@ import org.apache.wicket.model.Model;
 import org.apache.wicket.util.convert.IConverter;
 import org.apache.wicket.validation.validator.StringValidator;
 
+import org.apache.isis.commons.internal.assertions._Assert;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.core.metamodel.commons.ScalarRepresentation;
 import org.apache.isis.core.metamodel.facets.objectvalue.maxlen.MaxLengthFacet;
@@ -101,6 +102,13 @@ extends ScalarPanelFormFieldAbstract<T> {
     }
 
     protected final IModel<T> unwrappedModel() {
+
+        _Assert.assertTrue(scalarModel().getScalarTypeSpec().isAssignableFrom(type), ()->
+            String.format("[%s] cannot possibly unwrap model of type %s into target type %s",
+                    this.getClass().getSimpleName(),
+                    scalarModel().getScalarTypeSpec().getCorrespondingClass(),
+                    type));
+
         return scalarModel().unwrapped(type);
     }
 
@@ -153,7 +161,7 @@ extends ScalarPanelFormFieldAbstract<T> {
         val converter = getConverter(scalarModel());
         return converter!=null
                 ? new ToStringConvertingModel<>(converter)
-                :  _Casts.uncheckedCast(getFormComponent().getModel());
+                : super.obtainOutputFormatModel(); // _Casts.uncheckedCast(getFormComponent().getModel());
     }
 
     protected class ToStringConvertingModel<X> extends Model<String> {
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/_Util.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/_Util.java
new file mode 100644
index 0000000..82a6209
--- /dev/null
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/_Util.java
@@ -0,0 +1,38 @@
+package org.apache.isis.viewer.wicket.ui.components.scalars;
+
+import java.util.Optional;
+
+import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions.LinkAndLabelFactory;
+import org.apache.isis.viewer.wicket.ui.components.widgets.linkandlabel.ActionLink;
+
+import lombok.val;
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+class _Util {
+
+    boolean canPropertyEnterInlineEditDirectly(final ScalarModel scalarModel) {
+        return scalarModel.getPromptStyle().isInline()
+                && scalarModel.canEnterEditMode();
+    }
+
+    Optional<ActionLink> lookupPropertyActionForInlineEdit(final ScalarModel scalarModel) {
+        val inlineActionIfAny =
+                scalarModel.getAssociatedActions().getFirstAssociatedWithInlineAsIfEdit();
+
+        if(canPropertyEnterInlineEditDirectly(scalarModel)) {
+            return Optional.empty();
+        }
+
+        // not editable property, but maybe one of the actions is.
+        return inlineActionIfAny
+        .map(LinkAndLabelFactory.forPropertyOrParameter(scalarModel))
+        .map(LinkAndLabel::getUiComponent)
+        .map(ActionLink.class::cast)
+        .filter(ActionLink::isVisible)
+        .filter(ActionLink::isEnabled);
+    }
+
+}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/string/ScalarTitlePanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/string/ScalarTitlePanel.java
index 1ede5ef..8b9b1c8 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/string/ScalarTitlePanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/string/ScalarTitlePanel.java
@@ -18,8 +18,17 @@
  */
 package org.apache.isis.viewer.wicket.ui.components.scalars.string;
 
+import java.util.EnumSet;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.markup.html.panel.Fragment;
+
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarFragmentFactory.CompactFragment;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldWithValueSemantics;
+import org.apache.isis.viewer.wicket.ui.util.Wkt;
+
+import lombok.val;
 
 /**
  * Panel for rendering titles for scalars of any type.
@@ -32,5 +41,58 @@ public class ScalarTitlePanel<T> extends ScalarPanelTextFieldWithValueSemantics<
         super(id, scalarModel, type);
     }
 
+    @Override
+    protected void setupFormatModifiers(final EnumSet<FormatModifier> modifiers) {
+        modifiers.add(FormatModifier.MARKUP);
+    }
+
+    @Override
+    protected Component createComponentForOutput(final String id) {
+
+        System.err.printf("%s%n", id);
+
+        if(id.equals("container-scalarValue-inputFormat")) {
+            val badgeFragment = //CompactFragment.BADGE.createFragment(this)
+                    new Fragment(id, "fragment-compact-badge", this)
+                    ;
+            Wkt.labelAdd(badgeFragment, "scalarValue", obtainOutputFormatModel());
+            return badgeFragment;
+
+        } else {
+            return Wkt.labelAdd(
+                  CompactFragment.BADGE.createFragment(this),
+                  id,
+                  obtainOutputFormatModel());
+        }
+
+    }
+
+//
+//    static class TitleField<T> extends AbstractTextComponent<T> {
+//        private static final long serialVersionUID = 1L;
+//
+//        final IModel<T> model;
+//        final Class<T> type;
+//        final @Nullable IConverter<T> converter;
+//
+//        public TitleField(final String id, final IModel<T> model, final Class<T> type,
+//                final @Nullable IConverter<T> converter) {
+//            super(id);
+//            this.model = model;
+//            this.type = type;
+//            this.converter = converter;
+//
+//        }
+//
+//        @SuppressWarnings("unchecked")
+//        @Override public <C> IConverter<C> getConverter(final Class<C> cType) {
+//            return cType == type
+//                    ? (IConverter<C>) converter
+//                    : super.getConverter(cType);}
+//        @Override public void error(final IValidationError error) {
+//            //errorMessageIgnoringResourceBundles(this, error);
+//        }
+//
+//    }
 
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/Wkt.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/Wkt.java
index 27dce9c..a8fea68 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/Wkt.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/Wkt.java
@@ -420,27 +420,47 @@ public class Wkt {
     // -- FRAGMENT
 
     /**
-     * @param container - The component whose markup contains the fragment's markup
      * @param id - The component id
      * @param fragmentId - The id of the associated markup fragment
+     * @param markupProvider - The component whose markup contains the fragment's markup
      */
-    public Fragment fragmentAdd(final MarkupContainer container, final String id, final String fragmentId) {
-        return new Fragment(id, fragmentId, container);
+    public Fragment fragment(final String id, final String fragmentId, final MarkupContainer markupProvider) {
+        return new Fragment(id, fragmentId, markupProvider);
     }
 
     /**
-     * @param container - The component whose markup contains the fragment's markup
      * @param id - The component id
      * @param fragmentId - The id of the associated markup fragment
+     * @param markupProvider - The component whose markup contains the fragment's markup
      */
-    public Fragment fragmentAddNoTab(final MarkupContainer container, final String id, final String fragmentId) {
-        return new Fragment(id, fragmentId, container) {
+    public Fragment fragmentNoTab(final String id, final String fragmentId, final MarkupContainer markupProvider) {
+        return new Fragment(id, fragmentId, markupProvider) {
             private static final long serialVersionUID = 1L;
             @Override protected void onComponentTag(final ComponentTag tag) {
                 super.onComponentTag(tag);
-                tag.put("tabindex", "-1");
-            }
-        };
+                tag.put("tabindex", "-1");}};
+    }
+
+    /**
+     * @param container - The component to add the fragment to
+     * @param id - The component id
+     * @param fragmentId - The id of the associated markup fragment
+     * @param markupProvider - The component whose markup contains the fragment's markup
+     */
+    public Fragment fragmentAdd(final MarkupContainer container,
+            final String id, final String fragmentId, final MarkupContainer markupProvider) {
+        return add(container, fragment(id, fragmentId, markupProvider));
+    }
+
+    /**
+     * @param container - The component to add the fragment to
+     * @param id - The component id
+     * @param fragmentId - The id of the associated markup fragment
+     * @param markupProvider - The component whose markup contains the fragment's markup
+     */
+    public Fragment fragmentAddNoTab(final MarkupContainer container,
+            final String id, final String fragmentId, final MarkupContainer markupProvider) {
+        return add(container, fragmentNoTab(id, fragmentId, markupProvider));
     }
 
     // -- IMAGE