/******************************************************************************
* Product: Posterita Ajax UI *
* Copyright (C) 2007 Posterita Ltd. All Rights Reserved. *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program is distributed in the hope *
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
* For the text or an alternative of this public license, you may reach us *
* Posterita Ltd., 3, Draper Avenue, Quatre Bornes, Mauritius *
* or via info@posterita.org or http://www.posterita.org/ *
*****************************************************************************/
package org.adempiere.webui.desktop;
import static org.compiere.model.SystemIDs.TREE_MENUPRIMARY;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.adempiere.base.event.EventManager;
import org.adempiere.base.event.IEventManager;
import org.adempiere.base.event.IEventTopics;
import org.adempiere.model.MBroadcastMessage;
import org.adempiere.util.Callback;
import org.adempiere.webui.ClientInfo;
import org.adempiere.webui.LayoutUtils;
import org.adempiere.webui.adwindow.ADWindow;
import org.adempiere.webui.apps.AEnv;
import org.adempiere.webui.apps.BusyDialog;
import org.adempiere.webui.apps.ProcessDialog;
import org.adempiere.webui.component.Tab;
import org.adempiere.webui.component.Tabpanel;
import org.adempiere.webui.component.ToolBar;
import org.adempiere.webui.component.ToolBarButton;
import org.adempiere.webui.component.Window;
import org.adempiere.webui.dashboard.DashboardPanel;
import org.adempiere.webui.event.MenuListener;
import org.adempiere.webui.event.ZKBroadCastManager;
import org.adempiere.webui.panel.ADForm;
import org.adempiere.webui.panel.BroadcastMessageWindow;
import org.adempiere.webui.panel.HeaderPanel;
import org.adempiere.webui.panel.HelpController;
import org.adempiere.webui.panel.InfoPanel;
import org.adempiere.webui.panel.TimeoutPanel;
import org.adempiere.webui.part.ITabOnSelectHandler;
import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.theme.ThemeManager;
import org.adempiere.webui.util.UserPreference;
import org.adempiere.webui.util.ZKUpdateUtil;
import org.compiere.model.GridField;
import org.compiere.model.GridTab;
import org.compiere.model.I_AD_Preference;
import org.compiere.model.MMenu;
import org.compiere.model.MPreference;
import org.compiere.model.MRole;
import org.compiere.model.MTable;
import org.compiere.model.MTreeFavorite;
import org.compiere.model.Query;
import org.compiere.model.SystemIDs;
import org.compiere.model.X_AD_CtxHelp;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.compiere.util.Util;
import org.compiere.util.WebUtil;
import org.idempiere.broadcast.BroadCastMsg;
import org.idempiere.broadcast.BroadCastUtil;
import org.idempiere.broadcast.BroadcastMsgUtil;
import org.osgi.service.event.EventHandler;
import org.zkoss.zk.au.out.AuScript;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.HtmlBasedComponent;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.EventQueue;
import org.zkoss.zk.ui.event.EventQueues;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zk.ui.event.SwipeEvent;
import org.zkoss.zk.ui.metainfo.PageDefinition;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zk.ui.util.DesktopCleanup;
import org.zkoss.zul.Anchorchildren;
import org.zkoss.zul.Anchorlayout;
import org.zkoss.zul.Borderlayout;
import org.zkoss.zul.Center;
import org.zkoss.zul.East;
import org.zkoss.zul.Image;
import org.zkoss.zul.Popup;
import org.zkoss.zul.West;
/**
*
* Default {@link IDesktop} implementation.
* @author Ashley G Ramdass
* @author Low Heng Sin
* @date Mar 2, 2007
* @version $Revision: 0.10 $
* @author Deepak Pansheriya/Vivek - Adding support for message broadcasting
*/
public class DefaultDesktop extends TabbedDesktop implements MenuListener, Serializable, EventListener, EventHandler, DesktopCleanup
{
/**
* generated serial id
*/
private static final long serialVersionUID = 7189914859100400758L;
private static final String IMAGES_UPARROW_PNG = "images/collapse-header.png";
private static final String IMAGES_DOWNARROW_PNG = "images/expand-header.png";
private static final String IMAGES_CONTEXT_HELP_PNG = "images/Help16.png";
private static final String IMAGES_THREELINE_MENU_PNG = "images/threelines.png";
private static final String POPUP_OPEN_ATTR = "popup.open";
private static final String HOME_TAB_RENDER_ATTR = "homeTab.render";
private static final String HELP_CONTROLLER_WIDTH_PREFERENCE = "HelpController.Width";
private static final String SIDE_CONTROLLER_WIDTH_PREFERENCE = "SideController.Width";
@SuppressWarnings("unused")
private static final CLogger logger = CLogger.getCLogger(DefaultDesktop.class);
/** Main layout. With id "layout" in desktop.zul */
private Borderlayout layout;
private int noCount;
/** Panel of home tab */
private Tabpanel homeTab;
private DashboardController dashboardController, sideController;
/** HeaderPanel of {@link #headerContainer}. With id "header" in desktop.zul */
private HeaderPanel pnlHead;
private Desktop m_desktop = null;
/** Renderer and controller for help and quick info panel */
private HelpController helpController;
/** Button to hide or show North desktop header. Visible for mobile client. */
private ToolBarButton max;
/** Button to hide or show help and quick info panels */
private ToolBarButton contextHelp;
/** Button to open north header popup. Visible when {@link #max} is true. */
private ToolBarButton showHeader;
/** Body component of north header. With id "northBody" in desktop.zul */
private Component headerContainer;
/** Popup open by {@link #showHeader} */
private Window headerPopup;
private Image logo;
/** true if client browser is a mobile browser */
private boolean mobile;
/** Help and quick info popup for mobile client */
private Popup eastPopup;
/** West panel popup for mobile client */
private Popup westPopup;
/** Button to show {@link #westPopup}. Visible for mobile client. */
private ToolBarButton westBtn;
// For quick info optimization
private GridTab gridTab;
/** True if Right side Quick info is visible */
private boolean isQuickInfoOpen = true;
/**
* Default constructor
*/
public DefaultDesktop()
{
super();
dashboardController = new DashboardController();
sideController = new DashboardController();
helpController = new HelpController();
m_desktop = AEnv.getDesktop();
m_desktop.addListener(this);
//subscribing to broadcast event
bindEventManager();
try {
ZKBroadCastManager.getBroadCastMgr();
} catch (Throwable e) {
e.printStackTrace();
}
EventQueue queue = EventQueues.lookup(ACTIVITIES_EVENT_QUEUE, true);
queue.subscribe(this);
}
/**
* Create desktop layout from "zul/desktop/desktop.zul".
*/
@SuppressWarnings("serial")
protected Component doCreatePart(Component parent)
{
PageDefinition pagedef = Executions.getCurrent().getPageDefinition(ThemeManager.getThemeResource("zul/desktop/desktop.zul"));
Component page = Executions.createComponents(pagedef, parent, null);
layout = (Borderlayout) page.getFellow("layout");
headerContainer = page.getFellow("northBody");
pnlHead = (HeaderPanel) headerContainer.getFellow("header");
West w = layout.getWest();
w.addEventListener(Events.ON_OPEN, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
OpenEvent oe = (OpenEvent) event;
updateMenuCollapsedPreference(!oe.isOpen());
}
});
w.addEventListener(Events.ON_SWIPE, new EventListener() {
@Override
public void onEvent(SwipeEvent event) throws Exception {
if ("left".equals(event.getSwipeDirection())) {
West w = (West) event.getTarget();
if (w.isOpen()) {
w.setOpen(false);
LayoutUtils.addSclass("slide", w);
updateMenuCollapsedPreference(true);
}
}
}
});
w.addEventListener(Events.ON_SIZE, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
West west = (West) event.getTarget();
updateSideControllerWidthPreference(west.getWidth());
}
});
UserPreference pref = SessionManager.getSessionApplication().getUserPreference();
boolean menuCollapsed= pref.isPropertyBool(UserPreference.P_MENU_COLLAPSED);
w.setOpen(!menuCollapsed);
if (!w.isOpen())
LayoutUtils.addSclass("slide", w);
mobile = ClientInfo.isMobile();
w.setCollapsible(true);
LayoutUtils.addSlideSclass(w);
if (mobile) {
w.setOpen(false);
}
East e = layout.getEast();
e.addEventListener(Events.ON_OPEN, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
OpenEvent oe = (OpenEvent) event;
isQuickInfoOpen = oe.isOpen();
updateHelpCollapsedPreference(!oe.isOpen());
HtmlBasedComponent comp = windowContainer.getComponent();
if (comp != null) {
contextHelp.setVisible(!oe.isOpen());
if (!oe.isOpen())
layout.getEast().setVisible(false);
}
}
});
e.addEventListener(Events.ON_SWIPE, new EventListener() {
@Override
public void onEvent(SwipeEvent event) throws Exception {
if ("right".equals(event.getSwipeDirection())) {
East e = (East) event.getTarget();
if (e.isOpen()) {
e.setOpen(false);
LayoutUtils.addSclass("slide", e);
updateHelpCollapsedPreference(true);
}
}
}
});
e.addEventListener(Events.ON_SIZE, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
East east = (East) event.getTarget();
updateHelpWidthPreference(east.getWidth());
}
});
String westWidth = getWestWidthPreference();
String eastWidth = getEastWidthPreference();
//Set preference width
if( westWidth != null || eastWidth != null ){
//If both panels have preferred size check that the sum is not bigger than the browser
if( westWidth != null && eastWidth != null ){
ClientInfo browserInfo = getClientInfo();
int browserWidth = browserInfo.desktopWidth;
int wWidth = Integer.valueOf(westWidth.replace("px", ""));
int eWidth = Integer.valueOf(eastWidth.replace("px", ""));
if( eWidth + wWidth <= browserWidth ){
ZKUpdateUtil.setWidth(w, westWidth);
ZKUpdateUtil.setWidth(e, eastWidth);
}
}
else if ( westWidth != null )
ZKUpdateUtil.setWidth(w, westWidth);
else if ( eastWidth != null )
ZKUpdateUtil.setWidth(e, eastWidth);
}
boolean helpCollapsed= pref.isPropertyBool(UserPreference.P_HELP_COLLAPSED);
e.setVisible(!helpCollapsed);
helpController.render(e, this);
if (mobile) {
e.setVisible(false);
e.setOpen(false);
Component content = e.getFirstChild();
eastPopup = new Popup();
ToolBarButton btn = new ToolBarButton();
btn.setIconSclass("z-icon-remove");
btn.addEventListener(Events.ON_CLICK, evt -> {
eastPopup.close();
isQuickInfoOpen = false;
});
eastPopup.appendChild(btn);
btn.setStyle("position: absolute; top: 20px; right: 0px; padding: 2px 0px;");
eastPopup.setStyle("padding-top: 20px;");
eastPopup.appendChild(content);
eastPopup.setPage(getComponent().getPage());
eastPopup.setHeight("100%");
helpController.setupFieldTooltip();
eastPopup.addEventListener(Events.ON_OPEN, (OpenEvent oe) -> {
isQuickInfoOpen = oe.isOpen();
});
westPopup = new Popup();
westPopup.setStyle("padding-top: 10px;");
westPopup.setPage(getComponent().getPage());
westPopup.setHeight("100%");
westPopup.addEventListener(Events.ON_OPEN, (OpenEvent oe) -> {
if (oe.isOpen()) {
westPopup.setAttribute(POPUP_OPEN_ATTR, Boolean.TRUE);
} else {
westPopup.removeAttribute(POPUP_OPEN_ATTR);
}
});
}
Center windowArea = layout.getCenter();
windowContainer.createPart(windowArea);
homeTab = new Tabpanel();
windowContainer.addWindow(homeTab, Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Home")), false, null);
homeTab.getLinkedTab().setSclass("desktop-hometab");
((Tab)homeTab.getLinkedTab()).setDisableDraggDrop(true);
homeTab.setSclass("desktop-home-tabpanel");
BusyDialog busyDialog = new BusyDialog();
busyDialog.setShadow(false);
homeTab.appendChild(busyDialog);
// register as 0
registerWindow(homeTab);
BroadcastMessageWindow messageWindow = new BroadcastMessageWindow(pnlHead);
BroadcastMsgUtil.showPendingMessage(Env.getAD_User_ID(Env.getCtx()), messageWindow);
if (!layout.getDesktop().isServerPushEnabled())
{
layout.getDesktop().enableServerPush(true);
}
Executions.schedule(layout.getDesktop(), event -> {
renderHomeTab();
automaticOpen(Env.getCtx());
}, new Event("onRenderHomeTab"));
ToolBar toolbar = windowContainer.getToobar();
if (!mobile) {
showHeader = new ToolBarButton() {
@Override
public void onPageDetached(Page page) {
super.onPageDetached(page);
if (DefaultDesktop.this.headerPopup != null) {
DefaultDesktop.this.headerPopup.setPage(null);
}
}
};
toolbar.appendChild(showHeader);
if (ThemeManager.isUseFontIconForImage())
showHeader.setIconSclass("z-icon-ThreeLineMenu");
else
showHeader.setImage(ThemeManager.getThemeResource(IMAGES_THREELINE_MENU_PNG));
showHeader.addEventListener(Events.ON_CLICK, this);
showHeader.setSclass("window-container-toolbar-btn");
showHeader.setVisible(false);
max = new ToolBarButton();
toolbar.appendChild(max);
if (ThemeManager.isUseFontIconForImage())
max.setIconSclass("z-icon-Collapsing");
else
max.setImage(ThemeManager.getThemeResource(IMAGES_UPARROW_PNG));
max.addEventListener(Events.ON_CLICK, this);
max.setSclass("window-container-toolbar-btn");
}
contextHelp = new ToolBarButton();
toolbar.appendChild(contextHelp);
if (ThemeManager.isUseFontIconForImage())
contextHelp.setIconSclass("z-icon-Help");
else
contextHelp.setImage(ThemeManager.getThemeResource(IMAGES_CONTEXT_HELP_PNG));
contextHelp.addEventListener(Events.ON_CLICK, this);
contextHelp.setSclass("window-container-toolbar-btn context-help-btn");
contextHelp.setTooltiptext(Util.cleanAmp(Msg.getElement(Env.getCtx(), "AD_CtxHelp_ID")));
contextHelp.setVisible(!e.isVisible());
isQuickInfoOpen = e.isVisible();
if (!mobile) {
boolean headerCollapsed= pref.isPropertyBool(UserPreference.P_HEADER_COLLAPSED);
if (headerCollapsed) {
collapseHeader();
}
}
if (mobile) {
westBtn = new ToolBarButton();
if (ThemeManager.isUseFontIconForImage())
westBtn.setIconSclass("z-icon-ThreeLineMenu");
else
westBtn.setImage(ThemeManager.getThemeResource(IMAGES_THREELINE_MENU_PNG));
westBtn.addEventListener(Events.ON_CLICK, this);
westBtn.setSclass("window-container-toolbar-btn");
westBtn.setStyle("cursor: pointer; padding: 0px; margin: 0px;");
}
return layout;
}
/**
* @return saved width for west panel. null if there's no saved width.
*/
private String getWestWidthPreference() {
String width = Env.getPreference(Env.getCtx(), 0, SIDE_CONTROLLER_WIDTH_PREFERENCE, false);
if( (! Util.isEmpty(width)) ){
ClientInfo browserInfo = getClientInfo();
int browserWidth = browserInfo.desktopWidth;
int prefWidth = Integer.valueOf(width.replace("px", ""));
if( prefWidth <= browserWidth )
return width;
}
return null;
}
/**
* Save width of west panel as user preference
* @param width
*/
protected void updateSideControllerWidthPreference(String width) {
if( width != null ){
Query query = new Query(Env.getCtx(),
MTable.get(Env.getCtx(), I_AD_Preference.Table_ID),
" Attribute=? AND AD_User_ID=? AND AD_Process_ID IS NULL AND PreferenceFor = 'W'",
null);
int userId = Env.getAD_User_ID(Env.getCtx());
MPreference preference = query.setOnlyActiveRecords(true)
.setApplyAccessFilter(true)
.setClient_ID()
.setParameters(SIDE_CONTROLLER_WIDTH_PREFERENCE, userId)
.first();
if ( preference == null || preference.getAD_Preference_ID() <= 0 ) {
preference = new MPreference(Env.getCtx(), 0, null);
preference.setAD_User_ID(userId);
preference.setAttribute(SIDE_CONTROLLER_WIDTH_PREFERENCE);
}
preference.setValue(width);
preference.saveEx();
}
}
/**
* @return saved width of east/help panel. null if there's no saved width.
*/
private String getEastWidthPreference() {
String width = Env.getPreference(Env.getCtx(), 0, HELP_CONTROLLER_WIDTH_PREFERENCE, false);
if( (! Util.isEmpty(width)) ){
ClientInfo browserInfo = getClientInfo();
int browserWidth = browserInfo.desktopWidth;
int prefWidth = Integer.valueOf(width.replace("px", ""));
if( prefWidth <= browserWidth )
return width;
}
return null;
}
/**
* Save width of east/help panel as user preference
* @param width
*/
protected void updateHelpWidthPreference(String width) {
if( width != null ){
Query query = new Query(Env.getCtx(),
MTable.get(Env.getCtx(), I_AD_Preference.Table_ID),
" Attribute=? AND AD_User_ID=? AND AD_Process_ID IS NULL AND PreferenceFor = 'W'",
null);
int userId = Env.getAD_User_ID(Env.getCtx());
MPreference preference = query.setOnlyActiveRecords(true)
.setApplyAccessFilter(true)
.setClient_ID()
.setParameters(HELP_CONTROLLER_WIDTH_PREFERENCE, userId)
.first();
if ( preference == null || preference.getAD_Preference_ID() <= 0 ) {
preference = new MPreference(Env.getCtx(), 0, null);
preference.setAD_User_ID(userId);
preference.setAttribute(HELP_CONTROLLER_WIDTH_PREFERENCE);
}
preference.setValue(width);
preference.saveEx();
}
}
/**
* Save west/menu panel collapsed state as user preference
* @param collapsed
*/
private void updateMenuCollapsedPreference(boolean collapsed) {
UserPreference pref = SessionManager.getSessionApplication().getUserPreference();
pref.setProperty(UserPreference.P_MENU_COLLAPSED, collapsed);
pref.savePreference();
}
/**
* Save east/help panel collapsed state as user preference
* @param collapsed
*/
private void updateHelpCollapsedPreference(boolean collapsed) {
UserPreference pref = SessionManager.getSessionApplication().getUserPreference();
pref.setProperty(UserPreference.P_HELP_COLLAPSED, collapsed);
pref.savePreference();
}
/**
* Save page/desktop header collapsed state as user preference
* @param collapsed
*/
private void updateHeaderCollapsedPreference(boolean collapsed) {
UserPreference pref = SessionManager.getSessionApplication().getUserPreference();
pref.setProperty(UserPreference.P_HEADER_COLLAPSED, collapsed);
pref.savePreference();
}
/**
* Render content of home tab.
* Delegate to {@link DashboardController#render(Component, IDesktop, boolean)}
*/
public void renderHomeTab()
{
homeTab.getChildren().clear();
dashboardController.render(homeTab, this, true);
if (homeTab.getFirstChild() != null) {
ITabOnSelectHandler handler = () -> {
invalidateDashboardPanel(homeTab.getFirstChild().getChildren());
};
homeTab.getFirstChild().setAttribute(ITabOnSelectHandler.ATTRIBUTE_KEY, handler);
}
homeTab.setAttribute(HOME_TAB_RENDER_ATTR, Boolean.TRUE);
West w = layout.getWest();
Component side = null;
if (mobile)
{
westPopup.getChildren().clear();
side = westPopup;
w.setVisible(false);
if (westBtn.getParent() == null)
{
Component menuSearchPanel = pnlHead.getFellow("menuLookup");
menuSearchPanel.getParent().insertBefore(westBtn, menuSearchPanel);
}
setSidePopupWidth(westPopup);
setSidePopupWidth(eastPopup);
}
else
{
w.getChildren().clear();
side = w;
}
sideController.render(side, this, false);
if (mobile)
{
ToolBarButton btn = new ToolBarButton();
btn.setIconSclass("z-icon-remove");
btn.addEventListener(Events.ON_CLICK, evt -> {
westPopup.close();
westPopup.removeAttribute(POPUP_OPEN_ATTR);
});
westPopup.appendChild(btn);
btn.setStyle("position: absolute; top: 10px; right: 0px; padding: 2px 0px;");
}
logo = pnlHead.getLogo();
if (mobile && logo != null)
{
Anchorchildren ac = new Anchorchildren();
ac.appendChild(logo);
ac.setStyle("padding: 4px;");
Anchorlayout layout = (Anchorlayout) side.getFirstChild();
layout.insertBefore(ac, layout.getFirstChild());
}
if (mobile)
{
pnlHead.invalidate();
}
homeTab.invalidate();
}
/**
* Redraw dashboard panel after switching back to home tab
* @param childrens
*/
private void invalidateDashboardPanel(List childrens) {
for (Component children : childrens) {
if (children instanceof DashboardPanel) {
children.invalidate();
} else {
invalidateDashboardPanel(children.getChildren());
}
}
}
/**
* Set width of popup for side panel
* @param popup
*/
protected void setSidePopupWidth(Popup popup) {
if (ClientInfo.minWidth(ClientInfo.LARGE_WIDTH))
popup.setWidth("30%");
else if (ClientInfo.minWidth(ClientInfo.MEDIUM_WIDTH))
popup.setWidth("40%");
else if (ClientInfo.minWidth(ClientInfo.SMALL_WIDTH))
popup.setWidth("50%");
else if (ClientInfo.minWidth(ClientInfo.EXTRA_SMALL_WIDTH))
popup.setWidth("60%");
else if (ClientInfo.minWidth(400))
popup.setWidth("70%");
else
popup.setWidth("80%");
}
@Override
public void onEvent(Event event)
{
Component comp = event.getTarget();
String eventName = event.getName();
if(eventName.equals(Events.ON_CLICK))
{
if (comp == max)
{
if (layout.getNorth().isVisible())
{
collapseHeader();
}
else
{
restoreHeader();
}
}
else if (comp == showHeader)
{
showHeader.setPressed(true);
if (pnlHead.getParent() != headerPopup)
headerPopup.appendChild(pnlHead);
LayoutUtils.openPopupWindow(showHeader, headerPopup, "after_start");
}
else if (comp == contextHelp)
{
if (mobile && eastPopup != null)
{
eastPopup.open(layout.getCenter(), "overlap_end");
isQuickInfoOpen = true;
updateHelpQuickInfo(gridTab);
}
else
{
layout.getEast().setVisible(true);
layout.getEast().setOpen(true);
LayoutUtils.removeSclass("slide", layout.getEast());
contextHelp.setVisible(false);
updateHelpCollapsedPreference(false);
isQuickInfoOpen = true;
updateHelpQuickInfo(gridTab);
}
}
else if (comp == westBtn)
{
westPopup.open(layout.getNorth(), "overlap_start");
westPopup.setAttribute(POPUP_OPEN_ATTR, Boolean.TRUE);
}
else if(comp instanceof ToolBarButton)
{
ToolBarButton btn = (ToolBarButton) comp;
if (btn.getAttribute("AD_Menu_ID") != null)
{
int menuId = (Integer)btn.getAttribute("AD_Menu_ID");
if(menuId > 0) onMenuSelected(menuId);
}
}
}
else if (eventName.equals(ON_ACTIVITIES_CHANGED_EVENT))
{
Integer count = (Integer) event.getData();
boolean change = false;
if (count != null && count.intValue() != noCount)
{
noCount = count.intValue(); change = true;
}
if (change)
updateUI();
}
}
/**
* Make page/desktop header visible again
*/
protected void restoreHeader() {
layout.getNorth().setVisible(true);
if (ThemeManager.isUseFontIconForImage())
max.setIconSclass("z-icon-Collapsing");
else
max.setImage(ThemeManager.getThemeResource(IMAGES_UPARROW_PNG));
showHeader.setVisible(false);
pnlHead.detach();
headerContainer.appendChild(pnlHead);
Clients.resize(pnlHead);
updateHeaderCollapsedPreference(false);
}
/**
* Hide page/desktop header
*/
protected void collapseHeader() {
layout.getNorth().setVisible(false);
if (ThemeManager.isUseFontIconForImage())
max.setIconSclass("z-icon-Expanding");
else
max.setImage(ThemeManager.getThemeResource(IMAGES_DOWNARROW_PNG));
showHeader.setVisible(true);
pnlHead.detach();
if (headerPopup == null)
{
headerPopup = new Window();
headerPopup.setSclass("desktop-header-popup");
ZKUpdateUtil.setVflex(headerPopup, "true");
headerPopup.setVisible(false);
headerPopup.addEventListener(Events.ON_OPEN, new EventListener() {
@Override
public void onEvent(OpenEvent event) throws Exception {
if (!event.isOpen()) {
if (showHeader.isPressed())
showHeader.setPressed(false);
}
}
});
}
headerPopup.appendChild(pnlHead);
updateHeaderCollapsedPreference(true);
}
/**
* @param page
*/
public void setPage(Page page) {
if (this.page != page) {
layout.setPage(page);
this.page = page;
if (dashboardController != null) {
dashboardController.onSetPage(page, layout.getDesktop());
}
if (sideController != null) {
sideController.onSetPage(page, layout.getDesktop());
}
}
}
/**
* Get the root component
* @return Component
*/
public Component getComponent() {
return layout;
}
@Override
public void logout() {
logout(null);
}
@Override
public void logout(Callback callback) {
if (layout != null && layout.getDesktop() != null
&& Executions.getCurrent() != null && Executions.getCurrent().getNativeRequest() != null) {
//close all tabs
List tabs = windowContainer.getComponent().getTabs().getChildren();
int end = tabs.size() - 1;
for (int i = end; i >= 0; i--) {
((Tab)tabs.get( i )).close();
}
AEnv.detachInputElement(layout);
layout.setVisible(false);
//schedule async logout
Executions.schedule(layout.getDesktop(), e -> asyncLogout(callback), new Event("onAsyncLogout"));
} else {
asyncLogout(callback);
}
}
/**
* Asynchronous logout. Call by {@link #logout(Callback)}.
* This is to workaround client side detached element leak.
* @param callback
*/
private void asyncLogout(Callback callback) {
unbindEventManager();
if (dashboardController != null) {
dashboardController.onLogOut();
dashboardController = null;
}
if (sideController != null) {
sideController.onLogOut();
sideController = null;
}
if (callback != null) {
if (layout != null && layout.getDesktop() != null
&& Executions.getCurrent() != null && Executions.getCurrent().getNativeRequest() != null) {
Executions.schedule(layout.getDesktop(), e -> callback.onCallback(Boolean.TRUE), new Event("onAsyncLogoutCallback"));
} else {
callback.onCallback(Boolean.TRUE);
}
}
layout = null;
pnlHead = null;
max = null;
m_desktop = null;
}
/**
* Update home tab title after {@link #ON_ACTIVITIES_CHANGED_EVENT}
*/
public void updateUI() {
windowContainer.setTabTitle(0, Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Home")) + " (" + noCount + ")", null);
}
/**
* use _docClick undocumented api. need verification after major zk release update
*/
private final static String autoHideMenuScript = "(function(){try{let w=zk.Widget.$('#{0}');let t=zk.Widget.$('#{1}');" +
"let e=new Object;e.target=t;w._docClick(e);}catch(error){}})()";
/**
* Auto hide west panel or popup
*/
private void autoHideMenu() {
if (mobile) {
if (westPopup.getAttribute(POPUP_OPEN_ATTR) != null) {
westPopup.close();
westPopup.removeAttribute(POPUP_OPEN_ATTR);
}
pnlHead.closeSearchPopup();
} else if (layout.getWest().isCollapsible() && !layout.getWest().isOpen())
{
String id = layout.getWest().getUuid();
Tab tab = windowContainer.getSelectedTab();
if (tab != null) {
String tabId = tab.getUuid();
String script = autoHideMenuScript.replace("{0}", id);
script = script.replace("{1}", tabId);
AuScript aus = new AuScript(layout.getWest(), script);
Clients.response("autoHideWest", aus);
}
}
}
@Override
protected void preOpenNewTab()
{
autoHideMenu();
}
/**
* Implementation for Broadcast message
*/
public void bindEventManager() {
EventManager.getInstance().register(IEventTopics.BROADCAST_MESSAGE, this);
}
/**
* Clean up for Broadcast message
*/
public void unbindEventManager() {
EventManager.getInstance().unregister(this);
}
/**
* Handle OSGi event for Broadcast message
*/
@Override
public void handleEvent(final org.osgi.service.event.Event event) {
String eventName = event.getTopic();
if (eventName.equals(IEventTopics.BROADCAST_MESSAGE)) {
EventListener listner = new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
BroadCastMsg msg = (BroadCastMsg) event.getData();
MBroadcastMessage mbMessage = null;
switch (msg.getEventId()) {
case BroadCastUtil.EVENT_TEST_BROADCAST_MESSAGE:
mbMessage = MBroadcastMessage.get(Env.getCtx(), msg.getIntData());
if (mbMessage == null)
return;
String currSession = Integer.toString(Env.getContextAsInt(Env.getCtx(), "AD_Session_ID"));
if (currSession.equals(msg.getTarget())) {
BroadcastMessageWindow testMessageWindow = new BroadcastMessageWindow(
pnlHead);
testMessageWindow.appendMessage(mbMessage, true);
testMessageWindow = null;
}
break;
case BroadCastUtil.EVENT_BROADCAST_MESSAGE:
mbMessage = MBroadcastMessage.get(Env.getCtx(), msg.getIntData());
if (mbMessage == null)
return;
if (mbMessage.isValidUserforMessage()) {
BroadcastMessageWindow messageWindow = new BroadcastMessageWindow(
pnlHead);
messageWindow.appendMessage(mbMessage, false);
}
break;
case BroadCastUtil.EVENT_SESSION_TIMEOUT:
currSession = Integer.toString(Env.getContextAsInt(
Env.getCtx(), "AD_Session_ID"));
if (currSession.equalsIgnoreCase(msg.getTarget())) {
new TimeoutPanel(pnlHead, msg.getIntData());
}
break;
case BroadCastUtil.EVENT_SESSION_ONNODE_TIMEOUT:
currSession = WebUtil.getServerName();
if (currSession.equalsIgnoreCase(msg.getTarget())) {
new TimeoutPanel(pnlHead, msg.getIntData());
}
break;
}
}
};
Executions.schedule(m_desktop, listner, new Event("OnBroadcast",
null, event.getProperty(IEventManager.EVENT_DATA)));
}
}
@Override
public void cleanup(Desktop desktop) throws Exception {
unbindEventManager();
}
@Override
public void updateHelpContext(String ctxType, int recordId) {
this.updateHelpContext(ctxType, recordId, null);
}
@Override
public void updateHelpContext(String ctxType, int recordId, InfoPanel infoPanel) {
// don't show context for SetupWizard Form, is managed internally using wf and node ctxhelp
if (recordId == SystemIDs.FORM_SETUP_WIZARD && X_AD_CtxHelp.CTXTYPE_Form.equals(ctxType))
return;
Clients.response(new AuScript("zWatch.fire('onFieldTooltip', this);"));
helpController.renderCtxHelp(ctxType, recordId);
GridTab gridTab = null;
Component window = getActiveWindow();
ADWindow adwindow = ADWindow.findADWindow(window);
if (adwindow != null) {
gridTab = adwindow.getADWindowContent().getActiveGridTab();
}
if(X_AD_CtxHelp.CTXTYPE_Info.equals(ctxType))
updateHelpQuickInfo(infoPanel);
else
updateHelpQuickInfo(gridTab);
}
@Override
public void updateHelpTooltip(GridField gridField) {
helpController.renderToolTip(gridField);
}
@Override
public void updateHelpTooltip(String hdr, String desc, String help, String otherContent) {
helpController.renderToolTip(hdr, desc, help, otherContent);
}
@Override
public void updateHelpQuickInfo(InfoPanel infoPanel) {
if (isQuickInfoOpen)
helpController.renderQuickInfo(infoPanel);
}
@Override
public void updateHelpQuickInfo(GridTab gridTab) {
this.gridTab = gridTab;
if (isQuickInfoOpen)
helpController.renderQuickInfo(gridTab);
}
@Override
public ProcessDialog openProcessDialog(int processId, boolean soTrx) {
ProcessDialog pd = super.openProcessDialog(processId, soTrx);
updateHelpContext(X_AD_CtxHelp.CTXTYPE_Process, processId);
return pd;
}
@Override
public ADForm openForm(int formId) {
ADForm form = super.openForm(formId);
updateHelpContext(X_AD_CtxHelp.CTXTYPE_Form, formId);
return form;
}
@Override
public void openInfo(int infoId) {
super.openInfo(infoId);
// updateHelpContext is already called in InfoPanel onPageAttached method - IDEMPIERE-5772
// updateHelpContext(X_AD_CtxHelp.CTXTYPE_Info, infoId);
}
@Override
public void openWorkflow(int workflow_ID) {
super.openWorkflow(workflow_ID);
updateHelpContext(X_AD_CtxHelp.CTXTYPE_Workflow, workflow_ID);
}
@Override
public void openTask(int taskId) {
super.openTask(taskId);
updateHelpContext(X_AD_CtxHelp.CTXTYPE_Task, taskId);
}
@Override
public boolean isPendingWindow() {
List