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 2021/09/17 19:13:13 UTC

[isis] branch master updated: ISIS-2871: Value Types need context on a per Member Basis

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

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


The following commit(s) were added to refs/heads/master by this push:
     new b653ec1  ISIS-2871: Value Types need context on a per Member Basis
b653ec1 is described below

commit b653ec11ff7b4a9f43694735cc3732914b711dbb
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri Sep 17 21:13:01 2021 +0200

    ISIS-2871: Value Types need context on a per Member Basis
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-2871
---
 .../metamodel/facets/fallback/TitleFacetNone.java  |   4 +-
 ...ainObjectLayoutAnnotationUsingTitleUiEvent.java |  14 +--
 .../TitleFacetDerivedFromProjectionFacet.java      |  12 +-
 .../metamodel/facets/object/title/TitleFacet.java  |  24 +---
 .../{TitleFacet.java => TitleRenderRequest.java}   |  38 +++---
 .../annotation/TitleFacetViaTitleAnnotation.java   |  19 +--
 .../TitleFacetInferredFromToStringMethod.java      |   6 +-
 .../title/methods/TitleFacetViaTitleMethod.java    |   8 +-
 .../title/parser/TitleFacetUsingRenderer.java      |  86 -------------
 .../title/parser/TitleFacetUsingValueFacet.java    | 103 ++++++++++++++++
 .../metamodel/facets/object/value/ValueFacet.java  |  23 ++++
 .../facets/object/value/ValueFacetAbstract.java    | 136 +++++++++++++++++++--
 .../ValueFacetUsingSemanticsProviderFactory.java   |  26 ++--
 .../managed/ParameterNegotiationModel.java         |   6 -
 .../services/title/TitleServiceDefault.java        |  10 +-
 .../isis/core/metamodel/spec/ManagedObject.java    |  15 ++-
 .../isis/core/metamodel/spec/ManagedObjects.java   |  14 ++-
 .../core/metamodel/spec/ObjectSpecification.java   |   6 +-
 .../specimpl/ObjectSpecificationAbstract.java      |   8 +-
 .../TitleAnnotationFacetFactoryTest.java           |   8 +-
 .../testspec/ObjectSpecificationStub.java          |   5 +-
 .../HasAsciiDocDescription_description.java        |   3 +-
 .../AsciiDocValueSemanticsWithPreprocessing.java   |  13 +-
 .../entity/icontitle/EntityIconAndTitlePanel.java  |   8 +-
 24 files changed, 379 insertions(+), 216 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/fallback/TitleFacetNone.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/fallback/TitleFacetNone.java
