Switching Menu type at application initialization time

Hi
I want to give users option to choose Main menu on the top or at side. My application has both type of menu designed. Each user will have option to select their default menu for which I maintain an Entity called MenuOption.

I wanted to use postInit() method but it seems it is not available for ext-MainWindow. Then tried to use the ready() method to hide the one not needed but it seems it is still not the right place as I am getting exception.


    @Override
    public void ready() {
        super.ready();
        if(menuOptionsDs.getItem().getMenuType().equalsIgnoreCase("top")){
            sideMenu.setVisible(false);
        }else{
            mainMenu.setVisible(false);
        }
    }

Here is the exception that I get when I hit the submit button for log-in.


02:48:58.799 WARN  c.h.c.w.a.loginwindow.AppLoginWindow - Unable to login
java.lang.NullPointerException: null
        at com.company.testsidemenusub.web.screens.ExtAppMainWindow.ready(ExtAppMainWindow.java:45) ~[app-web-0.1-SNAPSHOT.jar:na]
        at com.haulmont.cuba.gui.WindowManager.afterShowWindow(WindowManager.java:976) ~[cuba-gui-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.WebWindowManager.createTopLevelWindow(WebWindowManager.java:1530) ~[cuba-web-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.App.createTopLevelWindow(App.java:308) ~[cuba-web-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.DefaultApp.connectionStateChanged(DefaultApp.java:108) ~[cuba-web-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.AbstractConnection.fireConnectionListeners(AbstractConnection.java:272) ~[cuba-web-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.AbstractConnection.internalLogin(AbstractConnection.java:176) ~[cuba-web-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.AbstractConnection.update(AbstractConnection.java:123) ~[cuba-web-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.DefaultConnection.login(DefaultConnection.java:60) ~[cuba-web-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.app.loginwindow.AppLoginWindow.doLogin(AppLoginWindow.java:421) [cuba-web-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.app.loginwindow.AppLoginWindow.doLogin(AppLoginWindow.java:392) [cuba-web-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.app.loginwindow.AppLoginWindow.login(AppLoginWindow.java:317) [cuba-web-6.5.0.jar:6.5.0]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_112]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_112]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_112]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_112]
        at com.haulmont.cuba.gui.xml.DeclarativeAction.actionPerform(DeclarativeAction.java:92) [cuba-gui-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.gui.components.WebButton.performAction(WebButton.java:44) [cuba-web-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.gui.components.WebButton.lambda$new$61446b05$1(WebButton.java:36) [cuba-web-6.5.0.jar:6.5.0]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_112]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_112]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_112]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_112]
        at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:510) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:200) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:163) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:1037) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.vaadin.ui.Button.fireClick(Button.java:377) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.haulmont.cuba.web.toolkit.ui.CubaButton.fireClick(CubaButton.java:54) ~[cuba-web-6.5.0.jar:6.5.0]
        at com.vaadin.ui.Button$1.click(Button.java:54) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_112]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_112]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_112]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_112]
        at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:158) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:119) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.vaadin.server.communication.ServerRpcHandler.handleInvocation(ServerRpcHandler.java:444) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:409) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:274) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:90) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1422) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:385) ~[vaadin-server-7.7.8.cuba.4.jar:7.7.8.cuba.4]
        at com.haulmont.cuba.web.sys.CubaApplicationServlet.serviceAppRequest(CubaApplicationServlet.java:278) ~[cuba-web-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.sys.CubaApplicationServlet.service(CubaApplicationServlet.java:187) ~[cuba-web-6.5.0.jar:6.5.0]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[servlet-api.jar:na]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) ~[catalina.jar:8.5.9]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.9]
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-websocket.jar:8.5.9]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.9]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.9]
        at com.haulmont.cuba.web.sys.CubaHttpFilter.handleNotFiltered(CubaHttpFilter.java:108) ~[cuba-web-6.5.0.jar:6.5.0]
        at com.haulmont.cuba.web.sys.CubaHttpFilter.doFilter(CubaHttpFilter.java:95) ~[cuba-web-6.5.0.jar:6.5.0]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.9]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.9]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[catalina.jar:8.5.9]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[catalina.jar:8.5.9]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474) ~[catalina.jar:8.5.9]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) ~[catalina.jar:8.5.9]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) ~[catalina.jar:8.5.9]
        at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624) ~[catalina.jar:8.5.9]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) ~[catalina.jar:8.5.9]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349) ~[catalina.jar:8.5.9]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783) ~[tomcat-coyote.jar:8.5.9]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) ~[tomcat-coyote.jar:8.5.9]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:789) ~[tomcat-coyote.jar:8.5.9]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1437) ~[tomcat-coyote.jar:8.5.9]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-coyote.jar:8.5.9]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_112]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_112]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-util.jar:8.5.9]
        at java.lang.Thread.run(Thread.java:745) ~[na:1.8.0_112]

