Using the menu component in a tree panel

Starting a new XEO Application leads you to create the basic XEO Models that comprise the application’s domain, their attributes and relations. Often you’ll also begin by implementing some business logic in events and methods. In parallel you can also deal with the viewers required to display and create instances of said models. The first viewer you’ll need to deal with is the “Main” viewer where you’ll have your application workspace and navigation menu.

If you ever used XEO Studio’s scaffolding option or Viewer wizard you may have already created a main viewer and you have noticed something like this in the viewers’ XML code.

<xvw:treePanel id="tree" renderComponent="false">

  <xvw:menu icon="resources/Ebo_Pef/ico16.gif" serverAction="#{viewBean.listObject}"
   target="Tab" text="Users"
   value="{viewerName:'Ebo_Perf/list.xvw', boql:'select Ebo_Perf'}" />

</treePanel>

If you preview a main viewer with such a tree panel declaration you’ll see something like the following:

Main viewer

Main Viewer

So as you can see, the xvw:treePanel component is used to create, unsurprisingly, tree panels, and the xvw:menu component is used to create the menu structure. Today’s post is all about the menu component.

Menu’s are hierarchical, meaning that if you create a menu component it will be displayed as a leaf in the tree, but if you create a menu nested in another menu, the top menu will be displayed as folder. See the following code:

<xvw:treePanel id="tree" renderComponent="false">
<xvw:menu icon="resources/Ebo_Perf/ico16.gif" serverAction="#{viewBean.listObject}"
  target="Tab" text="Users"
   value="{viewerName:'Ebo_Perf/list.xvw', boql:'select Ebo_Perf where 1=1'}" />
<xvw:menu text="Folder">
   <xvw:menu text="SubMenu 1"/>
    <xvw:menu text="SubMenu 2"/>
</xvw:menu>
</xvw:treePanel>

Which, in turn, will give you the following result:

Menus

Menus

You can nest menus as much as you like, beware of usability, though 😉

Menu Properties

The menu component has a set of properties, namely (not all are included see the documentation for further options):

  • text – The label of the menu
  • tooltip – The menu’s tool tip
  • icon – The menu’s icon (path to a 16×16 icon file)
  • serverAction – The action to execute when the menu is clicked
  • target – The target of the executed action (can be one of tab – opens in a new application tab, window, blank, top, download, self = default)
  • expanded – If the menu is a folder (has sub-menus) whether it should be expanded upon rendering (defaults to false)
  • profiles – a list of comma-separated string with the names of the profiles authorized to see this menu (if a user is logged with profile that it’s not part of the list, he won’t be able to see the menu (or click))
  • profile – Same as above, for a single profile.
  • value – Check the section bellow

Menu Actions

More important than what menus look like, is what they do. The action executed by a menu is declared in the serverAction property (as explained above). When in a Main viewer (backed by the netgest.bo.xwc.xeo.beans.XEOMainBean) you have a set of predefined actions that you can reuse (you can pass parameters to that action by using the value property); Let’s examine some of the available actions :

serverAction=’#{viewBean.listObject}’ – List Model Instance

