@PropertyLayout

Collects together all layout hints for a property of a domain object.

API

PropertyLayout.java
@interface PropertyLayout {
  String cssClass() default "";     (1)
  String describedAs() default "";     (2)
  String fieldSetId() default "__infer";     (3)
  String fieldSetName() default "__infer";     (4)
  Where hidden() default Where.NOT_SPECIFIED;     (5)
  LabelPosition labelPosition() default LabelPosition.NOT_SPECIFIED;     (6)
  int multiLine() default -1;     (7)
  String named() default "";     (8)
  Navigable navigable() default Navigable.NOT_SPECIFIED;     (9)
  PromptStyle promptStyle() default PromptStyle.NOT_SPECIFIED;     (10)
  Repainting repainting() default Repainting.NOT_SPECIFIED;     (11)
  String sequence() default "";     (12)
  int typicalLength() default -1;     (13)
}
1 cssClass

Indicates the css class that a property should have, to allow more targeted styling in application.css .

2 describedAs

Description of this property, eg to be rendered in a tooltip.

3 fieldSetId

Specifies the id of associated FieldSet .XML layout is presentXML layout is absent

4 fieldSetName

Specifies the friendly-name of associated FieldSet .

5 hidden

Indicates where in the UI the property should not be visible.

6 labelPosition

In forms, positioning of the label (left, top or none) relative to the property value.

7 multiLine

For string properties (and parameters), render as a text area over specified number of lines.

8 named

Name of this property (overriding the name derived from its name in code).

9 navigable

Whether this property should be used to construct the navigable chain of breadcrumbs in the UI.

10 promptStyle

How the properties of this domain object are be edited, either PromptStyle#DIALOG dialog or PromptStyle#INLINE inline .

11 repainting

Indicates that the value held by the property never changes over time, even when other properties of the object do change.

12 sequence

The order of this member relative to other members in the same (layout) group, given in Dewey-decimal notation.

13 typicalLength

The typical entry length of a field, use to determine the optimum width for display.

Members

cssClass

Indicates the css class that a property should have, to allow more targeted styling in application.css .

describedAs

Description of this property, eg to be rendered in a tooltip.

fieldSetId

Specifies the id of associated FieldSet .XML layout is presentXML layout is absent

A FieldSet is a layout component for property grouping, that can either be specified via a Xxx.layout.xml file (with Xxx the domain object name) or is inferred by the framework via annotations (aka the programming model). FieldSet s are represented in-memory and requires a framework internal unique id per domain object type.

Following 2 scenarios have slightly different behavior:

When a XML layout is present, every FieldSet id is either explicitly specified in the file or may be inferred from a non-empty name . If the name is empty "" or missing, then the id within the file is mandatory.

If this Property is not already explicitly listed within the XML layout, we lookup the associated FieldSet in the XML layout file first matching by id using @PropertyLayout(fieldSetId=…​) if any, then falling back to matching by (friendly) name using @PropertyLayout(fieldSetName=…​)} if any.

We reify (in-memory) the associated FieldSet using @PropertyLayout(fieldSetId=…​) (if present) as its id and using @PropertyLayout(fieldSetId=…​) as its (friendly) name . While if no id is provided an id is inferred from the (friendly) name , in which case the (friendly) name must not be empty. Whereas if no (friendly) name is provided a (friendly) name is inferred from the id , in which case the id must not be empty.

With @PropertyLayout(sequence=…​) the relative position within that FieldSet can be specified.

fieldSetName

Specifies the friendly-name of associated FieldSet .

Explicitly specifying an empty "" friendly-name will suppress the FieldSet 's label from being rendered.

For a more in depth description see PropertyLayout#fieldSetId() .

hidden

Indicates where in the UI the property should not be visible.

labelPosition

In forms, positioning of the label (left, top or none) relative to the property value.