Here is my ext-MainWindow XML


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        caption="mainMsg://application.caption"
        class="com.company.testsidemenusub.web.screens.ExtAppMainWindow"
        xmlns:main="http://schemas.haulmont.com/cuba/mainwindow.xsd">
    <dsContext>
        <collectionDatasource id="menuOptionsDs"
                              class="com.company.testsidemenusub.entity.MenuOption"
                              view="_local">
            <query>
                <![CDATA[select e from testsidemenusub$MenuOption e]]>
            </query>
        </collectionDatasource>
    </dsContext>
    <layout expand="horizontalWrap"
            responsive="true"
            stylename="c-sidemenu-responsive">
        <main:menu id="mainMenu"/>
        <hbox id="horizontalWrap"
              expand="workArea"
              stylename="c-sidemenu-layout"
              width="100%">
            <cssLayout id="sideMenuPanel"
                       height="100%"
                       stylename="c-sidemenu-panel">
                <button id="mobileMenuButton"
                        caption="mainMsg://app.menu"
                        icon="icons/mobile-menu.png"
                        stylename="primary c-sidemenu-toggle"/>
                <hbox id="mobileButtonsBox"
                      stylename="c-sidemenu-mobile-buttons">
                    <main:newWindowButton id="mobileNewWindowButton"
                                          description="mainMsg://newWindowBtnDescription"
                                          icon="app/images/new-window.png"/>
                    <main:logoutButton id="mobileLogoutButton"
                                       description="mainMsg://logoutBtnDescription"
                                       icon="app/images/exit.png"/>
                </hbox>
                <hbox id="appTitleBox"
                      spacing="true"
                      stylename="c-sidemenu-title"
                      width="100%">
                    <label id="appTitleLabel"
                           value="mainMsg://application.logoLabel"/>
                </hbox>
                <cssLayout id="sideMenuWrap"
                           stylename="c-sidemenu-wrap">
                    <embedded id="logoImage"
                              align="MIDDLE_CENTER"
                              stylename="c-app-icon"
                              type="IMAGE"/>
                    <main:userIndicator id="userIndicator"
                                        width="100%"/>
                    <hbox id="mainButtonsBox"
                          stylename="c-main-buttons">
                        <main:newWindowButton id="newWindowButton"
                                              description="mainMsg://newWindowBtnDescription"
                                              icon="app/images/new-window.png"/>
                        <main:logoutButton id="logoutButton"
                                           description="mainMsg://logoutBtnDescription"
                                           icon="app/images/exit.png"/>
                    </hbox>
                    <main:timeZoneIndicator id="timeZoneIndicator"
                                            width="100%"/>
                    <main:sideMenu id="sideMenu"
                                   sidePanel="sideMenuPanel"
                                   sidePanelToggleButton="mobileMenuButton"/>
                    <main:ftsField id="ftsField"
                                   width="100%"/>
                </cssLayout>
            </cssLayout>
            <main:workArea id="workArea"
                           height="100%">
                <main:initialLayout margin="true"
                                    spacing="true">
                    <label id="welcomeLabel"
                           align="MIDDLE_CENTER"
                           stylename="c-welcome-text"
                           value="mainMsg://application.welcomeText"
                           width="100%"/>
                </main:initialLayout>
            </main:workArea>
        </hbox>
    </layout>
</window>

Thanks for your help.

1 Like

Hi,

First of all, your code produces NPE since menuOptionsDs.getItem() returns null. If you want to load data at init stage, do the following:

  1. Call refresh on your datasource to load data.
  2. Then obtain getItems()instead of getItem, since getItem return “current” item that is null if no one sets it.

Instead of your custom entity with simple settings for user I recommend that you use UserSettingService that we use for various user settings available from Help - Settings window. It is a service providing current user settings functionality: an application can save/load some “setting” (plain or XML string) for current user. In this case you don’t need to define a datasource, just call service methods to save/load setting values.

Hi Yuriy
Thanks. Then I would prefer using user settings.
Here is what I did,

  1. Extended the settings-window (ext-settings-window) - attached image (user-settings1.png)
  2. Added options (MenuType options group) in screen.
  3. Added the following codes in the controller to initiate options

  @Inject
    private UserSettingService userSettingService;

    @Inject
    protected OptionsGroup optionsgroupMenuType;

    @Override
    public void init(Map<String, Object> params) {
        super.init(params);
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("Side-Bar Menu", 1);
        map.put("Top-down Menu", 2);
        optionsgroupMenuType.setOptionsMap(map);
        optionsgroupMenuType.setOrientation(OptionsGroup.Orientation.HORIZONTAL);

        String menuOption = userSettingService.loadSetting("menuType");
        if(menuOption !=null){
            if (menuOption.equals(1)) {
                optionsgroupMenuType.setValue(1);
            } else {
                optionsgroupMenuType.setValue(2);
            }
        }
    }
  1. The user setting screen is nicely updated but not with the value I saved for the menu option (Attached)… If I am using the following codes in controller (invoked by Ok button) but not sure if it is the right event to use, thanks for the hints.

     public void onOkBtnClick() {
        userSettingService.saveSetting("menuType",optionsgroupMenuType.getValue());
        close(COMMIT_ACTION_ID);
    }

user_setting1

menuOption