Just An Application

July 2, 2009

What’s New In MIDP 3.0 ? Part 22: LCDUI – Form Layout

Filed under: Java, JME, LCDUI, MIDP, MIDP3, MIDP3Issues, MIDP3LCDUI — Tags: , , , , , , , — Simon Lewis @ 7:39 am

1. Form Layout Model

  • a MIDlet may explicitly control the layout of Items in a Form visible on a Display

  • the layout of the Items in a Form is performed by an instance of a sub-class of the FormLayoutPolicy class

  • each Form can have an associated FormLayoutPolicy object

  • a FormLayoutPolicy object can only be constructed for use with a specific Form

  • each Item in a Form has the following layout specific data

    • height

    • width

    • the x co-ordinate of the Item’s top-left corner

    • the y co-ordinate of the Item’s top-left corner

  • for each Item the layout specific data may be marked as invalid.

  • each Item may also have a associated layout hint.

  • a Form’s FormLayoutPolicy object is responsible for setting all the layout specific data for a Form’s Items as appropriate.

  • the values of all the layout specific data of an Item persist between each request to a FormLayoutPolicy object to layout a Form’s Items.

  • when a Form’s Items needs to be laid out then

    1. if the Form has an associated FormPolicyObject it will be used. If not then

    2. the default Form layout mechanism which implements the MIDP 2 Form layout semantics will be used

  • if an Exception is thrown by a FormLayoutPolicy object’s doLayout() method
    then the FormLayoutObject is removed from the Form and the default Form layout mechanism will be used.

  • a Form’s FormLayoutPolicy object is also responsible for supporting Item traversal

  • if an Exception is thrown by a FormLayoutPolicy object’s getTraverse() method
    then the FormLayoutObject is removed from the Form.

Note

  • the documentation does not actually say what the x and y co-ordinates of an Item are

2. FormLayoutPolicy

The FormLayoutPolicy class is an abstract class which defines the interface used for the layout of the Items in a Form and their traversal, and provides methods to access layout specific Item data.

A custom policy for the layout and traversal of Items in a Form can be implemented by sub-classing the FormLayoutPolicy class and providing concrete implementations of the doLayout() and getTraversal() methods.

2.1 Layout Direction

The current default layout direction can be obtained by calling the Form method

	public static final int getLayoutDirection()

which will return one of the following constants defined in the Form class

  • DIRECTION_LTR

  • DIRECTION_RTL

denoting

  • left-to-right

  • right-to-left

respectively.

2.2 Getting The Form

The Form the FormLayoutPolicy object was constructed with can be obtained by calling the FormLayoutPolicy method

    protected final Form getForm()

2.3 Layout

When the Item’s belonging to a Form associated with a FormPolicyLayout object need to be laid out, the objects’s implementation of the FormLayoutPolicy method

    protected abstract void doLayout(
                                int   viewportX,
                                int   viewportY,
                                int   viewportWidth,
                                int   viewportHeight,
                                int[] totalSize)

is called.

The arguments

  • viewportX
  • viewportY
  • viewportWidth
  • viewportHeight

specify the area of the Form which needs to be laid out.

The totalSize argument is an out parameter and must be used to return the width and height of the Form, in the first,

    totalSize[0]

and second,

    totalSize[1] 

elements respectively.

When the method implementation is called the layout specific data for each Item is either in its initial state, or in the state it was left in the last time the Form was laid out.

If the method implementation completes without throwing an Exception the layout specific data of all Items in the Form is assumed to be valid irrespective of the reported status of the Item’s validity.

If the method implementation throws an Exception then the FormLayoutPolicy object is removed from the associated Form, and the form is laid out automatically as specified in MIDP 2

Notes

  1. it is unclear what the validity status of individual Items will actually be when the method is called. See here.

  2. the method is declared to throw an ArrayIndexOutOfBoundsException if

    the length of the totalSize array is less than 2.

    which is a little odd because

    1. it will be passed by the implementation which should really know better than to pass an array of the wrong size, and

    2. the implementation could actually throw any kind of RuntimeException it chooses in these circumstances

    This assumes of course that the MIDlet itself does not engage in a bizarre act of self-immolation and call the method itself, deliberately
    passing an array of the wrong size just to see what happens.

2.4 Item Traversal

When the user attempts to traverse the Items in a Form with an associated FormLayoutPolicy object, the object’s implementation of the

    protected abstract Item getTraverse(Item item, int dir)

method will be called.

The item argument specifies the current Item

The dir argument specifies the direction of the traversal using one of the following constants defined in the Canvas class

  • LEFT
  • RIGHT
  • UP
  • DOWN

