Positional ordering proposal

Order of bindings and contexts can be set in module layer by relative ordering attributes. This proposal suggests to use Positional attributes instead.

Current state

Before going to details about solution let's recapitulate when the oder is important, how it is defined now and what are the most typical usecases clients are solving.

Where is the order important?

The order of bindings and subcontexts in context is significant in for example these cases:
  • Menu
Menu is defined as context. The context bindings represent menu actions. The context subcontexts represent submenus. Order of bindings and subcontext is important, because that is how the created menu will look like.
  • Toolbar
Similar to menu case the Toolbar is defined as Context. All bindings in that context are toolbar actions. The order of bindings is order of buttons in toolbar.
  • New from Template
Very similar to Menu case. A context is defined which contains all templates for New from Template action. The context bindings are (or will be) instances of wizard iterator. The context subcontexts represent subgroups of templates. Their order defines how the user will see them.
  • Options
The tree of options which can be seen in the left pane of Options dialog is similarly as Menu case is mapped directly to ordered Registry contexts and bindings.
  • Services
Compared to previous examples this is first non-visual case where ordering can be useful. Imagine that there is a service type (eg. Compiler) and context where all implementations of that service type should be stored (eg. JavaCompiler, ...). The services (that is the context bindings) will be presented to user in the order in which they were defined and choosen service will be always the first one.

However this case can be solved also differently by storing binding name of selected service in separate property and by presenting the services always sorted alphabetically.
  • Looks
Looks API is also non-visual example where sorting is important. For example composite look is defined as context which bindings and subcontexts are read in the defined order to create composite look.

How is the order specified?

The order is specified by relative ordering attributes set on context. Their syntax is:

<attr name="firstitem/seconditem" boolvalue="true"/>

where "firstitem" and "seconditem" are subcontext name or binding name. The resulting order is composed according to all relative ordering attributes.

What are common usecases?

Usecase 1

Module writer defines a context and wants to add into that context couple of bindings in some order.

Usecase 2

Module writer defines sharable context with some ordered items and want to suggest place(s) suitable for foreign bindings.

For example Editor module defines context for Editor popup menu actions and suggests a place in the popup menu where all third party actions should be placed.

Usecase 3

Module writer wants to register bindings into some shared context and want to place them into some position or into place suggested by context owner.

For example Refactoring module may want to add refactoring actions into Editor popup menu which was defined in Usecase 2 and it may want to put the actions either into the place which owner of the context suggested (that it the Editor in this case) or it may want to ignore it and put them into some other place.

Problems of current state

Current solution (let put aside lacks of the declarative format) works fine for Usecase 1, has undocumented support for Usecase 2 and has fragile support for Usecase 3.

The support for Usecase 3 is fragile because module writer has to use relative ordering attributes what means that they have to find an item from some foreign module according to which they will relative order their own items. The pitfall which is not obvious is that they should have module dependency on that module. Otherwise the module can be uninstalled and configured ordering will not work. On the other hand sometimes the module does not want or cannot have dependency on that module.

Solution

First it must be said that there is no magical solution which would solve this forever. The goal is to reasonably support all above mentioned usecases and to provide mechanism which is independent on the installed state of module without requiring inter-module dependencies.

Position

Each item (that is binding and context) has so called position value. The final order of items is calculated according to these positions. If two items with the same positions are found, the clash is reported to log and items will be listed in undefined order. But it should be feasible to at least return clashing items from that moment always in the same order.

It is expected that position would replace and deprecate relative ordering attributes.

Example of declaration could look like:

<folder name="MyMenu">

    <file name="actionC.instance">
       <attr name="position" floatvalue="30"/>
    </file>

    <file name="actionB.instance">
       <attr name="position" floatvalue="20"/>
    </file>

    <file name="actionA.instance">
       <attr name="position" floatvalue="10"/>
    </file>

    <folder name="subActions">
       <attr name="position" floatvalue="15"/>
   
       <!-- other items here-->

    </folder>

</folder>

and the resulting order of items of this context would be: actionA, subActions, actionB, actionC.

Using positions instead of relative names guarantees that installation/uninstallation of modules will not negatively affect the ordering.

The type of position attribute is float.

It is recommended to not treat position value as API. But on per case basis the change of the value might need to be properly documented and announced similarly as stable API change.

Ordered context

Not all contexts need to be ordered, but these which are must be marked as ordered. It has several purposes:
  • module writer adding an item to a context can see that context is ordered and that their item must have position specified
  • ordering methods can warn user when they are called on non-ordered context
  • any items which do not have position and are in ordered context can be logged with warning that their order will be undefined
So the correct above example should contains also:

<folder name="MyMenu">
    <attr name="ordered" boolvalue="true"/>

    <!-- ... -->

</folder>

Insertion point

Insertion point is place in the ordered context which is suitable for insertion of other items by other modules. Owners of ordered contexts can and should define one or more insertion points. The insertion point is logical ordering tag to which other clients can put their objects.

There will be no explicit support for insertion points. They can be easily simulated by providing a subcontext of special type which will act as insertion point. It is up to owners of such a context to define a contract how to mark the subcontext as insertion point and how the items in that insertion point will be treated.

Menu based on context example:

<folder name="MyMenu2">
    <attr name="ordered" boolvalue="true"/>

    <file name="actionA.instance">
       <attr name="position" intvalue="10"/>
    </file>

    <file name="actionB.instance">
       <attr name="position" intvalue="20"/>
    </file>

    <folder name="thirdPartyActionsPlace">
       <attr name="ordered" boolvalue="true"/>
       <attr name="position" intvalue="30"/>
       <attr name="type" stringvalue="section"/>

       <!-- this is section for third party actions.
            the JSeparators will be automatically added
            around the section if it is non-empty -->

    </folder

    <file name="actionC.instance">
       <attr name="position" intvalue="40"/>
    </file>

    <folder name="subMenu">
       <attr name="position" intvalue="30"/>

       <!-- all items here will be placed into regular submenu -->

    </folder

</folder>

Module which would like to extend that menu with its own items can use that insertion point by simply registering items into that context:

<folder name="MyMenu2">

    <folder name="thirdPartyActionsPlace">
        <file name="foreignAction.instance">
            <attr name="position" intvalue="10"/>
        </file>
    </folder>

</folder>

The menu creation code must handle two types of subcontexts: regular submenu and insertion point. Items from insertion point can be for example placed directly into the menu and separated by JSeparator if insertion point is non-empty. The position attribute in foreignAction is optional. It is used for ordering of items within the insertion point.

It is recommended to treat insertion point name as stable API. Thus owner of the context have to properly document names of all its insertion points, their semantics and how they are marked as insertion points.

The insertion points should be defined only by owners of the context. Otherwise it can happen again that module defining some insertion point was uninstalled and some other modules without dependency on that module are still referencing to that insertion point.

Order customization

The order of items in the context can be customized and stored as full order. If full order is specified on the context the position attributes and relative ordering attributes are ignored. The full order is stored as "fullorder" context attribute:

<folder name="MyMenu">
    <attr name="fullorder" stringvalue="actionA,actionB,thirdPartyActionsPlace/,.../"/>

    <!-- ... -->

</folder>

Order of items not specified in fullorder is undefined. Non-existing items specified in full order are ignored.

This mechanism can be used also for branding of order of items in the context.

Summary

Let's look back at the usecases and how they will be solved if this proposal is accepted:

Usecase 1 revisited

Module writer defines a context and wants to add into that context couple of bindings in some order.

They can use position for this.

Usecase 2 revisited

Module writer defines sharable context with some ordered items and want to suggest places suitable for foreign bindings.

They can use position for ordering of their items and define one or more insertion points for foreign clients.

Usecase 3 revisited

Module writer wants to register bindings into some shared context and want to place them into some position or into place suggested by context owner.

They can add their actions to insertion points or use position attribute.

Known limitations of this proposal

Clearly there can be position clashes.

Sorting according to display name

There exist usecase to sort menu actions (and possibly other types of items) alphabetically. This is related to handling of display names in Registry which is discussed separately and which also mentions sorting according to display name.

The problem with ordering according to object's display name is that Registry would have to be aware of object's display name. Either the Registry defines a storage for display name or it defines an interface for display name retrieval which is implemented by objects.

At the moment it is proposed to not support alphabetical sorting in Registry. That means no semantics about object name in Registry. The sorting of this type has to be solved by higher layers which already know the type of objects they are working with and which can reuse existing API of these objects for display name retrieval (e.g. Action.getValue(Action.NAME)).

Project Features

About this Project

openide was started in November 2009, is owned by Antonin Nebuzelsky, and has 78 members.
By use of this website, you agree to the NetBeans Policies and Terms of Use (revision 20160708.bf2ac18). © 2014, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo
 
 
Close
loading
Please Confirm
Close