If not specified, the default depends upon the property value’s datatype (including whether the field is #multiLine() .

multiLine

For string properties (and parameters), render as a text area over specified number of lines.

If set to > 1, then #labelPosition() defaults to LabelPosition#TOP top .

named

Name of this property (overriding the name derived from its name in code).

A typical use case is if the desired name is a reserved Java keyword, such as default or package.

Whether this property should be used to construct the navigable chain of breadcrumbs in the UI.

Only one property can be annotated as such per domain class.

promptStyle

How the properties of this domain object are be edited, either PromptStyle#DIALOG dialog or PromptStyle#INLINE inline .

repainting

Indicates that the value held by the property never changes over time, even when other properties of the object do change.

Setting this attribute to RepaintPolicy.NO_REPAINT is used as a hint to the viewer to not repaint the property after an AJAX update of some other property/ies of the object have changed. This is primarily for performance, eg can improve the user experience when rendering PDFs/blobs.

Note that for this to work, the viewer will also ensure that none of the property’s parent component (such as a tab group panel) are re-rendered.

Design note: we considered implementing this an "immutable" flag on the Property annotation (because this flag is typically appropriate for immutable/unchanging properties of a domain object). However, we decided not to do that, on the basis that it might be interpreted as having a deeper impact within the framework than simply a hint for rendering.

sequence

The order of this member relative to other members in the same (layout) group, given in Dewey-decimal notation.

Also governs slot-in order for the layout group that collects all unreferenced Properties , unless overwritten via application scoped config option that enforced alphabetical order:_causeway.applib.annotation.propertyLayout.sequencePolicyIfUnreferenced_

An alternative is to use the Xxx.layout.xml file, where Xxx is the domain object name.

typicalLength

The typical entry length of a field, use to determine the optimum width for display.

Note: the Wicket viewer does not use this information.

Examples

For example:

public class ToDoItem {
    @PropertyLayout(
        cssClass="x-key",
        named="Description of this <i>item</i>",
        namedEscaped=false,
        describedAs="What needs to be done",
        labelPosition=LabelPosition.LEFT,
        typicalLength=80
    )
    public String getDescription() { /* ... */ }
    ...
}

As an alternative to using the @PropertyLayout annotation, a file-based layout can be used (and is generally to be preferred since it is more flexible/powerful).

The annotation is one of a handful (others including @Collection, @CollectionLayout and @Property) that can also be applied to the field, rather than the getter method. This is specifically so that boilerplate-busting tools such as Project Lombok can be used.

Usage Notes

As alternative to using the annotation, the dynamic file-based layout can generally be used instead.

Label Positioning

The labelPosition() element determines the positioning of labels for properties.

The positioning of labels is typically LEFT, but can be positioned to the TOP. The one exception is multiLine string properties, where the label defaults to TOP automatically (to provide as much real-estate for the multiline text field as possible).

For boolean properties a positioning of RIGHT is also allowed; this is ignored for all other types.

It is also possible to suppress the label altogether, using NONE.

For example:

import lombok.Getter;
import lombok.Setter;

public class ToDoItem {

    @PropertyLayout(
        labelPosition=LabelPosition.TOP
    )
    @Getter @Setter
    private String description;

    // ...
}

Default settings

If you want a consistent look-n-feel throughout the app, eg all property labels to the top, then it’d be rather frustrating to have to annotate every property.

Instead, a default can be specified using the causeway.applib.annotation.property-layout.label-position configuration property:

application.properties
causeway.applib.annotation.property-layout.label-position=TOP

or

application.properties
causeway.applib.annotation.property-layout.label-position=LEFT

If these are not present then the framework will render according to internal defaults. At the time of writing, this means labels are to the left for all datatypes except multiline strings.

Prompt Style

The promptStyle() element is used to specify whether, when editing a domain object property, the new value for the property is prompted by way of a dialog box, or is prompted using an inline panel (replacing the property on the page).

If the attribute is not set, then the value of the causeway.viewer.wicket.prompt-style configuration property is used. If this is itself not set, then an inline prompt is used.

For example:

import lombok.Getter;
import lombok.Setter;

public class Customer {

    @PropertyLayout(
        promptStyle=PromptStyle.INLINE  (1)
    )
    @Getter @Setter
    private String notes;

    // ...
}
1 prompt for the new value for the property using an inline panel Note that the value INLINE_AS_IF_EDIT does not make sense for properties; if specified then it will be interpreted as just INLINE.

Text boxes

The multiLine() element specifies that the text field for a string property should span multiple lines. It is ignored for other property types.

If set > 1 (as would normally be the case), then the default labelPosition defaults to TOP (rather than LEFT, as would normally be the case).

For example:

import lombok.Getter;
import lombok.Setter;

public class BugReport {

    @PropertyLayout(
        numberOfLines=10
    )
    @Getter @Setter
    private String stepsToReproduce;

    // ...
}

Here the stepsToReproduce property will be displayed in a text box of 10 rows.

The navigable() element allows to specify a domain object’s (or view’s) navigable parent, as utilized by the 'Where am I' feature.

For example, suppose:

@DomainObject
public class Company {
    // ...
}

then:

import lombok.Getter;
import lombok.Setter;

@DomainObject
public class Employee {

    @PropertyLayout(navigable=Navigable.PARENT)
    @Getter @Setter
    private Company myCompany;

    // ...
}

This points up to the Employee's parent Company.

For further details on using a navigable tree-structure, see Where am I in the user guide.

Descriptions

The describedAs() element is used to provide a short description of the property to the user.

In the Web UI (Wicket viewer) it is displayed as a 'tool tip'.

For example:

public class Customer {

    @PropertyLayout(
        describedAs = "The name that the customer has indicated " +
                      "that they wish to be addressed as " +
                      "(e.g. Johnny rather than Jonathan)")
    private String firstName;

    // ...
}

CSS Styling

The cssClass() element can be used to render additional CSS classes in the HTML (a wrapping <div>) that represents the property. Application-specific CSS can then be used to target and adjust the UI representation of that particular element.

For example:

import lombok.Getter;
import lombok.Setter;

public class ToDoItem {

    @PropertyLayout(cssClass="x-key")
    @Getter @Setter
    private LocalDate dueBy;

    // ...
}

Date intervals

The renderDay() element applies only to date properties whereby the date will be rendered as the day before the value actually held in the domain object. It is ignored for properties of other types.

This behaviour might at first glance appear odd, but the rationale is to support the use case of a sequence of instances that represent adjacent intervals of time. In such cases there would typically be startDate and endDate properties, eg for all of Q2. Storing this as a half-closed interval — eg [1-Apr-2015, 1-July-2015) — can substantially simplify internal algorithms; the endDate of one interval will correspond to the startDate of the next.

However, from an end-user perspective the requirement may be to render the interval as a fully closed interval; eg the end date should be shown as 30-Jun-2015.

This attribute therefore bridges the gap; it presents the information in a way that makes sense to an end-user, but also stores the domain object in a way that is easy work with internally.

For example:

import lombok.Getter;
import lombok.Setter;

public class Tenancy {

    @Getter @Setter
    private LocalDate startDate;

    @PropertyLayout(
        renderDay = RenderDay.AS_DAY_BEFORE
    )
    @Getter @Setter
    private LocalDate endDate;

    // ...
}

Smoother UI

The repainting() element is used to indicate that the value held by the property never changes over time, even when other properties of the object do change.

Setting this attribute to true is used as a hint to the viewer to not redraw the property after an AJAX update of some other property/ies of the object have changed. This is primarily for performance, eg can improve the user experience when rendering PDFs/blobs.

Note that for this to work, the viewer will also ensure that none of the property’s parent component (such as a tab group panel) are re-rendered.

Design note: we considered implementing this an "immutable" flag on the @Property annotation (because this flag is typically appropriate for immutable/unchanging properties of a domain object). However, we decided not to do that, on the basis that it might be interpreted as having a deeper impact within the framework than simply a hint for rendering.

For example:

import lombok.Getter;
import lombok.Setter;

public class Document {

    @PropertyLayout(
        repainting=Repainting.NO_REPAINT
    )
    @Getter @Setter
    private Blob blob;

    // ...
}

Names

The named() element explicitly specifies the property’s name, overriding the name that would normally be inferred from the Java source code.

We recommend that you only use this element when the desired name cannot be used in Java source code. Examples of that include a name that would be a reserved Java keyword (eg "package"), or a name that has punctuation, eg apostrophes.

The name is HTML escaped.

For example:

import lombok.Getter;
import lombok.Setter;

public class ToDoItem {

    @PropertyLayout(
        named="Description of this item"
    )
    @Getter @Setter
    private String description;

    // ...
}

Alternatives

The framework also provides a separate, powerful mechanism for internationalization.

Hiding properties

The hidden() element attribute indicates where (in the UI) the property should be hidden from the user.

The acceptable values for the where parameter are:

  • Where.EVERYWHERE or Where.ANYWHERE

    The property should be hidden everywhere.

  • Where.ANYWHERE

    Synonym for everywhere.

  • Where.OBJECT_FORMS

    The property should be hidden when displayed within an object form.

  • Where.PARENTED_TABLES

    The property should be hidden when displayed as a column of a table within a parent object’s collection.

  • Where.STANDALONE_TABLES

    The property should be hidden when displayed as a column of a table showing a standalone list of objects, for example as returned by a repository query.

  • Where.ALL_TABLES

    The property should be hidden when displayed as a column of a table, either an object’s * collection or a standalone list. This combines PARENTED_TABLES and STANDALONE_TABLES.

  • Where.NOWHERE

    The property should not be hidden, overriding any other metadata/conventions that would normally cause the property to be hidden.

The RestfulObjects viewer has only partial support for these Where enums.

Examples

For example:

import lombok.Getter;
import lombok.Setter;

public class Customer {

    @PropertyLayout(
        hidden=Where.ALL_TABLES
    )
    @Getter @Setter
    private int internalId;

    // ...
}

As one specific use case, if a property is annotated with @Title, then normally this should be hidden from all tables. Annotating with @Property(where=Where.NOWHERE) overrides this.

Alternatives

It is also possible to use @PropertyLayout#hidden to hide a property at the domain layer.

Typical (string) length

The typicalLength() element indicates the typical length of a string property. It is ignored for properties of other types.

The information is intended as a hint to the UI to determine the space that should be given to render a particular string property.

For example:

import lombok.Getter;
import lombok.Setter;

public class Customer {

    @javax.jdo.annotations.Column(length=30)
    @ParameterLayout(typicalLength=20)
    @Getter @Setter
    private String firstName;

    // ...
}
All that said, the Web UI (Wicket viewer) uses the maximum space available for all fields, so in effect ignores this element.