The method should return the next Item in the direction specified, where the definition of next is policy specific. The method may return null indicating that it is not possible to traverse away from the current Item.

Notes

  1. the method is declared to throw the following exceptions

    • a NullPointerException if item is null

    • an IllegalArgumentException if item is not an Item contained in the Form associated with the FormLayoutPolicy object

    • an IllegalArgumentException if dir is not one of the four Canvas constants specified above

    yet this method is invoked by the implementation.

    Surely it can ensure that the item is not null and that the dir argument is legal ? Ensuring that the Item passed in is not simultaneously removed from the Form is not really an insuperable problem either.

3. ItemLayoutHint

An Item can have a layout hint which can be any object which implements the empty ItemLayoutHint interface.

The hint can be obtained by calling the Item’s

    public ItemLayoutHint getLayoutHint()

method.

The hint can be set by calling the Item’s

    public void setLayoutHint(ItemLayoutHint hint)

method.

Note

  • Although the Item class documentation says

    Some layout policy subclasses use additional layout hints that are set on Items using the setLayoutHint method.
    The current layout hint is available from the getLayoutHint method. Refer to the specific layout subclass for
    the types and values of hints.

    and the ItemLayoutHint documentation says

    Each layout subclass defines the classes that specify the hints it uses and how they affect layout. Refer to the subclasses of FormLayoutPolicy for a description of the layout hints accepted.

    there is only one sub-class of FormLayoutPolicy, namely TableLayoutPolicy and as it’s class documentation says it

    does not introduce any ItemLayoutHints.

4. Form Layout Support

4.1 Getting The Current FormLayoutPolicy Object

The current FormLayoutPolicy object of a Form can be obtained by calling the Form’s

    public FormLayoutPolicy getLayoutPolicy()

method, which will return an instance of FormLayoutPolicy, or null.

4.2 Setting The Current FormLayoutPolicy Object

The current FormLayoutPolicy object of a Form can be set by calling the Form’s

    public void setLayoutPolicy(FormLayoutPolicy layoutPolicy)

method.

The layoutPolicy argument must be either an instance of FormLayoutPolicy or null.

If layoutPolicy is an instance of FormLayoutPolicy, then it is an error if its getForm() method does not return this Form, and an IllegalArgumentException will be thrown.

4.3. Accessing The Form’s Items During Layout

During layout the Form’s Items can be accessed as usual using the Form’s

    public Item get(int itemNum)

method.

5. Accessing Layout Specific Item Data Using FormLayoutPolicy Methods

The FormLayoutPolicy methods for accessing layout specific Item data, below, can only be called directly, or indirectly, from the implementation of a doLayout() method or a getTraversal() method. If this constraint is not met then the method called will throw an IllegalStateException.

The Item passed to any method must be an Item contained in the Form associated with the FormLayoutPolicy object and an IllegalArgumentException will be thrown if it is not.

5.1 Is An Item’s Layout Specific Data Valid ?

The validity of an Item’s layout specific data can be determined using the FormLayoutPolicy object’s

    protected final boolean isValid(Item item)

method.

5.2 Setting The Validity Of An Item’s Layout Specific Data

The validity of an Item’s layout specific data can be set using the FormLayoutPolicy object’s

    protected final void setValid(Item item, boolean valid)

method.

5.3 Getting An Item’s Position

The x and y co-ordinates of an Item can be obtained by calling the FormLayoutPolicy object’s

    protected final int getX(Item item)

or

    rotected final int getY(Item item)

methods respectively.

5.4 Getting An Item’s Size

The height and width of an Item can be obtained by calling the FormLayoutPolicy object’s

    protected final int getHeight(Item item)

or

    rotected final int getWidth(Item item)

methods respectively.

5.5 Setting An Item’s Position

The position of an Item can be set using the FormLayoutPolicy object’s

    protected final void setPosition(Item item, int x, int y)

It is an error if either x, or y is less than zero, and an IllegalArgumentException will be thrown.

5.6 Setting An Item’s Size

The size of an Item can be set using the FormLayoutPolicy object’s

    protected final void setPosition(Item item, int width, int height)

It is an error if width, or height are less than the values returned by the methods Item.getMinimumWidth()
and Item.getMinimumHeight() respectively, and an IllegalArgumentException will be thrown.

Note

  • It is unclear what happens if an Item’s size or position is changed during a call to an implementation of the getTraversal() method

6. TableLayoutPolicy

The TableLayoutPolicy class is a sub-class of FormLayoutPolicy which will layout
a Form’s Items in columns.

