3.11.2. Extending Screens

The platform supports creating new XML descriptors by inheriting them from the existing ones.

XML inheritance is implemented by specifying the parent descriptor path in the extends attribute of the root window element.

XML screen elements overriding rules:

  • If the extending descriptor has a certain element, the corresponding element will be searched for in the parent descriptor using the following algorithm:

    • If the overriding element has the id attribute, the corresponding element with the same id will be searched for.

    • If the search is successful, the found element is overridden.

    • Otherwise, the platform determines how many elements with the provided path and name are contained in the parent descriptor. If there is only one element, it is overridden.

    • If the search yields no result and there is either zero or more than one element with the given path and name in the parent descriptor, a new element is added.

  • The text for the overridden or added element is copied from the extending element.

  • All attributes from the extending element are copied to the overridden or added element. If attribute names match, the value is taken from the extending element.

  • By default, the new element is added to the end of the list of adjacent elements. In order to add a new element to the beginning or with an arbitrary index, you can do the following:

    • Define an additional namespace in the extending descriptor: xmlns:ext="http://schemas.haulmont.com/cuba/window-ext.xsd".

    • Add the ext:index attribute with a desired index, for example: ext:index="0" to the extending element.

In order to debug the descriptor conversion, you can output the resulting XML to the server log by specifying the TRACE level for the com.haulmont.cuba.gui.xml.XmlInheritanceProcessor logger in the Logback configuration file.

Extending Legacy Screens

The framework contains a number of screens implemented with legacy API for backward compatibility. Below are examples of extending screens of the User entity from the security subsystem.

First, consider a browser screen of the ExtUser entity:

ext-user-browse.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        xmlns:ext="http://schemas.haulmont.com/cuba/window-ext.xsd"
        extends="/com/haulmont/cuba/gui/app/security/user/browse/user-browse.xml">
    <layout>
        <groupTable id="usersTable">
            <columns>
                <column ext:index="2" id="address"/>
            </columns>
        </groupTable>
    </layout>
</window>

In this example, the descriptor is inherited from the standard User entities browser of the framework. The address column is added to the table with index 2, so it is displayed after login and name.

If you register a new screen in screens.xml with the same identifiers that were used for the parent screen, the new screen will be invoked everywhere instead of the old one.

<screen id="sec$User.browse"
        template="com/sample/sales/gui/extuser/extuser-browse.xml"/>
<screen id="sec$User.lookup"
        template="com/sample/sales/gui/extuser/extuser-browse.xml"/>

Similarly, let’s create an edit screen:

ext-user-edit.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        xmlns:ext="http://schemas.haulmont.com/cuba/window-ext.xsd"
        extends="/com/haulmont/cuba/gui/app/security/user/edit/user-edit.xml">
    <layout>
        <groupBox id="propertiesBox">
            <grid id="propertiesGrid">
                <rows>
                    <row id="propertiesRow">
                        <fieldGroup id="fieldGroupLeft">
                            <column>
                                <field ext:index="3" id="address" property="address"/>
                            </column>
                        </fieldGroup>
                    </row>
                </rows>
            </grid>
        </groupBox>
    </layout>
</window>

Register it in screens.xml with the identifier of the parent screen:

<screen id="sec$User.edit"
        template="com/sample/sales/gui/extuser/extuser-edit.xml"/>

Once all the above-mentioned actions are completed, the application will use ExtUser with the corresponding screens instead of the standard User entity of the platform.

Screen controller can be extended by creating a new class that is inherited from the base screen controller. The class name is specified in the class attribute of the root element of the extending XML descriptor; the usual rules of inheriting XML described above will apply.

Extending screens using CUBA Studio

In this example, we will add an Excel button to the customer browser table by extending the screen for the Customer entity from the Customer Management component described in Example of Application Component.

  1. Create a new project in Studio and add the Customer Management component.

  2. Select Generic UI in the project tree and click New > Screen in the context menu. Then select the Extend an existing screen on the Screen Templates tab. In the Extend Screen list, select customer-browse.xml. The new ext-customer-browse.xml and ExtCustomerBrowse.java files will be created in the web module.

  3. Open the ext-customer-browse.xml and switch to the Designer tab. The components of the parent screen are displayed in the designer workspace.

  4. Select the customersTable and add a new excel action.

  5. Add a button to the buttonsPanel linked to the customersTable.excel action.

As a result, the ext-customer-browse.xml code on the Text tab will look as follows:

ext-customer-browse.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
        messagesPack="com.company.sales2.web"
        extends="com/company/customers/web/customer/customer-browse.xml">
    <layout>
        <groupTable id="customersTable">
            <actions>
                <action id="excel" type="excel"/>
            </actions>
            <buttonsPanel id="buttonsPanel">
                <button id="excelButton" action="customersTable.excel"/>
            </buttonsPanel>
        </groupTable>
    </layout>
</window>

Consider the ExtCustomerBrowse screen controller.

ExtCustomerBrowse.java
@UiController("customers_Customer.browse")
@UiDescriptor("ext-customer-browse.xml")
public class ExtCustomerBrowse extends CustomerBrowse {
}

As the screen identifier customers_Customer.browse matches the identifier of a base screen, the new screen will be invoked everywhere instead of the old.