Skip to main content

Using IUserPanelMenuFactory in Plug-ins

Goal​

The goal of this tutorial is to show how to use the IUserPanelMenuFactory service in your plug-in project. Use this service to add custom entries to the WebUI user panel (the menu that contains Feedback, Preference, Change Role, and Log Out).

Custom User Menu

Prerequisites​

Before you start, review the following tutorials:

Workflow​

Step 1: Create a plug-in​

Create a new plug-in (or use an existing one). In Eclipse, go to File > New > Other, select Plug-in Project from the Plug-in Development section, and follow the wizard. Make sure the OSGi framework is set to Equinox.

Step 2: Implement IUserPanelMenuFactory​

Create a class that implements IUserPanelMenuFactory:

package org.evenos.menutest;

import org.adempiere.webui.factory.IUserPanelMenu;
import org.adempiere.webui.factory.IUserPanelMenuFactory;

public class MenuFactory implements IUserPanelMenuFactory {

@Override
public IUserPanelMenu getImplementation() {
return null;
}

}

Step 3: Create a component definition​

Go to File > New > Other and select Component Definition from the Plug-in Development section. Give it a unique name.

In the component definition, provide a unique name (use reverse domain notation, e.g. org.evenos.menutest.menufactory). Select your MenuFactory class, add a service.ranking integer property with a value > 0, and on the Services tab select org.adempiere.webui.panel.IUserPanelMenuFactory as a provided service.

The resulting XML will look like this:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.evenos.menutest.menufactory">
<implementation class="org.evenos.menutest.MenuFactory"/>
<service>
<provide interface="org.adempiere.webui.factory.IUserPanelMenuFactory"/>
</service>
<property name="service.ranking" type="Integer" value="100"/>
</scr:component>

Step 4: Implement IUserPanelMenu​

Create another class that implements IUserPanelMenu:

package org.evenos.menutest;

import org.adempiere.webui.factory.IUserPanelMenu;
import org.adempiere.webui.panel.UserPanelMenu;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;

public class MenuImplementation implements IUserPanelMenu {

@Override
public void onEvent(Event event) throws Exception {
// TODO Auto-generated method stub
}

@Override
public UserPanelMenu[] getMenus() {
// TODO Auto-generated method stub
return null;
}

@Override
public void setComponent(Component component) {
// TODO Auto-generated method stub
}

}

Return an instance of this class from your factory:

public class MenuFactory implements IUserPanelMenuFactory {
@Override
public IUserPanelMenu getImplementation() {
return new MenuImplementation();
}
}

Step 5: Define menu IDs and implement getMenus()​

Use private static final strings for menu IDs. In getMenus(), create UserPanelMenu objects and return them. UserPanelMenu provides static factory methods for menus with images, without images, or without a name label:

private final static String MENU_ONE_ID = "org.evenos.menu.one";
private final static String MENU_TWO_ID = "org.evenos.menu.two";
private final static String MENU_THREE_ID = "org.evenos.menu.three";

@Override
public UserPanelMenu[] getMenus() {
UserPanelMenu menu1 = UserPanelMenu.get(
MENU_ONE_ID,
Msg.getMsg(Env.getCtx(), MENU_ONE_ID),
"desktop-header-font link",
ThemeManager.getThemeResource("images/BPartner10.png"),
"Tooltip 1");
UserPanelMenu menu2 = UserPanelMenu.getWithoutImage(
MENU_TWO_ID,
Msg.getMsg(Env.getCtx(), MENU_TWO_ID),
"desktop-header-font link",
"Tooltip 2");
UserPanelMenu menu3 = UserPanelMenu.getWithoutName(
MENU_THREE_ID,
"desktop-header-font link",
ThemeManager.getThemeResource("images/BPartner10.png"),
"Tooltip 3");
return new UserPanelMenu[] { menu1, menu2, menu3 };
}

Store the component for later use in event handling:

private Component component;

@Override
public void setComponent(Component component) {
this.component = component;
}

Step 6: Add a popup menu (optional)​

Create a popup menu in the constructor:

private Menupopup myMenu;

private final static String MENU_ITEM_ONE_ID = "org.evenos.menuitem.one";
private final static String MENU_ITEM_TWO_ID = "org.evenos.menuitem.two";

public MenuImplementation() {
myMenu = new Menupopup();
Menuitem mi = new Menuitem(Msg.getMsg(Env.getCtx(), MENU_ITEM_ONE_ID));
mi.setId(MENU_ITEM_ONE_ID);
myMenu.appendChild(mi);
mi.addEventListener(Events.ON_CLICK, this);
mi = new Menuitem(Msg.getMsg(Env.getCtx(), MENU_ITEM_TWO_ID));
mi.setId(MENU_ITEM_TWO_ID);
mi.addEventListener(Events.ON_CLICK, this);
myMenu.appendChild(mi);
}

Step 7: Implement onEvent()​

Handle menu button clicks in onEvent():

@Override
public void onEvent(Event event) throws Exception {
if (event.getTarget().getId().equals(MENU_ONE_ID)) {
if (myMenu.getPage() == null) {
component.appendChild(myMenu);
}
myMenu.open(event.getTarget(), "after_start");
} else if (event.getTarget().getId().equals(MENU_TWO_ID)) {
FDialog.ask(0, component, "Do something?", new Callback<Boolean>() {
@Override
public void onCallback(Boolean result) {
}
});
} else if (event.getTarget().getId().equals(MENU_THREE_ID)) {
System.out.println("Menu three pressed");
} else if (event.getTarget() instanceof Menuitem) {
Menuitem mi = (Menuitem) event.getTarget();
if (MENU_ITEM_ONE_ID.equals(mi.getId())) {
System.out.println("Menuitem one pressed");
} else if (MENU_ITEM_TWO_ID.equals(mi.getId())) {
System.out.println("Menuitem two pressed");
}
}
}

Step 8: Create messages and test​

Log in as System Administrator and create message entries for each menu ID in the Message window:

Custom User Menu

After a cache reset (Process: Cache Reset) and re-login, you should see your new menu entries:

Custom User Menu

Custom User Menu

Custom User Menu

Troubleshooting​

  • Make sure the plug-in is loaded and started correctly.
  • If you use a custom theme, make sure theme/<themename>/zul/desktop/header.zul is loaded and uses the UserPanel class. If you have a custom UserPanel implementation, make sure it loads additional menus in addAdditionalMenus().