6.1 Creating An Instance Of TableLayoutPolicy

An instance of TableLayoutPolicy can be created using the

    public TableLayoutPolicy(Form form, int columns)

constructor.

The form argument is the Form the instance is responsible for laying out.

The columns argument specifies the number of columns to use for the layout.

It is an error if columns is less than one, and an IllegalArgumentException will be thrown.

6.2 Item Layout

Items are laid out in the direction specified by the current default layout direction, and from top to bottom.

6.2.1 Column Widths

The width of a column is the width of the widest Item in the column.

The width of an Item is either

  • the Item’s minimum width if the layout directive Item.LAYOUT_SHRINK is set for the Item, or

  • the Item’s preferred width

If the width of an Item is less than the column width, and the layout directive Item.LAYOUT_EXPAND is set for the Item, it is expanded to the smaller of its preferred width and the column width.

6.2.2 Row Heights

The height of a row is the height of the tallest Item in the row.

The height of an Item is either

  • the Item’s minimum height if the layout directive Item.LAYOUT_VSHRINK is set for the Item, or

  • the Item’s preferred height

If the height of an Item is less than the row height, and the layout directive Item.LAYOUT_VEXPAND is set for the Item, it is expanded to the smaller of its preferred height and the row height.

6.3 Item Traversal

Assume a Form containing N items laid out in R rows. If the current Item is the i’th Item in the Form at row r and column c, then
if the direction passed to a TableLayoutPolicy object’s getTraversal(Item,int) is

  • Canvas.LEFT

    then if the default layout direction is

    • FormLayoutPolicy.DIRECTION_LTR

      the Item returned will be, if

      • i == 0

        the N-1’th item

      • i > 0

        the i-1’th Item

    • FormLayoutPolicy.DIRECTION_RTL

      the Item returned will be, if

      • i == N-1

        the 0’th Item

      • i < N-1

        the i+1’th Item

  • Canvas.RIGHT

    then if the default layout direction is

    • FormLayoutPolicy.DIRECTION_LTR

      then if

      • i == N-1

        the 0’th Item

      • i < N-1

        the i+1’th Item

    • FormLayoutPolicy.DIRECTION_RTL

      then if

      • i == 0

        the N-1’th item

      • i > 0

        the i-1’th Item

  • Canvas.UP

    the item returned will be, if

    • r == 0

    • the item in the R-1’th row and the c’th column

    • r > 0

    • the item in the r-1’th row and the c’th column

  • Canvas.DOWN

    the item returned will be, if

    • r == R-1

    • the item in the 0’th row and the c’th column

    • r > 0

    • the item in the r+1’th row and the c’th column

7. Issues

7.1 Item Validity

It is not clear what role an Item’s validity status plays. It can only be set by using the FormLayoutPolicy.setValidity(Item,boolean) method, which can only be called directly, or indirectly, from implementations of the FormLayoutPolicy.doLayout() and FormLayoutPolicy.getTraversal() methods, and according to the FormLayoutPolicy class documentation it can be ignored by the caller of the FormLayoutPolicy.doLayout() method.

After doLayout returns, the caller can assume that all of the Items within the viewport are valid and have valid positions and sizes and may display them as necessary; though the actual valid flags may not be set to true. (emphasis added)

so what is it for ?

There are some clues. Earlier in the FormLayoutPolicy class documentation it says

When the contents or size of Items change it maybe necessary to update the layout. When items change in a way that might require the layout to be updated the Items MUST be marked invalid by calling setValid(item, false). When a valid layout is needed, for example to display the Form, the doLayout method is called to compute and update, as necessary, the position and size of invalid Items. Only the doLayout method should set the valid item to true.

This almost makes sense except that the doLayout method (and the getTraversal method for some reason) are the only methods that can actually call the setValidity(Item,boolean) method and thus set the Item validity at all, and there is not a great deal of point by then.

In the FormLayoutPolicy.doLayout() method documentation it says

Any Item that has changed is invalid and its position and size may need to be updated and set as valid.

but it also says

The doLayout method should not make any changes to Item contents or invalidate Items.[Emphasis added]

so how does an Item ever get invalidated ?

One possible interpretation of all of this is that an Item is marked as invalid by the implementation when it is changed in some way. During Item layout the current validity of each Item can then be determined and invalid Items can then be laid out again and marked as valid once more. It would be better however if the specification actually said that this is what happens, especially what causes an Item to be invalidated, or if it doesn’t, what does.


Copyright (c) 2009 By Simon Lewis. All Rights Reserved.

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: