--
PedroRio - 19 Jan 2011
XEO Web Components - Introducing the API
In the previous chapters you generated viewers using XEO Studio's Scaffolding tool and went
through an explanation of the basics of XEO Viewers as well as
customized an edit viewer for the LIB_Book Object Model. In this chapter we'll introduce the Java API to use when creating your own custom viewers and beans, before that, however, you should create some instances of Object Models so that some of things you'll do in this chapter are visible.
Go the Main_Library.xvw viewer and add an entry for the list viewer of the LIB_Publisher Object Model with the following code:
<xvw:menu text='Publishers'
value="{viewerName:'LIB_Publisher/list.xvw', boql:select LIB_Publisher}"
target='Tab' serverAction="#{viewBean.listObject}" icon='resources/LIB_Publisher/ico16.gif'/>
And create a publisher with any name you like (Wrox Press, for example). Now add two book instances (for example book Beggining Spring Framework 2 and Professional Apache Tomcat 6), for the author you can use the previously created "John Doe" (or create a new one) and for the publisher use the newly created "Wrox Press" instance. The task in this section is to add a new tab to the LIB_Publisher and LIB_Author edit viewers, to display the list of each books that publishe/author has worked on. This will also be used to introduce the Java API that can be used.
Start by creating a new java class in the
org.examples.viewer.beans package with the name
LibPublisherEditBean and make it extend the
netgest.bo.xwc.xeo.beans.XEOEditBean class, then open the LIB_Publisher/edit.xvw file and change the classBean property to org.viewers.examples.viewers.beans.LibPublisherEditBean this will associate the viewer with this bean.
Next, add a new tab element, to the tabs container already present in the viewer, just like the following:
<xvw:tabs>
<xvw:tab label="Nucleus">
<xeo:bridge bridgeName='nucleus' >
<xvw:columns>
<xvw:columnAttribute width="150" label="Nucleus" dataField="SYS_CARDID"/>
</xvw:columns>
</xeo:bridge>
</xvw:tab>
<xvw:tab label="Published Books">
</xvw:tab>
</xvw:tabs>
In order to display a list of Object Model instances you'll use the xeo:list component which is essentially like xeo:bridge component used before, but tailored to display any list of instances (and not only lists that come from collection attributes). Since you'll be displaying books just use the title for the column, use the following code:
<xvw:tab label="Published Books">
<xeo:list targetList="#{viewBean.dataList}" >
<xvw:columns>
<xvw:columnAttribute width="150" dataField="title"/>
</xvw:columns>
</xeo:list>
</xvw:tab>
Notice the "targetList='#{viewBean.dataList}'" property. It tells the xeo:list component that its data source should come from the dataList property of the current bean. Switch the
LibPublisherBean and create a method like the following (you'll need to import
netgest.bo.xwc.components.connectors.DataListConnector):
public DataListConnector getDataList(){ }
The
DataListConnector interface represents a list of elements to display in a xvw:gridPanel component (or any component that derives from the xvw:gridPanel component, actually, like the xeo:bridge and xeo:list component. For the xeo:bridge and xeo:list components there's an implementation of the interface that allows to use elements from a boObjectList instance. Compose the method with the following:
public DataListConnector getDataList(){
String boqlExpression = "";
boObjectList listBooksOfPublisher = ObjectListManager.list(getEboContext(), boqlExpression);
return new XEOObjectListConnector(listBooksOfPublisher);
}
Essentially, to create a list of instances, you only need a XEOQL (BOQL) expression an a Context to pass to the list method of the
ObjectListManager class. The resulting set of instances is passed to the constructor of the
XEOObjectListConnector which an implementation of the
DataListConnector interface for lists of instances.The getEBoContext() method is available for any bean that extends the
XEOBaseBean (which is the case of the
XEOEditBean which is the bean you're extending in this situation)
The only situation here is what will be the XEOQL expression to retrieve all books from the current publisher, to do that, use the following query:
String boqlExpression = "select LIB_Book where publisher = " + getXEOObject().getBoui();
The
getXEOObject() method is available in the
XEOEditBean, which returns the current boObject instance being edited (in this situation, the publisher instance); since relations between instances are done using the instance's BOUI (Business Object Unique Identifier), you use the getBoui() method to complete the query. If the BOUI of the current publisher is 12345, the query would be
select LIB_Book where publisher = 12345.
If you do this, and now open the list of Publishers, open the "Wrox Press" instance and select the "Published Books" tab you should see the list of books like depicted in figure XWCIA.1.
Figure XWCIA.1 - List of books published by "Wrox Press"
A note before moving on to the next viewer. List (xeo:list) components are usually found inside list viewers which are associated with the
XEOBaseList bean, and that bean as a specific method to open an edit viewer from a double click of an item in the list. The
XEOEditBean does not have such a method and if you try double clicking on a line of the "Published Books" list it will trigger an error, to prevent that from happenning you'll either have to implement a method to respond to the double click event, or disabled that via the
onRowDblClick property, like in the following code:
<xeo:list targetList="#{viewBean.dataList}" onRowDblClick="">
<xvw:columns>
<xvw:columnAttribute width="150" dataField="title"/>
</xvw:columns>
</xeo:list>
Also, a
xeo:list component includes a default toolbar with the "New" button, which creates a new instance for that list. The problem here, again, is that the "New" button assumes the existence of a method that will perform that action and that method is available in the
XEOBaseList bean (but not on the
XEOEditBean). So, if anyone presses the "New" button on this viewer an error will be triggered; the solution to that will be either disabling the button, or implementing the method. Since there's not much sense in creating a book directly from the publisher's page, hiding the button seems a better choice, to do that, use the
renderToolBar property of the
xeo:list component, which will hide the entire toolbar of the list. The following code is the final version for this viewer.
<xeo:list targetList="#{viewBean.dataList}" onRowDoubleClick="" renderToolBar="false">
<xvw:columns>
<xvw:columnAttribute width="150" dataField="title"/>
</xvw:columns>
</xeo:list>
As an exercise, to the same to the LIB_Author edit viewer (i.e. add a tab with all books that that author has ever published). You'll need to do exactly the same as in the publisher's viewer, but the XEOQL expression is a little different.
Custom rendering of columns
Very often you'd like to make a custom render for a given column, instead of just presenting its value. The xvw:columnAttribute component which is used in gridPanels, list and bridges to choose which columns should appear in the viewer has precisely a property that lets you create your own custom render. For this example you'll take the list viewer of LIB_Book and change the columns that appear and one of the columns (the state) will have a special render so that instead of the state being the label "Available" / "Unavailable" it will display a small icon.
The first step is creating a new Java bean, based on the
XEOBaseList (to replace the one in the LIB_Book list viewer), name it
LibBookListBean and make it extend the
netgest.bo.xwc.xeo.beans.XEOBaseList bean (create it in the org.example.viewer.beans package). Open the LIB_Book list viewer and replace the
beanClass property with
org.example.viewer.beans.LibBookListBean. Next you'll need the icons representing the state of the book, you can use the two following icons (
) and save them as "book_available.png" and "book_unavailable.png" in the
webapps/default/Extras/Icons folder (you can you any other icon you'd like).
Open the
LibBookListBean and create the following method:
public GridColumnRenderer getMyRenderer() { }
The
GridColumnRenderer is an interface that
ColumnAttribute components accept in order to change the renderer of its value. The
GridColumnRenderer interface has a single method definition which is:
public String render(GridPanel grid, DataRecordConnector record, DataFieldConnector field)
The
render method will return the value to be displayed on a given column, it returns a string which can be HTML code (which allows you to display images, tables, or anything html provides). This method will be called once for every line in the corresponding gridPanel/list/bridge component for the given column where the renderer is being applied.
The render method receives three parameters. The
GridPanel (could be a List or Bridge component, because both extend from
GridPanel) where the column attribute is placed, a
DataRecordConnector instance and a
DataFieldConnector instance. A
DataRecordConnector is an interface representing a specific line in a list of elements. You used the
DataListConnector interface before to display the list of books of a publisher; each of those books in a
DataListConnector is represented by a
DataRecordConnector. The
DataFieldConnector is yet another interface which is tied to the
DataListConnector and
DataRecordConnector because it represents the value (and metadata) of a given column within a single line.
In order to complete this custom renderer, change the LIB_Book list viewer to the following:
<xeo:formList>
<xeo:list enableGroupBy='true'>
<xvw:columns>
<xvw:columnAttribute width="100" dataField="title" groupable='true'/>
<xvw:columnAttribute width="20" dataField='state' renderer='#{viewBean.myRenderer}'/>
<xvw:columnAttribute width="100" dataField="publisher"/>
<xvw:columnAttribute width="100" dataField="edition"/>
<xvw:columnAttribute width="100" dataField="authors"/>
<xvw:columnAttribute width="100" dataField="isbn"/>
</xvw:columns>
</xeo:list>
</xeo:formList>
Now go back to the bean and type/paste the following (inside the getMyRenderer method):
return new GridColumnRenderer() {
@Override
public String render(GridPanel grid, DataRecordConnector record, DataFieldConnector field) {
String state = field.getValue().toString(); //Retrieve the value of state lov
if(state.equals("0"))
return "<img src='Extras/Icons/book_add.png' title='Available'/>";
else
return "<img src='Extras/Icons/book_delete.png' title='Unavailable'/>";
}
};
If you recall from when the LIB_Book Modeling phase, the state attribute was connected to a XEO Lov, which has two values, "0" for Available and "1" for Available. You'll only have to check what's the value of the state attribute and return an HTML string with the link to the image (as depicted in the previous code). Save the bean, launch the project and go the list of books, the result should now be like the one depicted in figure XWCIA.2, bellow.
Figure XWCIA.2 - List viewer with custom renderer for a column
a
a
a
aa