/******************************************************************************
* 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.adwindow;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import org.adempiere.base.IServiceHolder;
import org.adempiere.webui.ClientInfo;
import org.adempiere.webui.LayoutUtils;
import org.adempiere.webui.action.Actions;
import org.adempiere.webui.action.IAction;
import org.adempiere.webui.apps.AEnv;
import org.adempiere.webui.component.Combobox;
import org.adempiere.webui.component.Tabpanel;
import org.adempiere.webui.component.ToolBar;
import org.adempiere.webui.component.ToolBarButton;
import org.adempiere.webui.desktop.IDesktop;
import org.adempiere.webui.event.ToolbarListener;
import org.adempiere.webui.part.WindowContainer;
import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.theme.ITheme;
import org.adempiere.webui.theme.ThemeManager;
import org.adempiere.webui.util.ZKUpdateUtil;
import org.adempiere.webui.window.Dialog;
import org.compiere.model.GridTab;
import org.compiere.model.MRole;
import org.compiere.model.MSysConfig;
import org.compiere.model.MToolBarButton;
import org.compiere.model.MUserQuery;
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.ValueNamePair;
import org.zkoss.image.AImage;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.AfterSizeEvent;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.KeyEvent;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.A;
import org.zkoss.zul.Cell;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Popup;
import org.zkoss.zul.Row;
import org.zkoss.zul.Rows;
import org.zkoss.zul.Separator;
import org.zkoss.zul.Space;
import org.zkoss.zul.Toolbarbutton;
import org.zkoss.zul.impl.LabelImageElement;
/**
* Toolbar of AD_Window
* @author Ashley G Ramdass
* @date Feb 25, 2007
* @version $Revision: 0.10 $
*
* @author Cristina Ghita, www.arhipac.ro
*
FR [ 2076330 ] Add new methods in CWindowToolbar class
*/
public class ADWindowToolbar extends ToolBar implements EventListener
{
/**
* generated serial id
*/
private static final long serialVersionUID = -2174135931334134570L;
/**
* Attribute for {@link #overflowPopup} to store the last close timestamp in ms.
* Use to prevent too rapid open and close of overflow popup.
*/
private static final String POPUP_CLOSE_TIMESTAMP_ATTR = "popup.close";
/** Prefix for Button Name **/
public static final String BTNPREFIX = "Btn";
@Deprecated(forRemoval = true, since = "11")
public static final String MNITMPREFIX = "Mnitm";
private static final CLogger log = CLogger.getCLogger(ADWindowToolbar.class);
/** translated message for new query label (default for en is "** New Query **") */
private String m_sNew;
/** combobox to select user query **/
private Combobox fQueryName;
private MUserQuery[] userQueries;
private MUserQuery selectedUserQuery;
private ToolBarButton btnIgnore;
private ToolBarButton btnHelp, btnNew, btnCopy, btnDelete, btnSave;
private ToolBarButton btnSaveAndCreate; // Elaine 2009/03/02 - Save & Create
private ToolBarButton btnRefresh, btnFind, btnLock, btnAttachment;
private ToolBarButton btnGridToggle;
private ToolBarButton btnParentRecord, btnDetailRecord;
private ToolBarButton btnReport, btnArchive, btnPrint;
private ToolBarButton btnZoomAcross, btnActiveWorkflows, btnRequests, btnProductInfo;
private ToolBarButton btnChat;
private ToolBarButton btnPostIt;
private ToolBarButton btnLabel;
private ToolBarButton btnCustomize;
private ToolBarButton btnExport;
private ToolBarButton btnFileImport;
private ToolBarButton btnCSVImport;
private ToolBarButton btnProcess;
private ToolBarButton btnQuickForm;
/** button to open overflow popup for toolbar buttons with IsShowMore=Y (for non-mobile client) **/
private ToolBarButton btnShowMore;
/** Button Name:ToolBarButton. Map for all buttons **/
private HashMap buttons = new HashMap();
/**
* For mobile client, the list of toolbar button with IsShowMore=Y is first keep here
* and move to {@link #overflows} in {@link #onOverflowButton(Event) event}
* */
private ArrayList mobileShowMoreButtons = new ArrayList();
/** All register toolbar listener **/
private ArrayList listeners = new ArrayList();
/** current ON_Click event that's being handle **/
private Event event;
/** shortcut key map without ctrl and alt **/
private Map keyMap = new HashMap();
/** alt+key shortcut map **/
private Map altKeyMap = new HashMap();
/** ctrl+key shortcut map **/
private Map ctrlKeyMap = new HashMap();
/** list of custom toolbar button (IsCustomization=Y) **/
private List toolbarCustomButtons = new ArrayList();
/** Restriction list for window, loaded from AD_ToolBarButtonRestrict **/
private List restrictionList;
/** List of toolbar button with IsAdvanced=Y **/
private List advancedList;
// Elaine 2008/12/04
/** Show Personal Lock */
public boolean isPersonalLock = MRole.getDefault().isPersonalLock();
private boolean isAllowProductInfo = MRole.getDefault().canAccess_Info_Product();
private int windowNo = 0;
/**
* Maintain hierarchical Quick form by its parent-child tab while open leaf
* tab once and dispose and doing same action
*/
private int quickFormTabHrchyLevel = 0;
/** show more button for mobile client **/
private A mobileOverflowButton;
/**
* list of toolbar button overflow to show more popup (or with IsShowMore=Y).
* Use for both mobile and desktop client.
* */
private ArrayList overflows;
/** Popup for overflow/IsShowMore=Y toolbar buttons. Use for both mobile and desktop client. **/
private Popup overflowPopup;
/** width of toolbar from previous ON_AFTER_SIZE event **/
private int prevWidth;
/** AD Window content part that own this toolbar **/
private AbstractADWindowContent windowContent;
/**
* SysConfig USE_ESC_FOR_TAB_CLOSING
*/
private boolean isUseEscForTabClosing = MSysConfig.getBooleanValue(MSysConfig.USE_ESC_FOR_TAB_CLOSING, false, Env.getAD_Client_ID(Env.getCtx()));
/**
* default constructor
*/
public ADWindowToolbar()
{
this(null, 0);
}
/**
* @param windowContent
* @param windowNo
*/
public ADWindowToolbar(AbstractADWindowContent windowContent, int windowNo) {
this.windowContent = windowContent;
setWindowNo(windowNo);
init();
if (ClientInfo.isMobile()) {
mobileInit();
}
}
/**
* Init components
*/
private void init()
{
LayoutUtils.addSclass("adwindow-toolbar", this);
//IDEMPIERE-4085
m_sNew = "** ".concat(Msg.getMsg(Env.getCtx(), "New Query")).concat(" **");
fQueryName = new Combobox();
fQueryName.setTooltiptext(Msg.getMsg(Env.getCtx(),"SelectQuery"));
fQueryName.setPlaceholder(Msg.getMsg(Env.getCtx(),"SelectQuery"));
fQueryName.setId(BTNPREFIX + "SearchQuery");
fQueryName.addEventListener(Events.ON_SELECT, this);
LayoutUtils.addSclass("toolbar-searchbox", fQueryName);
btnIgnore = createButton("Ignore", "Ignore", "Ignore");
btnIgnore.setTooltiptext(btnIgnore.getTooltiptext()+ " Alt+Z");
btnHelp = createButton("Help", "Help","Help");
btnHelp.setTooltiptext(btnHelp.getTooltiptext()+ " Alt+H");
btnNew = createButton("New", "New", "New");
btnNew.setTooltiptext(btnNew.getTooltiptext()+ " Alt+N");
btnCopy = createButton("Copy", "Copy", "Copy");
btnCopy.setTooltiptext(btnCopy.getTooltiptext()+ " Alt+C");
btnDelete = createButton("Delete", "Delete", "Delete");
btnDelete.setTooltiptext(btnDelete.getTooltiptext()+ " Alt+D");
btnSave = createButton("Save", "Save", "Save");
btnSave.setTooltiptext(btnSave.getTooltiptext()+ " Alt+S");
btnSaveAndCreate = createButton("SaveCreate", "SaveCreate", "SaveCreate");
btnSaveAndCreate.setTooltiptext(btnSaveAndCreate.getTooltiptext()+ " Alt+A");
btnRefresh = createButton("Refresh", "Refresh", "Refresh");
btnRefresh.setTooltiptext(btnRefresh.getTooltiptext()+ " Alt+E");
btnFind = createButton("Find", "Find", "Find");
btnFind.setTooltiptext(btnFind.getTooltiptext()+ " Alt+F");
btnAttachment = createButton("Attachment", "Attachment", "Attachment");
btnPostIt = createButton("PostIt", "PostIt", "PostIt");
btnChat = createButton("Chat", "Chat", "Chat");
btnLabel = createButton("Label", "Label", "Label");
btnGridToggle = createButton("Toggle", "Multi", "Toggle");
btnGridToggle.setTooltiptext(btnGridToggle.getTooltiptext()+ " Alt+T");
btnParentRecord = createButton("ParentRecord", "Parent", "ParentRecord");
btnParentRecord.setTooltiptext(btnParentRecord.getTooltiptext()+ " Alt+Up");
btnDetailRecord = createButton("DetailRecord", "Detail", "DetailRecord");
btnDetailRecord.setTooltiptext(btnDetailRecord.getTooltiptext()+ " Alt+Down");
if (MRole.getDefault().isCanReport()) {
btnReport = createButton("Report", "Report", "Report");
btnReport.setTooltiptext(btnReport.getTooltiptext()+ " Alt+R");
}
btnArchive = createButton("Archive", "Archive", "Archive");
btnPrint = createButton("Print", "Print", "Print");
btnPrint.setTooltiptext(btnPrint.getTooltiptext()+ " Alt+P");
if (isPersonalLock) {
btnLock = createButton("Lock", "Lock", "Lock"); // Elaine 2008/12/04
btnLock.setDisabled(!isPersonalLock); // Elaine 2008/12/04
btnLock.setVisible(isPersonalLock);
}
btnZoomAcross = createButton("ZoomAcross", "ZoomAcross", "ZoomAcross");
btnActiveWorkflows = createButton("ActiveWorkflows", "WorkFlow", "ActiveWorkflows");
btnRequests = createButton("Requests", "Request", "Requests");
if (isAllowProductInfo) {
btnProductInfo = createButton("ProductInfo", "Product", "ProductInfo");
btnProductInfo.setDisabled(!isAllowProductInfo); // Elaine 2008/07/22
btnProductInfo.setVisible(isAllowProductInfo);
}
btnCustomize= createButton("Customize", "Customize", "Customize");
btnCustomize.setDisabled(false);
btnProcess= createButton("Process", "Process", "Process");
btnProcess.setTooltiptext(btnProcess.getTooltiptext()+ " Alt+O");
btnProcess.setDisabled(false);
btnQuickForm = createButton("QuickForm", "QuickForm", "QuickForm");
btnQuickForm.setDisabled(false);
// Help and Exit should always be enabled
btnHelp.setDisabled(false);
btnGridToggle.setDisabled(false);
btnZoomAcross.setDisabled(false);
btnActiveWorkflows.setDisabled(false); // Elaine 2008/07/17
btnRequests.setDisabled(false); // Elaine 2008/07/22
btnArchive.setDisabled(false); // Elaine 2008/07/28
if (MRole.getDefault().isCanExport())
{
btnExport = createButton("Export", "Export", "Export");
}
btnFileImport = createButton("FileImport", "FileImport", "FileImport");
btnCSVImport = createButton("CSVImport", "CSVImport", "CSVImport");
btnShowMore = createButton("ShowMore", "ShowMore", "ShowMore");
btnShowMore.setDisabled(true);
btnShowMore.setVisible(false);
if (!ClientInfo.isMobile())
overflows = new ArrayList();
//Window toolbar buttons from AD_ToolBarButton
MToolBarButton[] officialButtons = MToolBarButton.getToolbarButtons("W", null);
for (MToolBarButton button : officialButtons) {
if (!button.isActive() || !hasAccess(BTNPREFIX+button.getComponentName())) {
buttons.remove(button.getComponentName());
} else {
if (button.isCustomization()) {
String actionId = button.getActionClassName();
IServiceHolder serviceHolder = Actions.getAction(actionId);
IAction action = serviceHolder.getService();
if (serviceHolder != null && action != null) {
String labelKey = actionId + ".label";
String tooltipKey = actionId + ".tooltip";
String label = Msg.getMsg(Env.getCtx(), labelKey, true);
String tooltiptext = Msg.getMsg(Env.getCtx(), labelKey, false);
if (Util.isEmpty(tooltiptext, true))
tooltiptext = Msg.getMsg(Env.getCtx(), tooltipKey, true);
else
tooltipKey = labelKey;
if (labelKey.equals(label)) {
label = button.getName();
}
if (tooltipKey.equals(tooltiptext) || labelKey.equals(tooltiptext)) {
tooltipKey = null;
}
ToolBarButton btn = createButton(button.getComponentName(), null, tooltipKey);
btn.removeEventListener(Events.ON_CLICK, this);
btn.setId(button.getName());
btn.setDisabled(false);
btn.setIconSclass(null);
if (ThemeManager.isUseFontIconForImage()) {
String iconSclass = Actions.getActionIconSclass(actionId);
if (!Util.isEmpty(iconSclass, true)) {
btn.setIconSclass(iconSclass);
LayoutUtils.addSclass("font-icon-toolbar-button", btn);
}
}
//not using font icon, fallback to image or label
if (Util.isEmpty(btn.getIconSclass(), true)) {
AImage aImage = Actions.getActionImage(actionId);
if (aImage != null) {
btn.setImageContent(aImage);
} else {
btn.setLabel(label);
}
}
ToolbarCustomButton toolbarCustomBtn = new ToolbarCustomButton(button, btn, actionId, windowNo);
toolbarCustomButtons.add(toolbarCustomBtn);
if (ClientInfo.isMobile() && button.isShowMore())
mobileShowMoreButtons.add(btn);
else if (!button.isShowMore()) {
this.appendChild(btn);
action.decorate(btn);
}
}
}
if (buttons.get(button.getComponentName()) != null) {
if (ClientInfo.isMobile() && button.isShowMore())
mobileShowMoreButtons.add(buttons.get(button.getComponentName()));
else if (button.isShowMore())
overflows.add(buttons.get(button.getComponentName()));
else {
this.appendChild(buttons.get(button.getComponentName()));
if (button.isAddSeparator()) {
this.appendChild(new Separator("vertical"));
}
}
} else if (button.isSearchQueryComponent())
this.appendChild(fQueryName);
}
}
if (!ClientInfo.isMobile() && overflows.size() > 0) {
enableShowMore();
}
configureKeyMap();
ZKUpdateUtil.setWidth(this, "100%");
}
/**
* Create new toolbar button
* @param name button name (BTNPREFIX+name)
* @param image image name (images/image+suffix) or iconSclass name (z-icon-image)
* @param tooltip
* @return {@link ToolBarButton}
*/
private ToolBarButton createButton(String name, String image, String tooltip)
{
ToolBarButton btn = new ToolBarButton("");
btn.setName(BTNPREFIX+name);
btn.setId(btn.getName());
if (image != null)
{
if (ThemeManager.isUseFontIconForImage())
{
String iconSclass = "z-icon-" + image;
btn.setIconSclass(iconSclass);
LayoutUtils.addSclass("font-icon-toolbar-button", btn);
}
else
{
Executions.createComponents(ThemeManager.getPreference(), this, null);
String size = Env.getContext(Env.getCtx(), ITheme.ZK_TOOLBAR_BUTTON_SIZE);
String suffix = "24.png";
if (!Util.isEmpty(size))
{
suffix = size + ".png";
}
btn.setImage(ThemeManager.getThemeResource("images/"+image + suffix));
}
}
String tooltipText = Msg.getMsg(Env.getCtx(),tooltip,false);
if (Util.isEmpty(tooltipText, true))
tooltipText = Msg.getMsg(Env.getCtx(),tooltip,true);
btn.setTooltiptext(tooltipText);
LayoutUtils.addSclass("toolbar-button", btn);
buttons.put(name, btn);
//make toolbar button last to receive focus
btn.setTabindex(0);
btn.addEventListener(Events.ON_CLICK, this);
btn.setDisabled(true);
return btn;
}
/**
* Get ToolBarButton by name
* @param name
* @return {@link ToolBarButton} or null
*/
public ToolBarButton getButton(String name)
{
return buttons.get(name);
}
/**
* Get ToolBarButton by name
* @param name
* @return {@link LabelImageElement} or null
*/
public LabelImageElement getToolbarItem(String name)
{
return buttons.get(name);
}
/** VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */
public static final int VK_A = 0x41;
public static final int VK_B = 0x42;
public static final int VK_C = 0x43;
public static final int VK_D = 0x44;
public static final int VK_E = 0x45;
public static final int VK_F = 0x46;
public static final int VK_G = 0x47;
public static final int VK_H = 0x48;
public static final int VK_I = 0x49;
public static final int VK_J = 0x4A;
public static final int VK_K = 0x4B;
public static final int VK_L = 0x4C;
public static final int VK_M = 0x4D;
public static final int VK_N = 0x4E;
public static final int VK_O = 0x4F;
public static final int VK_P = 0x50;
public static final int VK_Q = 0x51;
public static final int VK_R = 0x52;
public static final int VK_S = 0x53;
public static final int VK_T = 0x54;
public static final int VK_U = 0x55;
public static final int VK_V = 0x56;
public static final int VK_W = 0x57;
public static final int VK_X = 0x58;
public static final int VK_Y = 0x59;
public static final int VK_Z = 0x5A;
/**
* Configure shortcut key for each button
*/
private void configureKeyMap()
{
altKeyMap.put(VK_H, btnHelp);
altKeyMap.put(VK_N, btnNew);
altKeyMap.put(VK_D, btnDelete);
altKeyMap.put(VK_S, btnSave);
altKeyMap.put(VK_A, btnSaveAndCreate);
altKeyMap.put(VK_C, btnCopy);
altKeyMap.put(VK_E, btnRefresh);
altKeyMap.put(VK_T, btnGridToggle);
altKeyMap.put(KeyEvent.UP, btnParentRecord);
altKeyMap.put(KeyEvent.DOWN, btnDetailRecord);
altKeyMap.put(VK_F, btnFind);
altKeyMap.put(VK_Z, btnIgnore);
if (btnReport != null)
altKeyMap.put(VK_R, btnReport);
altKeyMap.put(VK_P, btnPrint);
altKeyMap.put(VK_O, btnProcess);
altKeyMap.put(VK_L, btnCustomize);
}
/**
* Add separator/spacer between button
*/
protected void addSeparator()
{
Space s = new Space();
s.setSpacing("6px");
s.setOrient("vertical");
this.appendChild(s);
}
/**
* Add ToolbarListener
* @param toolbarListener
*/
public void addListener(ToolbarListener toolbarListener)
{
listeners.add(toolbarListener);
}
/**
* Remove ToolbarListener
* @param toolbarListener
*/
public void removeListener(ToolbarListener toolbarListener)
{
listeners.remove(toolbarListener);
}
@Override
public void onEvent(Event event)
{
String eventName = event.getName();
if(eventName.equals(Events.ON_CLICK))
{
if(event.getTarget() instanceof ToolBarButton)
{
if (!event.getTarget().isVisible())
return;
if (!event.getTarget().getId().contentEquals(BTNPREFIX+"ShowMore"))
doOnClick(event);
else
onShowMore();
}
} else if (eventName.equals(Events.ON_CTRL_KEY))
{
KeyEvent keyEvent = (KeyEvent) event;
// If Quick form is opened then prevent toolbar shortcut key events.
if (!(keyEvent.getKeyCode() == KeyEvent.F2) && windowContent != null && windowContent.getOpenQuickFormTabs().size() > 0)
return;
if (LayoutUtils.isReallyVisible(this))
this.onCtrlKeyEvent(keyEvent);
} else if (Events.ON_SELECT.equals(eventName))
{
int index = fQueryName.getSelectedIndex();
if (index < 0) return;
if (index == 0) // no query - refresh
setSelectedUserQuery(null);
else if (m_sNew.equals(fQueryName.getValue())) { //On new send the Event to open the FindWindow
Events.sendEvent(Events.ON_CLICK, btnFind, null);
return;
}
else
setSelectedUserQuery(userQueries[index-1]);
doOnClick(event);
}
else if(IDesktop.ON_CLOSE_WINDOW_SHORTCUT_EVENT.equals(eventName)) {
IDesktop desktop = SessionManager.getAppDesktop();
if (windowNo > 0 && desktop.isCloseTabWithShortcut())
desktop.closeWindow(windowNo);
else
desktop.setCloseTabWithShortcut(true);
}
}
/**
* Handle ON_Click event for button.
* Call register {@link ToolbarListener}.
* @param event
*/
private void doOnClick(Event event) {
this.event = event;
String compName;
String methodName;
if (event.getTarget() == fQueryName) {
methodName = "onSearchQuery";
} else {
ToolBarButton cComponent = (ToolBarButton) event.getTarget();
compName = cComponent.getName();
methodName = "on" + compName.substring(3);
}
Iterator listenerIter = listeners.iterator();
while(listenerIter.hasNext())
{
try
{
ToolbarListener tListener = listenerIter.next();
Method method = tListener.getClass().getMethod(methodName, (Class[]) null);
method.invoke(tListener, (Object[]) null);
}
catch (Exception e)
{
String msg = null;
ValueNamePair vp = CLogger.retrieveError();
if (vp != null) {
msg = vp.getName();
}
if (msg == null) {
Throwable cause = e.getCause();
if (cause != null) {
msg = cause.getLocalizedMessage();
}
}
if (msg == null) {
msg = "Could not invoke Toolbar listener method: " + methodName + "()";
}
Dialog.error(windowNo, "Error", msg);
log.log(Level.SEVERE, msg, e);
}
}
this.event = null;
}
/**
* Enable/disable buttons for navigation between parent and detail tab
* @param enabled
*/
public void enableTabNavigation(boolean enabled)
{
enableTabNavigation(enabled, enabled);
}
/**
* Enable/disable buttons for navigation between parent and detail tab
* @param enableParent
* @param enableDetail
*/
public void enableTabNavigation(boolean enableParent, boolean enableDetail)
{
this.btnParentRecord.setDisabled(!enableParent);
this.btnDetailRecord.setDisabled(!enableDetail);
}
/**
* Enable/disable Refresh button
* @param enabled
*/
public void enableRefresh(boolean enabled)
{
this.btnRefresh.setDisabled(!enabled);
}
/**
* Enable/disable Save button
* @param enabled
*/
public void enableSave(boolean enabled)
{
this.btnSave.setDisabled(!enabled);
this.btnSaveAndCreate.setDisabled(!(isNewEnabled() || isSaveEnable()));
}
/**
* @return true if Save button is enable
*/
public boolean isSaveEnable() {
return !btnSave.isDisabled();
}
/**
* Enable/disable Delete button
* @param enabled
*/
public void enableDelete(boolean enabled)
{
this.btnDelete.setDisabled(!enabled);
}
/**
* @return true if Delete button is enable
*/
public boolean isDeleteEnable()
{
return !btnDelete.isDisabled();
}
/**
* @return true if New button is enable
*/
public boolean isNewEnabled() {
return !btnNew.isDisabled();
}
/**
* Enable/disable Ignore/Undo button
* @param enabled
*/
public void enableIgnore(boolean enabled)
{
this.btnIgnore.setDisabled(!enabled);
}
/**
* Enable/disable New button
* @param enabled
*/
public void enableNew(boolean enabled)
{
this.btnNew.setDisabled(!enabled);
this.btnSaveAndCreate.setDisabled(!(isNewEnabled() || isSaveEnable()));
}
/**
* Enable/disable Copy/Duplicate button
* @param enabled
*/
public void enableCopy(boolean enabled)
{
this.btnCopy.setDisabled(!enabled);
}
/**
* Enable/disable Attachment button
* @param enabled
*/
public void enableAttachment(boolean enabled)
{
this.btnAttachment.setDisabled(!enabled);
}
/**
* Enable/disable Chat button
* @param enabled
*/
public void enableChat(boolean enabled)
{
this.btnChat.setDisabled(!enabled);
}
/**
* Enable/disable Print button
* @param enabled
*/
public void enablePrint(boolean enabled)
{
this.btnPrint.setDisabled(!enabled);
}
/**
* Enable/disable Report button
* @param enabled
*/
public void enableReport(boolean enabled)
{
if (btnReport != null)
this.btnReport.setDisabled(!enabled);
}
/**
* Enable/disable Find/Query button
* @param enabled
*/
public void enableFind(boolean enabled)
{
this.btnFind.setDisabled(!enabled);
}
/**
* Enable/disable Toggle button
* @param enabled
*/
public void enableGridToggle(boolean enabled)
{
btnGridToggle.setDisabled(!enabled);
}
/**
* Enable/disable Customize Grid button
* @param enabled
*/
public void enableCustomize(boolean enabled)
{
btnCustomize.setDisabled(!enabled);
}
/**
* Enable/disable Archive button
* @param enabled
*/
public void enableArchive(boolean enabled)
{
btnArchive.setDisabled(!enabled);
}
/**
* Enable/disable Zoom Across button
* @param enabled
*/
public void enableZoomAcross(boolean enabled)
{
btnZoomAcross.setDisabled(!enabled);
}
/**
* Enable/disable Active Workflows button
* @param enabled
*/
public void enableActiveWorkflows(boolean enabled)
{
btnActiveWorkflows.setDisabled(!enabled);
}
/**
* Enable/disable Requests button
* @param enabled
*/
public void enableRequests(boolean enabled)
{
btnRequests.setDisabled(!enabled);
}
/**
* Enable/disable Quick Form button
* @param enabled
*/
public void enableQuickForm(boolean enabled)
{
btnQuickForm.setDisabled(!enabled);
}
/**
* Turn on/off Lock button (Pressed=On, Not Pressed=Off)
* @param locked
*/
public void lock(boolean locked)
{
setPressed("Lock", locked);
if (ThemeManager.isUseFontIconForImage())
{
String iconSclass = "z-icon-" + (this.btnLock.isPressed() ? "lock" : "unlock") ;
this.btnLock.setIconSclass(iconSclass);
LayoutUtils.addSclass("font-icon-toolbar-button", this.btnLock);
}
else
{
String size = Env.getContext(Env.getCtx(), ITheme.ZK_TOOLBAR_BUTTON_SIZE);
String suffix = "24.png";
if (!Util.isEmpty(size))
{
suffix = size + ".png";
}
String imgURL = "images/"+ (this.btnLock.isPressed() ? "LockX" : "Lock") + suffix;
imgURL = ThemeManager.getThemeResource(imgURL);
this.btnLock.setImage(imgURL);
}
}
/**
* Enable/disable Post It Note button
* @param enabled
*/
public void enablePostIt(boolean enabled)
{
this.btnPostIt.setDisabled(!enabled);
}
/**
* Enable/disable Label record button
* @param enabled
*/
public void enableLabel(boolean enabled)
{
this.btnLabel.setDisabled(!enabled);
}
/**
* @return ON_Click event that's being handle
*/
public Event getEvent()
{
return event;
}
/**
* Handle shortcut key event
* @param keyEvent
*/
private void onCtrlKeyEvent(KeyEvent keyEvent) {
if (windowContent != null && windowContent.isBlock())
return;
ToolBarButton btn = null;
if (keyEvent.isAltKey() && !keyEvent.isCtrlKey() && !keyEvent.isShiftKey())
{
if ((keyEvent.getKeyCode() == VK_X))
{
onCloseWithShortcut(keyEvent);
}
else
{
btn = altKeyMap.get(keyEvent.getKeyCode());
}
}
else if (keyEvent.getKeyCode() == 0x1B && isUseEscForTabClosing) { // ESC
onCloseWithShortcut(keyEvent);
}
else if (!keyEvent.isAltKey() && keyEvent.isCtrlKey() && !keyEvent.isShiftKey())
{
if (keyEvent.getKeyCode() == KeyEvent.F2)
{
quickFormTabHrchyLevel = quickFormTabHrchyLevel + 1;
fireButtonClickEvent(keyEvent, btnDetailRecord);
if (!btnQuickForm.isDisabled() && btnQuickForm.isVisible())
{
fireButtonClickEvent(keyEvent, btnQuickForm);
}
else if (!btnParentRecord.isDisabled() && btnParentRecord.isVisible())
{
fireButtonClickEvent(keyEvent, btnParentRecord);
quickFormTabHrchyLevel = quickFormTabHrchyLevel - 1;
}
return;
}
else
{
btn = ctrlKeyMap.get(keyEvent.getKeyCode());
}
}
else if (!keyEvent.isAltKey() && !keyEvent.isCtrlKey() && !keyEvent.isShiftKey())
btn = keyMap.get(keyEvent.getKeyCode());
else if (!keyEvent.isAltKey() && !keyEvent.isCtrlKey() && keyEvent.isShiftKey())
{
if (keyEvent.getKeyCode() == KeyEvent.F2)
{
btn = btnQuickForm;
}
}
fireButtonClickEvent(keyEvent, btn);
}
/**
* Close Window
* @param keyEvent
*/
private void onCloseWithShortcut(KeyEvent keyEvent) {
keyEvent.stopPropagation();
Events.echoEvent(new Event(IDesktop.ON_CLOSE_WINDOW_SHORTCUT_EVENT, this));
}
/**
* Fire ON_Click event for button, trigger by shortcut key event.
* @param keyEvent source shortcut key event
* @param btn
*/
private void fireButtonClickEvent(KeyEvent keyEvent, ToolBarButton btn)
{
if (btn != null) {
keyEvent.stopPropagation();
if (!btn.isDisabled() && btn.isVisible()) {
Events.sendEvent(btn, new Event(Events.ON_CLICK, btn));
}
}
}
/**
* Make all toolbar buttons visible
* @param visible
*/
public void setVisibleAll(boolean visible)
{
for (ToolBarButton btn : buttons.values())
{
btn.setVisible(visible);
}
}
/**
* @param buttonName
* @param visible
*/
public void setVisible(String buttonName, boolean visible)
{
ToolBarButton btn = buttons.get(buttonName);
if (btn != null)
{
btn.setVisible(visible);
}
}
/**
* @param windowNo
*/
public void setWindowNo(int windowNo) {
this.windowNo = windowNo;
}
/**
* Enable/disable Export button
* @param b
*/
public void enableExport(boolean b) {
if (btnExport != null)
btnExport.setDisabled(!b);
}
/**
* Enable/disable File Import button
* @param b
*/
public void enableFileImport(boolean b) {
if (btnFileImport != null)
btnFileImport.setDisabled(!b);
}
/**
* Enable/disable CSV Import button
* @param b
*/
public void enableCSVImport(boolean b) {
if (btnCSVImport != null)
btnCSVImport.setDisabled(!b);
}
private boolean ToolBarMenuRestictionLoaded = false;
/**
* @param buttonName
* @return true if current login user has access to buttonName
*/
private boolean hasAccess(String buttonName) {
ADWindow adwindow = ADWindow.get(windowNo);
if (restrictionList == null)
restrictionList = adwindow.getWindowToolbarRestrictList();
if (restrictionList.contains(buttonName))
return false;
if (!MRole.getDefault().isAccessAdvanced()) {
if (advancedList == null)
advancedList = adwindow.getWindowAdvancedButtonList();
if (advancedList.contains(buttonName))
return false;
}// All advanced btn
return true;
}
/**
* Initialise the accessibility state of toolbar buttons
*/
public void updateToolbarAccess() {
if (ToolBarMenuRestictionLoaded)
return;
ADWindow adwindow = ADWindow.findADWindow(this);
dynamicDisplay();
// If no workflow set for the table => disable btnWorkflow
if (!btnActiveWorkflows.isDisabled()) {
GridTab gridTab = adwindow.getADWindowContent().getActiveGridTab();
if (gridTab != null) {
btnActiveWorkflows.setDisabled(!hasWorkflow(gridTab));
}
}
ToolBarMenuRestictionLoaded = true;
}
/**
* btnActiveWorkflow should be disabled when table has no workflow defined
* @param gridTab
* @return true if has workflow define for gridTab
*/
protected boolean hasWorkflow(GridTab gridTab)
{
String sql = "SELECT COUNT(*) FROM AD_Workflow WHERE IsActive='Y' AND AD_Table_ID=? AND AD_Client_ID IN (0,?)";
return (DB.getSQLValueEx(null, sql, gridTab.getAD_Table_ID(), Env.getAD_Client_ID(Env.getCtx())) > 0);
}
/**
* Enable/disable Process button
* @param b boolean
*/
public void enableProcessButton(boolean b) {
if (btnProcess != null) {
btnProcess.setDisabled(!b);
}
}
/**
* Dynamic update of each toolbar button state (Check restrictions).
* For custom button, call {@link ToolbarCustomButton#dynamicDisplay()}, process pressedLogic and readOnlyLogic.
*/
public void dynamicDisplay() {
List customButtons = new ArrayList();
for(ToolbarCustomButton toolbarCustomBtn : toolbarCustomButtons) {
if (overflows != null)
toolbarCustomBtn.dynamicDisplay(overflows.contains(toolbarCustomBtn.getToolbarbutton()));
customButtons.add(toolbarCustomBtn.getToolbarbutton());
}
ADWindow adwindow = ADWindow.findADWindow(this);
GridTab gridTab = adwindow.getADWindowContent().getActiveGridTab();
if (gridTab != null) {
int AD_Tab_ID = gridTab.getAD_Tab_ID();
List restrictionList = adwindow.getTabToolbarRestrictList(AD_Tab_ID);
for (Component p = this.getFirstChild(); p != null; p = p.getNextSibling()) {
if (p instanceof ToolBarButton) {
if (!customButtons.contains(p) && !p.isVisible())
p.setVisible(true);
} else if (p instanceof Combobox && !p.isVisible()) {
p.setVisible(true);
}
}
for (String restrictName : restrictionList)
{
for (Component p = this.getFirstChild(); p != null; p = p.getNextSibling()) {
if (p instanceof ToolBarButton) {
if ( restrictName.equals(((ToolBarButton)p).getName()) ) {
p.setVisible(false);
break;
}
} else if (p instanceof Combobox) {
if (restrictName.equals(((Combobox) p).getId())) {
p.setVisible(false);
break;
}
}
}
}
if (overflows != null) {
//Set visible all overflow buttons with the same condition as above
overflows.stream()
.filter(button -> !customButtons.contains(button) && !button.isVisible())
.forEach(button -> button.setVisible(true));
for (String restrictName : restrictionList) {
for (ToolBarButton p : overflows) {
if (restrictName.equals(p.getName())) {
p.setVisible(false);
break;
}
}
}
}
}
pressedLogic();
readOnlyLogic();
}
/**
* Call {@link ToolbarCustomButton#pressedLogic()}
*/
private void pressedLogic()
{
for (ToolbarCustomButton toolbarCustomBtn : toolbarCustomButtons)
{
toolbarCustomBtn.pressedLogic();
}
}
/**
* Call {@link ToolbarCustomButton#readOnlyLogic()}
*/
private void readOnlyLogic()
{
for (ToolbarCustomButton toolbarCustomBtn : toolbarCustomButtons)
{
toolbarCustomBtn.readOnlyLogic();
}
}
@Override
public void onPageDetached(Page page) {
super.onPageDetached(page);
try {
SessionManager.getSessionApplication().getKeylistener().removeEventListener(Events.ON_CTRL_KEY, this);
removeEventListener(IDesktop.ON_CLOSE_WINDOW_SHORTCUT_EVENT, this);
} catch (Exception e) {}
}
@Override
public void onPageAttached(Page newpage, Page oldpage) {
super.onPageAttached(newpage, oldpage);
if (newpage != null) {
SessionManager.getSessionApplication().getKeylistener().addEventListener(Events.ON_CTRL_KEY, this);
addEventListener(IDesktop.ON_CLOSE_WINDOW_SHORTCUT_EVENT, this);
}
}
/**
* Init for mobile client only.
*/
private void mobileInit() {
LayoutUtils.addSclass("mobile", this);
addEventListener("onOverflowButton", evt -> onOverflowButton(evt));
this.setWidgetOverride("toolbarScrollable", "function (wgt) {\n" +
" let total = jq(wgt.$n()).width();\n" +
" let w = wgt.firstChild;\n" +
" let a = " + !mobileShowMoreButtons.isEmpty() + ";\n" +
"\n" +
" // make sure all images are loaded.\n" +
" if (zUtl.isImageLoading()) {\n" +
" let f = arguments.callee;\n" +
" setTimeout(function () {\n" +
" return f(wgt);\n" +
" }, 20);\n" +
" return;\n" +
" }\n" +
" for (; w; w = w.nextSibling) {\n" +
" let ow = jq(w.$n()).outerWidth(true);\n" +
" if (typeof ow != 'undefined') {total -= ow;}\n" +
" if (total < 0 && w.className == 'zul.wgt.Toolbarbutton') {\n" +
" break;\n" +
" }\n" +
" }\n" +
" if (w && total < 0) {\n" +
" let event = new zk.Event(wgt, 'onOverflowButton', w.uuid, {toServer: true}); \n" +
" zAu.send(event); \n" +
" }\n" +
" else if (a) {\n" +
" let event = new zk.Event(wgt, 'onOverflowButton', null, {toServer: true}); \n" +
" zAu.send(event); \n" +
" }\n" +
"}");
addEventListener(Events.ON_AFTER_SIZE, (AfterSizeEvent evt) -> onAfterSize(evt));
addCallback(AFTER_PAGE_ATTACHED, t -> afterPageAttached());
}
/**
* Mobile specific handling for AFTER_PAGE_ATTACHED callback.
*/
private void afterPageAttached() {
Component p = getParent();
while (p != null) {
if (p instanceof Tabpanel) {
p.addEventListener(WindowContainer.ON_MOBILE_SET_SELECTED_TAB, evt -> this.invalidate());
break;
}
p = p.getParent();
}
}
/**
* Mobile specific event handling for ON_AFTER_SIZE event.
* @param evt
*/
private void onAfterSize(AfterSizeEvent evt) {
int width = evt.getWidth();
if (width != prevWidth) {
prevWidth = width;
if (mobileOverflowButton != null)
mobileOverflowButton.detach();
if (overflowPopup != null)
overflowPopup.detach();
if (overflows != null) {
for (ToolBarButton btn : overflows) {
appendChild(btn);
}
overflows = null;
}
Events.postEvent("onPostAfterSize", this, null);
}
}
/**
* Handle onOverflowButton event from mobile client.
* @param evt
*/
private void onOverflowButton(Event evt) {
overflows = new ArrayList<>();
String uuid = (String) evt.getData();
if (uuid != null) {
boolean overflowStarted = false;
for(Component comp : getChildren()) {
if (comp instanceof ToolBarButton) {
if (overflowStarted) {
overflows.add((ToolBarButton) comp);
} else if (comp.getUuid().equals(uuid)) {
overflows.add((ToolBarButton) comp);
overflowStarted = true;
}
}
}
}
//Add at the end of the overflow those buttons marked as isShowMore
for (ToolBarButton toolbarButton : mobileShowMoreButtons)
overflows.add(toolbarButton);
if (overflows.size() > 0) {
createOverflowButtonForMobile();
populateOverflowPopup();
}
}
/**
* Populate overflow popup.
* Use for both desktop and mobile client.
*/
private void populateOverflowPopup() {
boolean vertical = !ClientInfo.isMobile() && MSysConfig.getBooleanValue(MSysConfig.ZK_TOOLBAR_SHOW_MORE_VERTICAL, true, Env.getAD_Client_ID(Env.getCtx()));
if (vertical) {
Grid grid = new Grid();
grid.setHflex("min");
grid.setStyle("border:none;");
Rows rows = new Rows();
rows.setParent(grid);
overflowPopup.appendChild(grid);
LayoutUtils.addSclass("toolbar-overflow-popup-vertical", overflowPopup);
for(ToolBarButton btn : overflows) {
Row row = new Row();
row.setParent(rows);
Cell cell1 = new Cell();
cell1.setParent(row);
cell1.appendChild(btn);
cell1.setStyle("border:none;");
String msgValue = btn.getName().substring(BTNPREFIX.length());
String msg = Msg.getMsg(Env.getCtx(), msgValue);
btn.setLabel(msg);
btn.setHflex("1");
}
} else {
for(ToolBarButton btn : overflows) {
overflowPopup.appendChild(btn);
}
}
if (!vertical) {
int cnt = 0;
for(Component c : getChildren()) {
if (c instanceof ToolBarButton)
cnt++;
}
if (overflows.size() >= cnt) {
String script = "(function(){let e = jq('#" + getUuid() + "');";
script = script + "let b=zk.Widget.$('#" + overflowPopup.getUuid() + "'); ";
script = script + "b.setWidth(e.css('width'));";
script = script + "})()";
Clients.evalJavaScript(script);
} else {
overflowPopup.setWidth(null);
}
}
}
/**
* Enable show more feature for desktop client.
* Overflow for mobile client is initialise differently in {@link #mobileInit()}.
*/
private void enableShowMore() {
this.appendChild(btnShowMore);
btnShowMore.setDisabled(false);
btnShowMore.setVisible(true);
newOverflowPopup();
appendChild(overflowPopup);
populateOverflowPopup();
}
/**
* Show overflow popup after {@link #btnShowMore}.
* For desktop client only.
*/
private void onShowMore() {
Long ts = (Long) overflowPopup.removeAttribute(POPUP_CLOSE_TIMESTAMP_ATTR);
if (ts != null) {
if (System.currentTimeMillis() - ts.longValue() < 500) {
return;
}
}
overflowPopup.open(btnShowMore, "after_end");
}
/**
* Create show more button for mobile client
*/
private void createOverflowButtonForMobile() {
mobileOverflowButton = new A();
mobileOverflowButton.setTooltiptext(Msg.getMsg(Env.getCtx(), "ShowMore"));
mobileOverflowButton.setIconSclass("z-icon-ShowMore");
mobileOverflowButton.setSclass("font-icon-toolbar-button toolbar-button mobile-overflow-link");
appendChild(mobileOverflowButton);
newOverflowPopup();
appendChild(overflowPopup);
mobileOverflowButton.addEventListener(Events.ON_CLICK, e -> {
Long ts = (Long) overflowPopup.removeAttribute(POPUP_CLOSE_TIMESTAMP_ATTR);
if (ts != null) {
if (System.currentTimeMillis() - ts.longValue() < 500) {
return;
}
}
overflowPopup.open(mobileOverflowButton, "after_end");
});
}
/**
* Create overflow popup.
* For both desktop and mobile client.
*/
private void newOverflowPopup() {
overflowPopup = new Popup();
overflowPopup.addEventListener(Events.ON_OPEN, (OpenEvent oe) -> {
if (!oe.isOpen()) {
overflowPopup.setAttribute(POPUP_CLOSE_TIMESTAMP_ATTR, System.currentTimeMillis());
Component[] childrens = overflowPopup.getChildren().toArray(new Component[0]);
for (Component child : childrens) {
if (child instanceof Grid || child instanceof Toolbarbutton)
continue;
child.detach();
}
}
});
}
/**
* Post after size event handler for mobile client.
* Calculate which toolbar buttons should overflow to show more popup.
*/
public void onPostAfterSize() {
if (this.getPage() != null) {
String script = "(function(){let w = zk.Widget.$('#" + getUuid() + "'); w.toolbarScrollable(w);";
script = script + "})()";
Clients.evalJavaScript(script);
}
}
/**
* Set button to pressed/not pressed state
* @param buttonName
* @param pressed
*/
public void setPressed(String buttonName, boolean pressed) {
if (getButton(buttonName) != null)
getButton(buttonName).setPressed(pressed);
}
/**
* @return parent tab level for quick form
*/
public int getQuickFormTabHrchyLevel()
{
return quickFormTabHrchyLevel;
}
/**
* @param quickFormHrchyTabLevel
*/
public void setQuickFormTabHrchyLevel(int quickFormHrchyTabLevel)
{
this.quickFormTabHrchyLevel = quickFormHrchyTabLevel;
}
/**
* Reload user queries and set selected item to AD_UserQuery_ID
* @param AD_Tab_ID
* @param AD_UserQuery_ID
*/
public void refreshUserQuery(int AD_Tab_ID, int AD_UserQuery_ID) {
if (AEnv.getOrSetExecutionAttribute(getClass().getName()+".refreshUserQuery")) {
return;
}
fQueryName.getItems().clear();
userQueries = MUserQuery.get(Env.getCtx(), AD_Tab_ID);
fQueryName.appendItem("");
for (int i = 0; i < userQueries.length; i++) {
Comboitem li = fQueryName.appendItem(userQueries[i].getName());
li.setValue(userQueries[i].getAD_UserQuery_ID());
if (AD_UserQuery_ID == userQueries[i].getAD_UserQuery_ID()) {
fQueryName.setSelectedItem(li);
if (AD_UserQuery_ID != getAD_UserQuery_ID())
setSelectedUserQuery(AD_UserQuery_ID);
}
}
fQueryName.appendItem(m_sNew, 0);
if (AD_UserQuery_ID <= 0 || fQueryName.getItemCount() <= 1
|| fQueryName.getSelectedItem() == null)
fQueryName.setSelectedIndex(0);
}
/**
* Set selected user query
* @param AD_UserQuery_ID
*/
public void setSelectedUserQuery(int AD_UserQuery_ID) {
for (MUserQuery userQuery : userQueries) {
if (AD_UserQuery_ID == userQuery.getAD_UserQuery_ID()) {
selectedUserQuery = userQuery;
break;
}
}
}
/**
* Set selected user query
* @param selectedUserQuery
*/
public void setSelectedUserQuery(MUserQuery selectedUserQuery) {
this.selectedUserQuery = selectedUserQuery;
if (selectedUserQuery != null)
fQueryName.setValue(selectedUserQuery.getName());
}
/**
* @return AD_UserQuery_ID of selected user query
*/
public int getAD_UserQuery_ID() {
if (selectedUserQuery == null)
return 0;
return selectedUserQuery.getAD_UserQuery_ID();
}
/**
* Set selected user query to first default user query (if any)
* @return true if there's a default user query
*/
public boolean initDefaultQuery() {
if(userQueries != null) {
for (int i = 0; i < userQueries.length; i++) {
if(userQueries[i].isDefault()) {
fQueryName.setSelectedIndex(i);
setSelectedUserQuery(userQueries[i]);
return true;
}
}
}
return false;
}
}