This action is used to list instances of a specific Model, to use it you need to define the value property with a JSON Object with the following properties:

  • viewerName – The name of the viewer to open (should be a viewer backed by the XEOBaseList bean (or a bean derived from that one)
  • boql – The boql expression to execute (the result of the boql evaluation will be the instances to display)

So, imagine you have Model A and want to create a menu entry to list all instances of the model. You would create your menu like this (notice the value property as a JSON Object):

<xvw:menu icon="resources/ModelA/ico16.gif" serverAction="#{viewBean.listObject}"
  target="Tab" text="ModelA"
   value="{viewerName:'ModelA/list.xvw', boql:'select ModelA'}" />

Another important thing: Usually the target for these kind of actions is “tab” to open a new tab in the application and also, don’t forget the convention of having icons for each model under the resources/MODEL_NAME/ico16.gif and for viewer location webapps/default/viewers/MODEL_NAME/viewerName.xvw (usually list.xvw, edit.xvw and lookup.xvw).

serverAction=’#{viewBean.editObject}’  – Edit a specific model instance

You can also have the menu to open an edit viewer for a specific instance. It’s not very useful if declared in XML as it requires you to know the identifier (BOUI) of the instance, but you could do it like the following:

<xvw:menu icon="resources/ModelA/ico16.gif" serverAction="#{viewBean.editObject}"
 target="Tab" text="ModelA"
 value="{viewerName:'ModelA/edit.xvw', boui:12345}" />

Notice the JSON Object in the value property now has a “boui”.

serverAction=’#{viewBean.createObject}’  – Create a new model instance

A more interesting use is to have a menu that allows creating a new instance of a specific model, you can do it like this:

<xvw:menu icon="resources/ModelA/ico16.gif" serverAction="#{viewBean.createObject}"
 target="Tab" text="ModelA"
 value="{viewerName:'ModelA/edit.xvw', objectName:'ModelA'}" />

This time around the value property has the “objectName” property to indicate which XEO Model instance to create.

serverAction=’#{viewBean.openViewer}’   – Open a specific viewer

If, for instance, you created a specific viewer that isn’t related to the usual list/edit/lookup method, you can also open that viewer by using the “openViewer” action, like the following:

<xvw:menu icon="path/to/icon.png" serverAction="#{viewBean.openViewer}"
  target="Tab" text="Custom Viewer"
  value="{viewerName:'path/to/custom/viewer.xvw'}" />

 serverAction=’#{viewBean.openLink}’    – Open a URL

A not so common, but still useful feature is to open given URL in a new tab (be it google, or a JSP of yours) the difference is that you don’t need a JSON object for the value property, just the url, like this:

<xvw:menu icon="path/to/icon.png" serverAction="#{viewBean.openLink}"
 target="Tab" text="Open Link!"
 value="http://blog.corrspt.com" />

 

Custom Actions and Parameters

Of course, you are not limited to the default actions in the XEOMainBean, if you need something more specific you can always extend the XEOMainBean with a bean of your own and create a method (like the following):

public void openMyCustomViewer() { }

And declare the menu using serverAction=’#{viewBean.openMyCustomViewer}’ you can also do more. You can use the Menu’s value property to pass parameters to your method. For instance, imagine a menu declared like the following:

<xvw:menu icon="path/to/icon.png" serverAction="#{viewBean.openMyCustomViewer}"
 target="Tab" text="My Custom Viewer and Method"
  value="{param1:'value1',param2:'value2'}'" />

And in your java source you can retrieve the value of the parameters by doing the following:

XUIRequestContext oRequestContext = getRequestContext(); //Provided by the Bean
JSONObject o = new JSONObject( (String)((XUICommand)oRequestContext.getEvent().getSource()).getValue()  );

Having the variable “o” you can do o.get(“param1”) to retrieve the value associated with that key.

As you can see there’s a lot you can do with menus (they can also be used in toolbar components with mostly the same semantics, but that’s for another post 😉 )

If you have any doubts leave a comment here, or join the community at sourceforge.

Avoiding the copy-paste mistake when using Iterators in Java

If you’re reading this it’s probably because you’ve done something like this (iterating over two lists in same block of code):

//Iterating with no problems

Iterator<String> it = list.iterator();  

while (it.hasNext()){  

     String current = it.next;  

}  

//BUG!!!!!!

Iterator<String> it2 = list2.iterator();  

while (it2.hasNext()){  

     String current = it.next;  //Not using the correct iterator

}

Before anyone says anything, YES, YOU SHOULD USE FOREACH. But there are situations where you want access to the iterator (for instance, to remove an element using the iterator’s remove() method).

This little bug where you increment the wrong iterator variable is a pain in the neck to figure out sometimes and I read this really interesting piece of advice in Joshua Bloch’s Effective Java. Instead of using a while loop, use a for loop like this:

for (Iterator<String> it = list.iterator(); it.hasNext(); ){  

   String current = it.next();  

}

The snippet above allows you to reuse the “it” variable name as many times as you wish because, this time, the variable is declared inside the for loop thus, if you try to use it else where the compiler will generate an error (because the variable is only declared in the scope of the for loop) and you’ll avoid some debugging time 🙂

P.S – One could argue that you should iterate over each list inside separate methods, but the point of this post is to put the variable declaration in a narrower scope than the original idea (the one that creates the error in the first place).

Happy coding!

Scrollbars in a XEO Viewer

When creating an XEO Viewer you’ll probably run into the “scrollbar issue”.  Not all container components (such as panel or section) add scrollbars when the content exceeds the available space. In order for you to assure that your content is visible you need to wrap your content using the Tab component, like the following:

<xvw:tabs>

   <xvw:tab label='Test'>

       <!-- Your content goes here  -->

    </xvw:tab>

</xvw:tabs>

Which produces the following result:

Tab with Label and Scrollbar

Tab with Label and Scrollbar

 

 

 

 

 

 

 

 

 

This will make the scrollbar appear if needed. If you set a label for the tab (as in the example with the “Test” label) it will be rendered as such. If you don’t set a label for the tab it will still render the space for that empty label which is not very pretty. In order to make that go away you can use the renderTabBar property of the parent xvw:tabs component to make that tab bar disappear (but still use a tab component), like in the following listing:

<xvw:tabs renderTabBar='false'>

   <xvw:tab>

       <!-- Your content goes here  -->

    </xvw:tab>

</xvw:tabs>

Which will produce the following result (with scrollbars as needed) :

Tab with No Label and Scrollbar

Tab with No Label and Scrollbar

 

 

 

 

 

 

 

 

 

Happy coding!