index 1fba3c5..897f644 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/fallback/TitleFacetNone.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/fallback/TitleFacetNone.java
@@ -20,7 +20,7 @@ package org.apache.isis.core.metamodel.facets.fallback;
 
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacetAbstract;
-import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
 
 public class TitleFacetNone extends TitleFacetAbstract {
 
@@ -29,7 +29,7 @@ public class TitleFacetNone extends TitleFacetAbstract {
     }
 
     @Override
-    public String title(final ManagedObject object) {
+    public String title(final TitleRenderRequest titleRenderRequest) {
         return null;
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobjectlayout/TitleFacetViaDomainObjectLayoutAnnotationUsingTitleUiEvent.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobjectlayout/TitleFacetViaDomainObjectLayoutAnnotationUsingTitleUiEvent.java
index bf4266e..7530fec 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobjectlayout/TitleFacetViaDomainObjectLayoutAnnotationUsingTitleUiEvent.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobjectlayout/TitleFacetViaDomainObjectLayoutAnnotationUsingTitleUiEvent.java
@@ -32,13 +32,12 @@ import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacetAbstract;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
 import org.apache.isis.core.metamodel.services.events.MetamodelEventService;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.util.EventUtil;
 
-import lombok.val;
-
 public class TitleFacetViaDomainObjectLayoutAnnotationUsingTitleUiEvent
 extends TitleFacetAbstract {
 
@@ -48,7 +47,7 @@ extends TitleFacetAbstract {
             final IsisConfiguration configuration,
             final FacetHolder facetHolder) {
 
-        val isPostForDefault = configuration
+        final var isPostForDefault = configuration
                 .getApplib()
                 .getAnnotation()
                 .getDomainObjectLayout()
@@ -89,7 +88,9 @@ extends TitleFacetAbstract {
     }
 
     @Override
-    public String title(final ManagedObject owningAdapter) {
+    public String title(final TitleRenderRequest titleRenderRequest) {
+
+        final ManagedObject owningAdapter = titleRenderRequest.getObject();
 
         if(owningAdapter == null) {
             return null;
@@ -108,7 +109,7 @@ extends TitleFacetAbstract {
             .orElse(null);
 
             if(underlyingTitleFacet!=null) {
-                return underlyingTitleFacet.title(owningAdapter);
+                return underlyingTitleFacet.title(titleRenderRequest);
             }
         }
 
@@ -130,7 +131,7 @@ extends TitleFacetAbstract {
 
     private static TranslationContext translationContextFor(final FacetHolder facetHolder) {
         if(facetHolder instanceof ObjectSpecification) {
-            val facetHolderAsSpec = (ObjectSpecification) facetHolder;
+            final var facetHolderAsSpec = (ObjectSpecification) facetHolder;
             return TranslationContext.forTranslationContextHolder(facetHolderAsSpec.getFeatureIdentifier());
         }
         return null;
@@ -151,5 +152,4 @@ extends TitleFacetAbstract {
         }
     }
 
-
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/projection/ident/TitleFacetDerivedFromProjectionFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/projection/ident/TitleFacetDerivedFromProjectionFacet.java
index eea0d14..60499f4 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/projection/ident/TitleFacetDerivedFromProjectionFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/projection/ident/TitleFacetDerivedFromProjectionFacet.java
@@ -23,21 +23,26 @@ import java.util.function.BiConsumer;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.object.projection.ProjectionFacet;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacetAbstract;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 
 import lombok.val;
 
-public class TitleFacetDerivedFromProjectionFacet extends TitleFacetAbstract {
+public class TitleFacetDerivedFromProjectionFacet
+extends TitleFacetAbstract {
 
     private final ProjectionFacet projectionFacet;
 
-    public TitleFacetDerivedFromProjectionFacet(final ProjectionFacet projectionFacet, final FacetHolder holder) {
+    public TitleFacetDerivedFromProjectionFacet(
+            final ProjectionFacet projectionFacet,
+            final FacetHolder holder) {
         super(holder);
         this.projectionFacet = projectionFacet;
     }
 
     @Override
-    public String title(final ManagedObject targetAdapter) {
+    public String title(final TitleRenderRequest titleRenderRequest) {
+        final ManagedObject targetAdapter = titleRenderRequest.getObject();
         val projectedAdapter = projectionFacet.projected(targetAdapter);
         return projectedAdapter.titleString();
     }
@@ -48,4 +53,5 @@ public class TitleFacetDerivedFromProjectionFacet extends TitleFacetAbstract {
         visitor.accept("projectionFacet", projectionFacet.getClass().getName());
     }
 
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/TitleFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/TitleFacet.java
index 6c895616..5f84cf4 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/TitleFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/TitleFacet.java
@@ -18,8 +18,6 @@
  */
 package org.apache.isis.core.metamodel.facets.object.title;
 
-import java.util.function.Predicate;
-
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facets.object.icon.IconFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -39,23 +37,13 @@ public interface TitleFacet extends Facet {
     /**
      * Provide a title for the target object.
      */
-    String title(ManagedObject targetAdapter);
+    String title(TitleRenderRequest titleRenderRequest);
 
-    /**
-     * Provide a title for the target object, possibly abbreviated (according to supplied predicate)
-     *
-     * <p>
-     * One reason why the title might be abbreviated is if it is being evaluated in the context of another object,
-     * for example as a child object of a parented collection of some parent object. In such a context, the
-     * title might be shortened so that it does not needlessly incorporate the title of the parent (context)
-     * object.
-     * </p>
-     */
-    default String title(
-            final Predicate<ManagedObject> skipTitlePartEvaluator,
-            final ManagedObject targetAdapter) {
-        //Default implementation that simply delegates to {@link TitleFacet#title(ManagedObject)}.
-        return title(targetAdapter);
+    @Deprecated
+    default String title(final ManagedObject targetAdapter) {
+        return title(TitleRenderRequest.builder()
+                .object(targetAdapter)
+                .build());
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/TitleFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/TitleRenderRequest.java
similarity index 63%
copy from core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/TitleFacet.java
copy to core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/TitleRenderRequest.java
index 6c895616..39175de 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/TitleFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/TitleRenderRequest.java
@@ -20,26 +20,21 @@ package org.apache.isis.core.metamodel.facets.object.title;
 
 import java.util.function.Predicate;
 
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.facets.object.icon.IconFacet;
+import org.springframework.lang.Nullable;
+
+import org.apache.isis.commons.internal.functions._Predicates;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.feature.ObjectFeature;
 
-/**
- * Mechanism for obtaining the title of an instance of a class, used to label
- * the instance in the viewer (usually alongside an icon representation).
- *
- * <p>
- * In the standard Apache Isis Programming Model, typically corresponds to a
- * method named <tt>title</tt>.
- *
- * @see IconFacet
- */
-public interface TitleFacet extends Facet {
+import lombok.Builder;
+import lombok.NonNull;
+import lombok.Value;
 
-    /**
-     * Provide a title for the target object.
-     */
-    String title(ManagedObject targetAdapter);
+@Value @Builder
+public class TitleRenderRequest {
+
+    private final @Nullable ObjectFeature feature;
+    private final @NonNull ManagedObject object;
 
     /**
      * Provide a title for the target object, possibly abbreviated (according to supplied predicate)
@@ -51,11 +46,8 @@ public interface TitleFacet extends Facet {
      * object.
      * </p>
      */
-    default String title(
-            final Predicate<ManagedObject> skipTitlePartEvaluator,
-            final ManagedObject targetAdapter) {
-        //Default implementation that simply delegates to {@link TitleFacet#title(ManagedObject)}.
-        return title(targetAdapter);
-    }
+    @Builder.Default
+    private final @NonNull Predicate<ManagedObject> skipTitlePartEvaluator =
+        _Predicates.alwaysFalse();
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleFacetViaTitleAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleFacetViaTitleAnnotation.java
index d8a3513..e2ed32a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleFacetViaTitleAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleFacetViaTitleAnnotation.java
@@ -44,6 +44,7 @@ import org.apache.isis.core.metamodel.facets.Evaluators.MethodEvaluator;
 import org.apache.isis.core.metamodel.facets.ImperativeFacet;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacetAbstract;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
@@ -114,14 +115,10 @@ implements ImperativeFacet {
     }
 
     @Override
-    public String title(final ManagedObject targetAdapter) {
-        return title(_Predicates.alwaysFalse(), targetAdapter);
-    }
+    public String title(final TitleRenderRequest titleRenderRequest) {
+
+        final ManagedObject targetAdapter = titleRenderRequest.getObject();
 
-    @Override
-    public String title(
-            final Predicate<ManagedObject> skipTitlePartEvaluator,
-            final ManagedObject targetAdapter) {
         val pojo = targetAdapter.getPojo();
         if(pojo==null) {
             return "";
@@ -137,10 +134,13 @@ implements ImperativeFacet {
                 }
                 // ignore context, if provided
                 val titlePartAdapter = objectManager.adapt(titlePart);
-                if(skipTitlePartEvaluator != null
-                        && skipTitlePartEvaluator.test(titlePartAdapter)) {
+                if(titleRenderRequest.getSkipTitlePartEvaluator().test(titlePartAdapter)) {
                     continue;
                 }
+
+                //TODO propagate the feature titleRenderRequest
+                //component.titleEvaluator.name();
+
                 String title = titleOf(titlePartAdapter);
                 if (_Strings.isNullOrEmpty(title)) {
                     // ... use the toString() otherwise
@@ -253,4 +253,5 @@ implements ImperativeFacet {
             return _Comparators.deweyOrderCompare(this.getDeweyOrdinal(), other.getDeweyOrdinal());
         }
     }
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/methods/TitleFacetInferredFromToStringMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/methods/TitleFacetInferredFromToStringMethod.java
index df58ebe..a6ec914 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/methods/TitleFacetInferredFromToStringMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/methods/TitleFacetInferredFromToStringMethod.java
@@ -30,7 +30,7 @@ import org.apache.isis.core.metamodel.facets.HasImperativeAspect;
 import org.apache.isis.core.metamodel.facets.ImperativeAspect;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacetAbstract;
-import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
 
 import lombok.Getter;
 import lombok.NonNull;
@@ -61,8 +61,8 @@ implements HasImperativeAspect {
     }
 
     @Override
-    public String title(final ManagedObject domainObject) {
-        return imperativeAspect.eval(domainObject, "(not present)");
+    public String title(final TitleRenderRequest titleRenderRequest) {
+        return imperativeAspect.eval(titleRenderRequest.getObject(), "(not present)");
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/methods/TitleFacetViaTitleMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/methods/TitleFacetViaTitleMethod.java
index ff5f9d0..6abf2ba 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/methods/TitleFacetViaTitleMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/methods/TitleFacetViaTitleMethod.java
@@ -31,6 +31,7 @@ import org.apache.isis.core.metamodel.facets.HasImperativeAspect;
 import org.apache.isis.core.metamodel.facets.ImperativeAspect;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacetAbstract;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
 
@@ -69,7 +70,10 @@ implements HasImperativeAspect {
     }
 
     @Override
-    public String title(final ManagedObject owningAdapter) {
+    public String title(final TitleRenderRequest titleRenderRequest) {
+
+        final ManagedObject owningAdapter = titleRenderRequest.getObject();
+
         if(ManagedObjects.isNullOrUnspecifiedOrEmpty(owningAdapter)) {
             return null;
         }
@@ -98,4 +102,6 @@ implements HasImperativeAspect {
         imperativeAspect.visitAttributes(visitor);
     }
 
+
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/parser/TitleFacetUsingRenderer.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/parser/TitleFacetUsingRenderer.java
deleted file mode 100644
index 9023cda..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/parser/TitleFacetUsingRenderer.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.core.metamodel.facets.object.title.parser;
-
-import java.util.function.BiConsumer;
-
-import org.apache.isis.applib.adapters.Renderer;
-import org.apache.isis.applib.adapters.ValueSemanticsProvider;
-import org.apache.isis.commons.internal.base._Casts;
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
-import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facetapi.FacetHolderAbstract;
-import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
-import org.apache.isis.core.metamodel.spec.ManagedObject;
-
-import lombok.NonNull;
-import lombok.val;
-
-public final class TitleFacetUsingRenderer
-extends FacetAbstract
-implements TitleFacet {
-
-    private final @NonNull Renderer<?> renderer;
-
-    public static TitleFacetUsingRenderer create(final Renderer<?> renderer, final FacetHolder holder) {
-        return new TitleFacetUsingRenderer(renderer, holder);
-    }
-
-    private TitleFacetUsingRenderer(final Renderer<?> renderer, final FacetHolder holder) {
-        super(TitleFacet.class, holder, Precedence.LOW);
-        this.renderer = renderer;
-    }
-
-    @Override
-    public boolean semanticEquals(final @NonNull Facet other) {
-        return other instanceof TitleFacetUsingRenderer
-                ? this.renderer.getClass() == ((TitleFacetUsingRenderer)other).renderer.getClass()
-                : false;
-    }
-
-    @Override
-    public String title(final ManagedObject adapter) {
-        if (adapter == null) {
-            return null;
-        }
-        final Object object = adapter.getPojo();
-        if (object == null) {
-            return null;
-        }
-        return renderer.presentationValue(valueSemanticsContext(), _Casts.uncheckedCast(object));
-    }
-
-    @Override
-    public void visitAttributes(final BiConsumer<String, Object> visitor) {
-        super.visitAttributes(visitor);
-        visitor.accept("renderer", renderer.toString());
-    }
-
-    private ValueSemanticsProvider.Context valueSemanticsContext() {
-        val iaProvider = super.getInteractionProvider();
-        if(iaProvider==null) {
-            return null; // JUnit context
-        }
-        return ValueSemanticsProvider.Context.of(
-                ((FacetHolderAbstract)getFacetHolder()).getFeatureIdentifier(),
-                iaProvider.currentInteractionContext().orElse(null));
-    }
-
-}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/parser/TitleFacetUsingValueFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/parser/TitleFacetUsingValueFacet.java
new file mode 100644
index 0000000..b2f1f8c
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/parser/TitleFacetUsingValueFacet.java
@@ -0,0 +1,103 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.facets.object.title.parser;
+
+import java.util.function.BiConsumer;
+
+import org.apache.isis.applib.adapters.Renderer;
+import org.apache.isis.applib.adapters.ValueSemanticsProvider;
+import org.apache.isis.commons.internal.base._NullSafe;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
+import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
+import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+
+import lombok.NonNull;
+
+public final class TitleFacetUsingValueFacet
+extends FacetAbstract
+implements TitleFacet {
+
+    private final @NonNull ValueFacet<?> valueFacet;
+
+    public static TitleFacetUsingValueFacet create(final ValueFacet<?> valueFacet, final FacetHolder holder) {
+        return new TitleFacetUsingValueFacet(valueFacet, holder);
+    }
+
+    private TitleFacetUsingValueFacet(final ValueFacet<?> valueFacet, final FacetHolder holder) {
+        // facets from the title() method have higher precedence
+        super(TitleFacet.class, holder, Precedence.LOW);
+        this.valueFacet = valueFacet;
+    }
+
+    @Override
+    public String title(final TitleRenderRequest renderRequest) {
+        if (renderRequest == null) {
+            return null;
+        }
+        final Object pojo = renderRequest.getObject().getPojo();
+        if (pojo == null) {
+            return null;
+        }
+
+        // support for qualified value semantics, requires a 'where' context,
+        // that is what property, collection, action return or action param this is to be rendered for ...
+
+        if(renderRequest.getFeature() instanceof OneToOneAssociation) {
+            final Renderer renderer = valueFacet
+                    .selectRendererForPropertyElseFallback((OneToOneAssociation)renderRequest.getFeature());
+            return renderer.presentationValue(valueFacet.createValueSemanticsContext(), pojo);
+        }
+        if(renderRequest.getFeature() instanceof ObjectActionParameter) {
+            final Renderer renderer = valueFacet
+                    .selectRendererForParameterElseFallback((ObjectActionParameter)renderRequest.getFeature());
+            return renderer.presentationValue(valueFacet.createValueSemanticsContext(), pojo);
+        }
+
+        // fall back to default value semantics ...
+
+        return valueFacet.getValueSemantics().stream()
+        .map(ValueSemanticsProvider::getRenderer)
+        .filter(_NullSafe::isPresent)
+        .findFirst()
+        .map(renderer->(Renderer) renderer)
+        .map(renderer->renderer.presentationValue(valueFacet.createValueSemanticsContext(), pojo))
+        .orElseGet(()->String.format("Value type %s has no value semantics for title rendering.",
+                renderRequest.getObject().getSpecification().getCorrespondingClass()));
+
+    }
+
+    @Override
+    public boolean semanticEquals(final @NonNull Facet other) {
+        return other instanceof TitleFacetUsingValueFacet
+                ? true //TODO this.valueFacet.semanticEquals(((TitleFacetUsingValueFacet)other).valueFacet)
+                : false;
+    }
+
+    @Override
+    public void visitAttributes(final BiConsumer<String, Object> visitor) {
+        valueFacet.visitAttributes(visitor);
+    }
+
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/ValueFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/ValueFacet.java
index 9a2183d..6781a34 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/ValueFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/ValueFacet.java
@@ -22,7 +22,9 @@ import java.util.Optional;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.adapters.Parser;
+import org.apache.isis.applib.adapters.Renderer;
 import org.apache.isis.applib.adapters.ValueSemanticsProvider;
+import org.apache.isis.applib.adapters.ValueSemanticsProvider.Context;
 import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.metamodel.facetapi.Facet;
@@ -42,6 +44,9 @@ public interface ValueFacet<T> extends Facet {
 
     LogicalType getValueType();
     Can<ValueSemanticsProvider<T>> getValueSemantics();
+    Context createValueSemanticsContext();
+
+    // -- PARSER
 
     Optional<Parser<T>> selectParserForParameter(final ObjectActionParameter param);
     Optional<Parser<T>> selectParserForProperty(final OneToOneAssociation prop);
@@ -58,4 +63,22 @@ public interface ValueFacet<T> extends Facet {
                 .orElseGet(()->fallbackParser(prop.getFeatureIdentifier()));
     }
 
+    // -- RENDERER
+
+    Optional<Renderer<T>> selectRendererForParameter(final ObjectActionParameter param);
+    Optional<Renderer<T>> selectRendererForProperty(final OneToOneAssociation prop);
+
+    Renderer<T> fallbackRenderer(Identifier featureIdentifier);
+
+    default Renderer<T> selectRendererForParameterElseFallback(final ObjectActionParameter param) {
+        return selectRendererForParameter(param)
+                .orElseGet(()->fallbackRenderer(param.getFeatureIdentifier()));
+    }
+
+    default Renderer<T> selectRendererForPropertyElseFallback(final OneToOneAssociation prop) {
+        return selectRendererForProperty(prop)
+                .orElseGet(()->fallbackRenderer(prop.getFeatureIdentifier()));
+    }
+
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/ValueFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/ValueFacetAbstract.java
index f2d44e9..fcb6974 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/ValueFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/ValueFacetAbstract.java
@@ -22,21 +22,29 @@ import java.util.Optional;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
+import org.springframework.beans.factory.annotation.Qualifier;
+
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.adapters.Parser;
+import org.apache.isis.applib.adapters.Renderer;
 import org.apache.isis.applib.adapters.ValueSemanticsProvider;
 import org.apache.isis.applib.adapters.ValueSemanticsProvider.Context;
 import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._NullSafe;
+import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.commons.internal.reflection._Annotations;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FacetHolderAbstract;
+import org.apache.isis.core.metamodel.facets.objectvalue.fileaccept.FileAcceptFacet;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 
 import lombok.Getter;
+import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
 
 public abstract class ValueFacetAbstract<T>
@@ -64,44 +72,154 @@ implements ValueFacet<T> {
     }
 
     @Override
+    public boolean semanticEquals(@NonNull final Facet other) {
+        return (other instanceof ValueFacetAbstract)
+                ? this.getValueSemantics().equals(((ValueFacetAbstract)other).getValueSemantics())
+                : false;
+    }
+
+    @Override
     public final LogicalType getValueType() {
         return getFacetHolder().getFeatureIdentifier().getLogicalType();
     }
 
     @Override
+    public ValueSemanticsProvider.Context createValueSemanticsContext() {
+        final var iaProvider = super.getInteractionProvider();
+        if(iaProvider==null) {
+            return null; // JUnit context
+        }
+        return ValueSemanticsProvider.Context.of(
+                ((FacetHolderAbstract)getFacetHolder()).getFeatureIdentifier(),
+                iaProvider.currentInteractionContext().orElse(null));
+    }
+
+    // -- PARSER
+
+    @Override
     public Optional<Parser<T>> selectParserForParameter(final ObjectActionParameter param) {
-        return streamParsers(s->true) // TODO filter by qualifier if any
+        return streamValueSemanticsHonoringQualifiers(param)
+                .map(ValueSemanticsProvider::getParser)
+                .filter(_NullSafe::isPresent)
                 .findFirst();
     }
 
     @Override
     public Optional<Parser<T>> selectParserForProperty(final OneToOneAssociation prop) {
-        return streamParsers(s->true) // TODO filter by qualifier if any
+        return streamValueSemanticsHonoringQualifiers(prop)
+                .map(ValueSemanticsProvider::getParser)
+                .filter(_NullSafe::isPresent)
                 .findFirst();
     }
 
     @Override
     public Parser<T> fallbackParser(final Identifier featureIdentifier) {
-        return new ReadonlyMissingParserMessageParser<T>(String
+        return new PseudoParserWithMessage<T>(String
                 .format("Could not find a parser for type %s "
                         + "in the context of %s",
                         getValueType(),
                         featureIdentifier));
     }
 
+    // -- RENDERER
+
+    @Override
+    public Optional<Renderer<T>> selectRendererForParameter(final ObjectActionParameter param) {
+        return streamValueSemanticsHonoringQualifiers(param)
+                .map(ValueSemanticsProvider::getRenderer)
+                .filter(_NullSafe::isPresent)
+                .findFirst();
+    }
+
+    @Override
+    public Optional<Renderer<T>> selectRendererForProperty(final OneToOneAssociation prop) {
+        return streamValueSemanticsHonoringQualifiers(prop)
+                .map(ValueSemanticsProvider::getRenderer)
+                .filter(_NullSafe::isPresent)
+                .findFirst();
+    }
+
+    @Override
+    public Renderer<T> fallbackRenderer(final Identifier featureIdentifier) {
+        return new PseudoRendererWithMessage<T>(String
+                .format("Could not find a renderer for type %s "
+                        + "in the context of %s",
+                        getValueType(),
+                        featureIdentifier));
+    }
+
     // -- HELPER
 
-    private Stream<Parser<T>> streamParsers(
-            final Predicate<ValueSemanticsProvider<T>> semanticsFilter) {
+    private Stream<ValueSemanticsProvider<T>> streamValueSemanticsHonoringQualifiers(
+            final FacetHolder feature) {
         return getValueSemantics()
                 .stream()
-                .filter(semanticsFilter)
-                .map(ValueSemanticsProvider::getParser)
-                .filter(_NullSafe::isPresent);
+                .filter(isMatchingAnyOf(qualifiersAccepted(feature)));
+    }
+
+    private Can<String> qualifiersAccepted(final FacetHolder feature) {
+        return feature.lookupFacet(FileAcceptFacet.class)
+        .map(FileAcceptFacet::value) // TODO use a new qualifier facet instead
+        .map(_Strings::emptyToNull)
+        .stream()
+        .collect(Can.toCan());
+
+//      System.err.printf("got: %s %s%n",
+//      prop.getFeatureIdentifier(),
+//      qualifiersRequired);
+//if(prop.getFeatureIdentifier().getLogicalType().getClassName().contains("AsciiDocValueSemanticsWithPreprocessing")
+//      || prop.getFeatureIdentifier().getLogicalType().getClassName().contains("HasAsciiDocDescription")
+//      ) {
+//  System.out.println("bingo: " + qualifiersRequired);
+//}
+    }
+
+    private Predicate<ValueSemanticsProvider<T>> isMatchingAnyOf(final Can<String> qualifiersAccepted) {
+        return valueSemantics->{
+
+            // qualifiers required vs. qualifiers present on bean type
+            // 1. empty     vs. empty      ->  accept
+            // 2. empty     vs. not-empty  ->  reject
+            // 3. not-empty vs. empty      ->  reject
+            // 4. not-empty vs. not-empty  ->  accept when any match
+
+            final var qualifiersOnBean =
+            _Annotations
+            .synthesizeInherited(valueSemantics.getClass(), Qualifier.class) //TODO memoize somewhere
+            .map(Qualifier::value)
+            .stream()
+            .map(_Strings::emptyToNull)
+            .collect(Can.toCan());
+
+            if(qualifiersAccepted.isEmpty()
+                    && qualifiersOnBean.isEmpty()) {
+                return true;
+            }
+
+            if(qualifiersAccepted.isNotEmpty()
+                    && qualifiersOnBean.isNotEmpty()) {
+                return qualifiersAccepted.stream().anyMatch(qualifiersOnBean::contains);
+            }
+
+            return false;
+        };
+    }
+
+    @RequiredArgsConstructor
+    private final static class PseudoRendererWithMessage<T>
+    implements Renderer<T> {
+
+        private final String message;
+
+        @Override
+        public String presentationValue(final Context context, final T value) {
+            return message;
+        }
+
     }
 
     @RequiredArgsConstructor
-    private final static class ReadonlyMissingParserMessageParser<T>
+    private final static class PseudoParserWithMessage<T>
     implements Parser<T> {
 
         private final String message;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/vsp/ValueFacetUsingSemanticsProviderFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/vsp/ValueFacetUsingSemanticsProviderFactory.java
index db4fe5d..4e43b58 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/vsp/ValueFacetUsingSemanticsProviderFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/vsp/ValueFacetUsingSemanticsProviderFactory.java
@@ -31,10 +31,13 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.object.defaults.DefaultedFacetUsingDefaultsProvider;
 import org.apache.isis.core.metamodel.facets.object.encodeable.encoder.EncodableFacetUsingEncoderDecoder;
-import org.apache.isis.core.metamodel.facets.object.title.parser.TitleFacetUsingRenderer;
+import org.apache.isis.core.metamodel.facets.object.title.parser.TitleFacetUsingValueFacet;
 import org.apache.isis.core.metamodel.facets.object.value.ImmutableFacetViaValueSemantics;
 import org.apache.isis.core.metamodel.facets.object.value.MaxLengthFacetUsingParser;
 import org.apache.isis.core.metamodel.facets.object.value.TypicalLengthFacetUsingParser;
+import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
+
+import lombok.val;
 
 public abstract class ValueFacetUsingSemanticsProviderFactory<T>
 extends FacetFactoryAbstract {
@@ -45,26 +48,30 @@ extends FacetFactoryAbstract {
 
     @Deprecated
     protected final void addValueFacet(final ValueSemanticsProviderAndFacetAbstract<T> valueSemantics) {
-        FacetUtil.addFacet(
-                new ValueFacetUsingSemanticsProvider(Can.ofSingleton(valueSemantics), valueSemantics.getFacetHolder()));
-        installRelatedFacets(Can.of(valueSemantics), valueSemantics.getFacetHolder());
+        val valueFacet = new ValueFacetUsingSemanticsProvider(
+                Can.ofSingleton(valueSemantics), valueSemantics.getFacetHolder());
+        installRelatedFacets(valueFacet, Can.of(valueSemantics), valueSemantics.getFacetHolder());
     }
 
     protected final void addAllFacetsForValueSemantics(
             final Can<ValueSemanticsProvider<?>> valueSemantics,
             final FacetHolder holder) {
-        FacetUtil.addFacet(
-                new ValueFacetUsingSemanticsProvider(valueSemantics, holder));
-        installRelatedFacets(valueSemantics, holder);
+
+        val valueFacet = new ValueFacetUsingSemanticsProvider(valueSemantics, holder);
+        installRelatedFacets(valueFacet, valueSemantics, holder);
     }
 
     // -- HELPER
 
     private void installRelatedFacets(
+            final ValueFacet<?> valueFacet,
             final Can<ValueSemanticsProvider<?>> semanticsProviders,
             final FacetHolder holder) {
 
+        FacetUtil.addFacet(valueFacet);
+
         holder.addFacet(new ImmutableFacetViaValueSemantics(holder));
+        holder.addFacet(TitleFacetUsingValueFacet.create(valueFacet, holder));
 
         semanticsProviders
         .forEach(semanticsProvider->{
@@ -76,11 +83,6 @@ extends FacetFactoryAbstract {
                 holder.addFacet(new EncodableFacetUsingEncoderDecoder(encoderDecoder, holder));
             }
 
-            final Renderer<?> renderer = semanticsProvider.getRenderer();
-            if (renderer != null) {
-                holder.addFacet(TitleFacetUsingRenderer.create(renderer, holder));
-            }
-
             // install the ParseableFacet and other facets if we've been given a
             // Parser
             final Parser<?> parser = semanticsProvider.getParser();
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ParameterNegotiationModel.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ParameterNegotiationModel.java
index 993da19..c726b7a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ParameterNegotiationModel.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ParameterNegotiationModel.java
@@ -18,19 +18,14 @@
  */
 package org.apache.isis.core.metamodel.interactions.managed;
 
-import java.util.Optional;
 import java.util.stream.IntStream;
 
 import org.springframework.lang.Nullable;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.adapters.Parser;
-import org.apache.isis.applib.adapters.ValueSemanticsProvider;
 import org.apache.isis.commons.binding.Bindable;
 import org.apache.isis.commons.binding.Observable;
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.commons.internal.assertions._Assert;
-import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.binding._BindableAbstract;
 import org.apache.isis.commons.internal.binding._Bindables;
 import org.apache.isis.commons.internal.binding._Observables;
@@ -39,7 +34,6 @@ import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.consent.Consent;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.consent.InteractionResult;
-import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/title/TitleServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/title/TitleServiceDefault.java
index 9d62ae3..748f294 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/title/TitleServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/title/TitleServiceDefault.java
@@ -28,7 +28,7 @@ import org.springframework.stereotype.Service;
 import org.apache.isis.applib.annotation.PriorityPrecedence;
 import org.apache.isis.applib.services.title.TitleService;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
-import org.apache.isis.commons.internal.functions._Predicates;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ManagedObjects.EntityUtil;
@@ -46,7 +46,6 @@ public class TitleServiceDefault implements TitleService {
     private final WrapperFactory wrapperFactory;
     private final ObjectManager objectManager;
 
-
     @Override
     public String titleOf(final Object domainObject) {
 
@@ -64,7 +63,10 @@ public class TitleServiceDefault implements TitleService {
         if(EntityUtil.isDetachedOrRemoved(objectAdapter)) {
             return "[DETACHED]";
         } else {
-            return objectAdapter.getSpecification().getTitle(_Predicates.alwaysFalse(), objectAdapter);
+            return objectAdapter.getSpecification().getTitle(
+                    TitleRenderRequest.builder()
+                    .object(objectAdapter)
+                    .build());
         }
     }
 
@@ -87,7 +89,7 @@ public class TitleServiceDefault implements TitleService {
 
     //-- HELPER
 
-    private Object unwrapped(Object domainObject) {
+    private Object unwrapped(final Object domainObject) {
         return wrapperFactory != null ? wrapperFactory.unwrap(domainObject) : domainObject;
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
index e801194..f9a2cab 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
@@ -20,17 +20,17 @@ package org.apache.isis.core.metamodel.spec;
 
 import java.util.Optional;
 import java.util.function.Function;
-import java.util.function.Predicate;
 import java.util.function.Supplier;
+import java.util.function.UnaryOperator;
 
 import org.springframework.lang.Nullable;
 
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
-import org.apache.isis.commons.internal.functions._Predicates;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.facets.object.icon.ObjectIcon;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 
@@ -75,12 +75,15 @@ public interface ManagedObject {
 
     // -- TITLE
 
-    public default String titleString() {
-        return titleString(_Predicates.alwaysFalse());
+    public default String titleString(final UnaryOperator<TitleRenderRequest.TitleRenderRequestBuilder> onBuilder) {
+        return ManagedObjects.TitleUtil
+                .titleString(onBuilder.apply(TitleRenderRequest.builder().object(this)).build());
     }
 
-    default String titleString(final @NonNull Predicate<ManagedObject> isContextAdapter) {
-        return ManagedObjects.TitleUtil.titleString(this, isContextAdapter);
+    public default String titleString() {
+        return ManagedObjects.TitleUtil.titleString(TitleRenderRequest.builder()
+                .object(this)
+                .build());
     }
 
     // -- SHORTCUTS - MM CONTEXT
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java
index 1bb6fb1..10b90a1 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java
@@ -55,6 +55,7 @@ import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.facets.collections.CollectionFacet;
 import org.apache.isis.core.metamodel.facets.object.entity.EntityFacet;
 import org.apache.isis.core.metamodel.facets.object.entity.PersistenceStandard;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
 import org.apache.isis.core.metamodel.interactions.InteractionHead;
 import org.apache.isis.core.metamodel.interactions.InteractionUtils;
 import org.apache.isis.core.metamodel.interactions.ObjectVisibilityContext;
@@ -405,9 +406,9 @@ public final class ManagedObjects {
 
         // -- TITLE SUPPORT
 
-        String titleString(
-                final @Nullable ManagedObject managedObject,
-                final @NonNull Predicate<ManagedObject> isContextAdapter) {
+        String titleString(@NonNull final TitleRenderRequest titleRenderRequest) {
+
+            val managedObject = titleRenderRequest.getObject();
 
             if(!ManagedObjects.isSpecified(managedObject)) {
                 return "unspecified object";
@@ -417,19 +418,20 @@ public final class ManagedObjects {
                 val collectionFacet = managedObject.getSpecification().getFacet(CollectionFacet.class);
                 return collectionTitleString(managedObject, collectionFacet);
             } else {
-                return objectTitleString(managedObject, isContextAdapter)
+                return objectTitleString(titleRenderRequest)
                         .trim();
             }
         }
 
         // -- HELPER
 
-        private String objectTitleString(final ManagedObject managedObject, final Predicate<ManagedObject> isContextAdapter) {
+        private String objectTitleString(@NonNull final TitleRenderRequest titleRenderRequest) {
+            val managedObject = titleRenderRequest.getObject();
             if (managedObject.getPojo() instanceof String) {
                 return (String) managedObject.getPojo();
             }
             val spec = managedObject.getSpecification();
-            return Optional.ofNullable(spec.getTitle(isContextAdapter, managedObject))
+            return Optional.ofNullable(spec.getTitle(titleRenderRequest))
                     .orElseGet(()->getDefaultTitle(managedObject));
         }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java
index f6cab8f..67c1f9e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java
@@ -25,7 +25,6 @@ import java.lang.reflect.Modifier;
 import java.util.Comparator;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.function.Predicate;
 import java.util.stream.Stream;
 
 import org.springframework.lang.Nullable;
@@ -58,6 +57,7 @@ import org.apache.isis.core.metamodel.facets.object.icon.ObjectIcon;
 import org.apache.isis.core.metamodel.facets.object.immutable.ImmutableFacet;
 import org.apache.isis.core.metamodel.facets.object.parented.ParentedCollectionFacet;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
 import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
 import org.apache.isis.core.metamodel.interactions.InteractionContext;
@@ -229,9 +229,9 @@ extends
      * of some other adapter (if any).
      *
      * <p>
-     * @see TitleFacet#title(Predicate, ManagedObject)
+     * @see TitleFacet#title(TitleRenderRequest)
      */
-    String getTitle(Predicate<ManagedObject> isContextAdapter, ManagedObject targetAdapter);
+    String getTitle(TitleRenderRequest titleRenderRequest);
 
     /**
      * Returns the name of an icon to use for the specified object.
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
index 0913d6b..68a8dc5 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
@@ -69,6 +69,7 @@ import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacet;
 import org.apache.isis.core.metamodel.facets.object.navparent.NavigableParentFacet;
 import org.apache.isis.core.metamodel.facets.object.parented.ParentedCollectionFacet;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
 import org.apache.isis.core.metamodel.interactions.InteractionContext;
 import org.apache.isis.core.metamodel.interactions.InteractionUtils;
 import org.apache.isis.core.metamodel.interactions.ObjectTitleContext;
@@ -402,12 +403,9 @@ implements ObjectSpecification {
     }
 
     @Override
-    public String getTitle(
-            final Predicate<ManagedObject> isContextAdapter,
-            final ManagedObject targetAdapter) {
-
+    public String getTitle(final TitleRenderRequest titleRenderRequest) {
         if (titleFacet != null) {
-            val titleString = titleFacet.title(isContextAdapter, targetAdapter);
+            val titleString = titleFacet.title(titleRenderRequest);
             if (!_Strings.isEmpty(titleString)) {
                 return titleString;
             }
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/title/annotation/TitleAnnotationFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/title/annotation/TitleAnnotationFacetFactoryTest.java
index 0aacdc4..f5ce06d 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/title/annotation/TitleAnnotationFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/title/annotation/TitleAnnotationFacetFactoryTest.java
@@ -37,6 +37,7 @@ import org.apache.isis.core.metamodel.facets.AbstractFacetFactoryJUnit4TestCase;
 import org.apache.isis.core.metamodel.facets.Evaluators;
 import org.apache.isis.core.metamodel.facets.FacetFactory.ProcessClassContext;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
 import org.apache.isis.core.metamodel.facets.object.title.annotation.TitleAnnotationFacetFactory;
 import org.apache.isis.core.metamodel.facets.object.title.annotation.TitleFacetViaTitleAnnotation;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -257,7 +258,7 @@ extends AbstractFacetFactoryJUnit4TestCase {
                 allowing(mockIntegerSpec).isParentedOrFreeCollection();
                 will(returnValue(false));
 
-                allowing(mockIntegerSpec).getTitle(with(any(Predicate.class)), with(any(ManagedObject.class)));
+                allowing(mockIntegerSpec).getTitle(with(any(TitleRenderRequest.class)));
                 will(returnValue("3"));
 
                 ignoring(mockIntegerSpec).assertPojoCompatible(with(any(Integer.class)));
@@ -265,7 +266,10 @@ extends AbstractFacetFactoryJUnit4TestCase {
 
             }
         });
-        final String title = titleFacetViaTitleAnnotation.title(mockObjectAdapter);
+        final String title = titleFacetViaTitleAnnotation.title(
+                TitleRenderRequest.builder()
+                .object(mockObjectAdapter)
+                .build());
         assertThat(title, is("titleElement1 titleElement3 titleElement5 3 this needs to be trimmed"));
     }
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/testspec/ObjectSpecificationStub.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/testspec/ObjectSpecificationStub.java
index d24a87c..0abaaa1 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/testspec/ObjectSpecificationStub.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/testspec/ObjectSpecificationStub.java
@@ -44,6 +44,7 @@ import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaFactor
 import org.apache.isis.core.metamodel.facets.object.icon.ObjectIcon;
 import org.apache.isis.core.metamodel.facets.object.immutable.ImmutableFacet;
 import org.apache.isis.core.metamodel.facets.object.logicaltype.LogicalTypeFacet;
+import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
 import org.apache.isis.core.metamodel.interactions.ObjectTitleContext;
 import org.apache.isis.core.metamodel.interactions.ObjectValidityContext;
 import org.apache.isis.core.metamodel.spec.ActionType;
@@ -214,9 +215,7 @@ implements ObjectSpecification {
     }
 
     @Override
-    public String getTitle(
-            final Predicate<ManagedObject> isContextAdapter,
-            final ManagedObject targetAdapter) {
+    public String getTitle(final TitleRenderRequest titleRenderRequest) {
         return title;
     }
 
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/_infra/asciidocdesc/HasAsciiDocDescription_description.java b/examples/demo/domain/src/main/java/demoapp/dom/_infra/asciidocdesc/HasAsciiDocDescription_description.java
index d15b1f4..9140f60 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/_infra/asciidocdesc/HasAsciiDocDescription_description.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/_infra/asciidocdesc/HasAsciiDocDescription_description.java
@@ -31,7 +31,8 @@ import lombok.RequiredArgsConstructor;
 
 import demoapp.dom._infra.resources.AsciiDocReaderService;
 
-@Property(snapshot = Snapshot.EXCLUDED)
+@Property(snapshot = Snapshot.EXCLUDED
+    , fileAccept = "demo-adoc-pre-processor") //TODO ISIS-2871 yet just a hack, used as a marker to select a different value-semantics
 @RequiredArgsConstructor
 public class HasAsciiDocDescription_description {
 
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/_infra/resources/AsciiDocValueSemanticsWithPreprocessing.java b/examples/demo/domain/src/main/java/demoapp/dom/_infra/resources/AsciiDocValueSemanticsWithPreprocessing.java
index 388802c..b16bb82 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/_infra/resources/AsciiDocValueSemanticsWithPreprocessing.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/_infra/resources/AsciiDocValueSemanticsWithPreprocessing.java
@@ -5,15 +5,22 @@ import javax.inject.Named;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Component;
 
+import org.apache.isis.applib.adapters.ValueSemanticsProvider;
+import org.apache.isis.valuetypes.asciidoc.applib.value.AsciiDoc;
 import org.apache.isis.valuetypes.asciidoc.metamodel.semantics.AsciiDocValueSemantics;
 
 @Component
 @Named("demo.AsciiDocValueSemantics")
-@Qualifier("adoc-pre-processor")
+@Qualifier("demo-adoc-pre-processor")
 public class AsciiDocValueSemanticsWithPreprocessing
-//extends AsciiDocValueSemantics
-{
+extends AsciiDocValueSemantics {
 
     //FIXME add pre-processing stuff
 
+    @Override
+    public String presentationValue(final ValueSemanticsProvider.Context context, final AsciiDoc adoc) {
+        return render(adoc, __->"Hello World!");
+                //AsciiDoc::asHtml);
+    }
+
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/icontitle/EntityIconAndTitlePanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/icontitle/EntityIconAndTitlePanel.java
index b53f33c..40e78a8 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/icontitle/EntityIconAndTitlePanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/icontitle/EntityIconAndTitlePanel.java
@@ -191,7 +191,7 @@ extends PanelAbstract<ManagedObject, ObjectAdapterModel> {
         return new Label(id, title);
     }
 
-    private String titleAbbreviated(String titleString) {
+    private String titleAbbreviated(final String titleString) {
         int maxTitleLength = abbreviateTo(getModel(), titleString);
         return abbreviated(titleString, maxTitleLength);
     }
@@ -206,11 +206,11 @@ extends PanelAbstract<ManagedObject, ObjectAdapterModel> {
     private String determineTitle() {
         val managedObject = getModel().getObject();
         return managedObject != null
-                ? managedObject.titleString(this::isContextAdapter)
+                ? managedObject.titleString(conf->conf.skipTitlePartEvaluator(this::isContextAdapter))
                 : "(no object)";
     }
 
-    private int abbreviateTo(ObjectAdapterModel model, String titleString) {
+    private int abbreviateTo(final ObjectAdapterModel model, final String titleString) {
         if(model.getRenderingHint().isInStandaloneTableTitleColumn()) {
             return getWicketViewerSettings().getMaxTitleLengthInStandaloneTables();
         }
@@ -233,7 +233,7 @@ extends PanelAbstract<ManagedObject, ObjectAdapterModel> {
         return image;
     }
 
-    private boolean isContextAdapter(ManagedObject other) {
+    private boolean isContextAdapter(final ManagedObject other) {
         final ObjectAdapterModel model = getModel();
         return model.isContextAdapter(other);
     }