/******************************************************************************
* Copyright (C) 2008 Low Heng Sin 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. *
*****************************************************************************/
package org.adempiere.webui.part;
import java.util.List;
import org.adempiere.webui.ClientInfo;
import org.adempiere.webui.adwindow.AbstractADWindowContent;
import org.adempiere.webui.apps.ProcessDialog;
import org.adempiere.webui.component.Menupopup;
import org.adempiere.webui.component.Tab;
import org.adempiere.webui.component.Tab.DecorateInfo;
import org.adempiere.webui.component.Tabbox;
import org.adempiere.webui.component.Tabpanel;
import org.adempiere.webui.component.Tabpanels;
import org.adempiere.webui.component.Tabs;
import org.adempiere.webui.component.ToolBar;
import org.adempiere.webui.component.ToolBarButton;
import org.adempiere.webui.component.Window;
import org.adempiere.webui.desktop.TabbedDesktop;
import org.adempiere.webui.panel.IHelpContext;
import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.theme.ThemeManager;
import org.adempiere.webui.util.ZKUpdateUtil;
import org.adempiere.webui.window.ZkReportViewer;
import org.compiere.model.MSysConfig;
import org.compiere.model.X_AD_CtxHelp;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.compiere.util.Util;
import org.zkoss.zk.ui.Component;
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.Events;
import org.zkoss.zk.ui.event.KeyEvent;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zk.ui.event.SwipeEvent;
import org.zkoss.zul.Menuitem;
import org.zkoss.zul.Style;
/**
* Controller for multiple desktop windows.
* Implemented using {@link Tabbox}.
* @author Low Heng Sin
*/
public class WindowContainer extends AbstractUIPart implements EventListener
{
private static final String OPTION_CLOSE = "Close";
private static final String OPTION_CLOSE_OTHER_WINDOWS = "CloseOtherWindows";
private static final String OPTION_CLOSE_WINDOWS_TO_THE_LEFT = "CloseWindowsToTheLeft";
private static final String OPTION_CLOSE_WINDOWS_TO_THE_RIGHT = "CloseWindowsToTheRight";
private static final String OPTION_CLOSE_ALL_WINDOWS = "CloseAllWindows";
public static final String ON_MOBILE_SET_SELECTED_TAB = "onMobileSetSelectedTab";
private static final String ON_AFTER_TAB_CLOSE = "onAfterTabClose";
private static final String ON_DEFER_SET_SELECTED_TAB = "onDeferSetSelectedTab";
public static final String ON_WINDOW_CONTAINER_SELECTION_CHANGED_EVENT = "onWindowContainerSelectionChanged";
public static final String DEFER_SET_SELECTED_TAB = "deferSetSelectedTab";
private static final int DEFAULT_MAX_TITLE_LENGTH = 30;
public static final String REPLACE_WINDOW_NO = "replaceWindowNo";
private Tabbox tabbox;
private ToolBar toolbar;
private ToolBarButton tabListBtn;
public WindowContainer()
{
}
/**
* @param tb
* @return WindowContainer
*/
public static WindowContainer createFrom(Tabbox tb)
{
WindowContainer wc = new WindowContainer();
wc.tabbox = tb;
return wc;
}
@Override
protected Component doCreatePart(Component parent)
{
if (isDesktopAutoShrinkTabTitle())
{
//style to enable auto shrink tab title and hide tab scroll buttons
Style style = new Style();
style.setContent(".desktop-tabbox > .z-tabs > .z-tabs-content {display:flex;width: auto !important;} "
+ ".desktop-tabbox > .z-tabs > .z-tabs-content > .z-tab {text-overflow: ellipsis;flex-shrink: 1;flex-basis: auto;min-width: 70px;} "
+ ".desktop-tabbox.z-tabbox > .z-tabbox-icon.z-tabbox-left-scroll,"
+ ".desktop-tabbox.z-tabbox > .z-tabbox-icon.z-tabbox-right-scroll {color:transparent;border:none;background:none;width:0px;} "
+ ".desktop-tabbox.z-tabbox-scroll > .z-tabs {margin:0px;} ");
parent.getParent().getParent().appendChild(style);
}
tabbox = new Tabbox();
tabbox.addEventListener("onPageAttached", this);
tabbox.addEventListener("onPageDetached", this);
tabbox.setSupportTabDragDrop(!isMobile());
tabbox.setActiveBySeq(true);
tabbox.setCheckVisibleOnlyForNextActive(!isMobile());
tabbox.setSclass("desktop-tabbox");
tabbox.setId("desktop_tabbox");
tabbox.setMaximalHeight(true);
tabbox.addEventListener(ON_DEFER_SET_SELECTED_TAB, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
Tab tab = (Tab) event.getData();
if (tab != null)
setSelectedTab(tab);
}
});
tabbox.addEventListener(ON_AFTER_TAB_CLOSE, evt -> {
if (isMobile()) {
updateMobileTabState(tabbox.getSelectedTab());
}
if (isShowTabList()) {
updateTabListButton();
}
});
Tabpanels tabpanels = new Tabpanels();
Tabs tabs = new Tabs();
//fix tabs scrolling issue for multiple tabs + tab toolbar
//not needed for mobile since mobile only show one tab at a time
if (!isMobile())
{
StringBuilder f = new StringBuilder();
f.append("function(way, tb) {\n")
.append(" let tabbox = this.getTabbox();let tabs = this.$n();\n")
.append(" this.$_scrollcheck(way,tb);\n")
.append(" if (tabs && !tabbox.isVertical() && !tabbox.inAccordionMold()) {\n")
.append(" this.__offsetWidth=tabs.offsetWidth;this.__scrollLeft=tabs.scrollLeft;\n")
.append(" this.__selectedIndex=tabbox.getSelectedIndex();\n")
.append(" this.__selectedTab=tabbox.getSelectedTab();\n")
.append(" } else {\n")
.append(" this.__offsetWidth=this.__scrollLeft==0;this.__selectedTab=null;this.__selectedIndex=-1;\n")
.append(" }\n")
.append("}");
tabs.setWidgetOverride("_scrollcheck", f.toString());
f = new StringBuilder();
f.append("function (toSel) {\n")
.append(" let tabbox = this.getTabbox();\n")
.append(" let tabs = this.$n();\n")
.append(" let tabsOffsetWidth=tabs.offsetWidth;\n")
.append(" this.$_fixWidth(toSel);\n")
.append(" if(this.__selectedTab && this.__selectedTab == tabbox.getSelectedTab() && this.__selectedIndex == tabbox.getSelectedIndex()) {\n")
.append(" if(tabs.offsetWidth == this.__offsetWidth) {\n")
.append(" if(tabsOffsetWidth != this.__offsetWidth && tabs.scrollLeft != this.__scrollLeft) {\n")
.append(" this._fixTabsScrollLeft(this.__scrollLeft);\n")
.append(" }\n")
.append(" }\n")
.append(" }\n")
.append("}");
tabs.setWidgetOverride("_fixWidth", f.toString());
//change _doScroll to immediate
f = new StringBuilder();
f.append("function (to, move) {\n")
.append(" if (move <= 0) return;\n")
.append(" let self=this,tabs = this.$n();\n")
.append(" switch (to) {\n")
.append(" case 'right':\n")
.append(" self._fixTabsScrollLeft(self._tabsScrollLeft + move);break;")
.append(" case 'left':\n")
.append(" self._fixTabsScrollLeft(self._tabsScrollLeft - move);break;")
.append(" case 'up':\n")
.append(" self._fixTabsScrollTop(self._tabsScrollTop - move);break;")
.append(" default:\n")
.append(" self._fixTabsScrollTop(self._tabsScrollTop + move);\n")
.append(" }\n")
.append(" let tabsScrollLeft = self._tabsScrollLeft, tabsScrollTop = self._tabsScrollTop;\n")
.append(" self._fixTabsScrollLeft(tabsScrollLeft <= 0 ? 0 : tabsScrollLeft);\n")
.append(" self._fixTabsScrollTop(tabsScrollTop <= 0 ? 0 : tabsScrollTop);\n")
.append("}");
tabs.setWidgetOverride("_doScroll", f.toString());
}
tabbox.appendChild(tabs);
tabbox.appendChild(tabpanels);
ZKUpdateUtil.setWidth(tabbox, "100%");
ZKUpdateUtil.setHeight(tabbox, "100%");
ZKUpdateUtil.setVflex(tabbox, "1");
ZKUpdateUtil.setHflex(tabbox, "1");
tabbox.setParent(parent);
toolbar = new ToolBar();
toolbar.setSclass("window-container-toolbar");
tabbox.appendChild(toolbar);
if (isShowHomeButton())
{
ToolBarButton homeButton = new ToolBarButton();
if (ThemeManager.isUseFontIconForImage())
homeButton.setIconSclass("z-icon-Home");
else
homeButton.setImage(ThemeManager.getThemeResource("images/Home16.png"));
homeButton.setSclass("window-container-toolbar-btn");
homeButton.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Home")));
homeButton.addEventListener(Events.ON_CLICK, evt -> setSelectedTab(tabbox.getTabpanel(0).getLinkedTab()));
toolbar.appendChild(homeButton);
}
if (isShowTabList())
{
tabListBtn = new ToolBarButton();
if (ThemeManager.isUseFontIconForImage())
{
tabListBtn.setIconSclass("z-icon-Expand");
}
else
{
tabListBtn.setImage(ThemeManager.getThemeResource("images/expand-header.png"));
}
tabListBtn.setSclass("window-container-toolbar-btn tab-list");
tabListBtn.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "ShowAllWindow")) + " Alt+W");
tabListBtn.addEventListener(Events.ON_CLICK, evt -> showTabList());
tabListBtn.setVisible(false);
toolbar.appendChild(tabListBtn);
}
SessionManager.getSessionApplication().getKeylistener().addEventListener(Events.ON_CTRL_KEY, (KeyEvent e) -> onCtrlKey(e));
return tabbox;
}
/**
* Handle ON_CTRL_KEY event
* @param e
*/
private void onCtrlKey(KeyEvent e) {
//alt+w
if (e.isAltKey() && !e.isCtrlKey() && !e.isShiftKey()) {
if (e.getKeyCode() == 87) {
if (tabListBtn != null && tabListBtn.isVisible())
Events.postEvent(Events.ON_CLICK, tabListBtn, null);
}
}
}
/**
* @return true if home button should be visible
*/
private boolean isShowHomeButton() {
return isMobile() || isDesktopShowHomeButton();
}
/**
* @return true to show home button for desktop browser
*/
private boolean isDesktopShowHomeButton() {
return MSysConfig.getBooleanValue(MSysConfig.ZK_DESKTOP_SHOW_HOME_BUTTON, true, Env.getAD_Client_ID(Env.getCtx()));
}
/**
* @return true to show tabs drop down list
*/
private boolean isShowTabList() {
return isMobile() || isDesktopAutoShrinkTabTitle() || isDesktopShowTabList();
}
/**
* @return true to show tabs drop down list for desktop browser
*/
private boolean isDesktopShowTabList() {
return MSysConfig.getBooleanValue(MSysConfig.ZK_DESKTOP_SHOW_TAB_LIST_BUTTON, true, Env.getAD_Client_ID(Env.getCtx()));
}
/**
* @return true to auto shrink title of tab to fit in more tabs without scrolling
*/
private boolean isDesktopAutoShrinkTabTitle() {
return MSysConfig.getBooleanValue(MSysConfig.ZK_DESKTOP_TAB_AUTO_SHRINK_TO_FIT, false, Env.getAD_Client_ID(Env.getCtx()));
}
/**
* Show tabs drop down list
*/
private void showTabList() {
org.zkoss.zul.Tabs tabs = tabbox.getTabs();
List list = tabs.getChildren();
Menupopup popup = new Menupopup();
for(int i = 1; i < list.size(); i++) {
Tab tab = (Tab) list.get(i);
Menuitem item = new Menuitem(tab.getLabel().endsWith("...") && !Util.isEmpty(tab.getTooltiptext(), true) ? tab.getTooltiptext() : tab.getLabel());
item.setValue(Integer.toString(i));
if (!Util.isEmpty(tab.getTooltiptext(), true) && !(item.getLabel().equals(tab.getTooltiptext())))
item.setTooltiptext(tab.getTooltiptext());
if (i == tabbox.getSelectedIndex())
item.setSclass("selected");
popup.appendChild(item);
item.addEventListener(Events.ON_CLICK, evt -> {
Menuitem t = (Menuitem) evt.getTarget();
String s = t.getValue();
Integer ti = Integer.parseInt(s);
setSelectedTab(tabbox.getTabpanel(ti.intValue()).getLinkedTab());
});
}
popup.setPage(tabbox.getPage());
popup.open(tabListBtn, "after_start");
}
/**
* @deprecated keep for compatible, replace by {@link #addWindow(Component, String, boolean, DecorateInfo)}
* @param comp
* @param title
* @param closeable
* @return
*/
@Deprecated(forRemoval = true, since = "11")
public Tab addWindow(Component comp, String title, boolean closeable){
return addWindow(comp, title, closeable, true, null);
}
/**
* @deprecated keep for compatible, replace by {@link #addWindow(Component, String, boolean, boolean, DecorateInfo)}
* @param comp
* @param title
* @param closeable
* @param enable
* @return
*/
@Deprecated(forRemoval = true, since = "11")
public Tab addWindow(Component comp, String title, boolean closeable, boolean enable) {
return addWindow(comp, title, closeable, true, null);
}
/**
* @deprecated keep for compatible, replace by {@link #insertBefore(Tab, Component, String, boolean, boolean, DecorateInfo)}
* @param refTab
* @param comp
* @param title
* @param closeable
* @param enable
* @return
*/
@Deprecated(forRemoval = true, since = "11")
public Tab insertBefore(Tab refTab, Component comp, String title, boolean closeable, boolean enable){
return insertBefore(refTab, comp, title, closeable, enable, null);
}
/**
* @deprecated keep for compatible, replace by {@link #insertAfter(Tab, Component, String, boolean, boolean, DecorateInfo)}
* @param refTab
* @param comp
* @param title
* @param closeable
* @param enable
* @return
*/
@Deprecated(forRemoval = true,since = "11")
public Tab insertAfter(Tab refTab, Component comp, String title, boolean closeable, boolean enable){
return insertAfter(refTab, comp, title, closeable, enable, null);
}
/**
* Add comp as new tab
* @param comp
* @param title
* @param closeable
* @param decorateInfo
* @return new tab
*/
public Tab addWindow(Component comp, String title, boolean closeable, DecorateInfo decorateInfo)
{
return addWindow(comp, title, closeable, true, decorateInfo);
}
/**
* Add comp as new tab
* @param comp
* @param title
* @param closeable
* @param enable
* @param decorateInfo
* @return new tab
*/
public Tab addWindow(Component comp, String title, boolean closeable, boolean enable, DecorateInfo decorateInfo)
{
return insertBefore(null, comp, title, closeable, enable, decorateInfo);
}
/**
* Insert comp as new tab before refTab
* @param refTab
* @param comp
* @param title
* @param closeable
* @param enable
* @param decorateInfo
* @return new tab
*/
public Tab insertBefore(Tab refTab, Component comp, String title, boolean closeable, boolean enable, DecorateInfo decorateInfo)
{
final Menupopup popupClose = new Menupopup();
final Tab tab = new Tab() {
/**
* generated serial id
*/
private static final long serialVersionUID = 2387473442130217806L;
@Override
public void close() {
super.close();
popupClose.detach();
popupClose.removeEventListener(Events.ON_OPEN, WindowContainer.this);
}
@Override
public void onPageDetached(Page page) {
super.onPageDetached(page);
if (tabbox != null && tabbox.getPage() != null) {
Events.postEvent(ON_AFTER_TAB_CLOSE, tabbox, null);
}
}
};
popupClose.addEventListener(Events.ON_OPEN, this);
popupClose.setAttribute("tab", tab);
tab.setDecorateInfo(decorateInfo);
if (title != null)
{
setTabTitle(title, tab);
}
tab.setClosable(closeable);
tab.addEventListener(Events.ON_SWIPE, new EventListener() {
@Override
public void onEvent(SwipeEvent event) throws Exception {
Tab tab = (Tab) event.getTarget();
if (tab.isClosable()
&& ("right".equals(event.getSwipeDirection()) || "left".equals(event.getSwipeDirection()))) {
tab.onClose();
}
}
});
// fix scroll position lost coming back into a grid view tab
tab.addEventListener(Events.ON_SELECT, new EventListener() {
public void onEvent(Event event) throws Exception {
Tab tab = (Tab)event.getTarget();
org.zkoss.zul.Tabpanel panel = tab.getLinkedPanel();
if (panel == null) {
return;
}
Component component = panel.getFirstChild();
if (component != null && component.getAttribute(ITabOnSelectHandler.ATTRIBUTE_KEY) instanceof ITabOnSelectHandler)
{
ITabOnSelectHandler handler = (ITabOnSelectHandler) component.getAttribute(ITabOnSelectHandler.ATTRIBUTE_KEY);
handler.onSelect();
}
if (component instanceof IHelpContext)
Events.sendEvent(new Event(ON_WINDOW_CONTAINER_SELECTION_CHANGED_EVENT, component));
else
SessionManager.getAppDesktop().updateHelpContext(X_AD_CtxHelp.CTXTYPE_Home, 0);
}
});
//disable text selection of tab label on mobile to
//fix conflict with long press context menu
if (ClientInfo.isMobile())
tab.setClientAttribute("onselectstart", "return false");
Tabpanel tabpanel = null;
if (comp instanceof Tabpanel) {
tabpanel = (Tabpanel) comp;
} else {
tabpanel = new Tabpanel();
tabpanel.appendChild(comp);
}
ZKUpdateUtil.setHeight(tabpanel, "100%");
ZKUpdateUtil.setWidth(tabpanel, "100%");
ZKUpdateUtil.setVflex(tabpanel, "1");
ZKUpdateUtil.setHflex(tabpanel, "1");
tabpanel.setSclass("desktop-tabpanel");
if (refTab == null)
{
tabbox.getTabs().appendChild(tab);
tabbox.getTabpanels().appendChild(tabpanel);
}
else
{
org.zkoss.zul.Tabpanel refpanel = refTab.getLinkedPanel();
tabbox.getTabs().insertBefore(tab, refTab);
tabbox.getTabpanels().insertBefore(tabpanel, refpanel);
}
if (enable)
{
Boolean b = (Boolean) comp.getAttribute(DEFER_SET_SELECTED_TAB);
if (b != null && b.booleanValue())
Events.echoEvent(ON_DEFER_SET_SELECTED_TAB, tabbox, tab);
else
setSelectedTab(tab);
}
Menuitem mi;
if (tab.getIndex() != 0) {
mi = new Menuitem(Msg.getMsg(Env.getCtx(), OPTION_CLOSE));
mi.setAttribute("option", OPTION_CLOSE);
popupClose.appendChild(mi);
mi.addEventListener(Events.ON_CLICK, new EventListener() {
public void onEvent(Event event) throws Exception {
int currentTabIndex = tab.getIndex();
int focusTabIndex = currentTabIndex;
int tabsSizeBeforeClose = tabbox.getTabs().getChildren().size();
if (tabsSizeBeforeClose == currentTabIndex + 1) {
focusTabIndex = currentTabIndex - 1;
}
closeTabs(tab, currentTabIndex, currentTabIndex, focusTabIndex);
}
});
mi = new Menuitem(Msg.getMsg(Env.getCtx(), OPTION_CLOSE_OTHER_WINDOWS));
mi.setAttribute("option", OPTION_CLOSE_OTHER_WINDOWS);
popupClose.appendChild(mi);
mi.addEventListener(Events.ON_CLICK, new EventListener() {
public void onEvent(Event event) throws Exception {
int currentTabIndex = tab.getIndex();
closeTabs(tab, currentTabIndex + 1, -1, currentTabIndex); // Right
int focusTabIndex = 1;
closeTabs(tab, 1, currentTabIndex - 1, focusTabIndex); // Left
}
});
mi = new Menuitem(Msg.getMsg(Env.getCtx(), OPTION_CLOSE_WINDOWS_TO_THE_LEFT));
mi.setAttribute("option", OPTION_CLOSE_WINDOWS_TO_THE_LEFT);
popupClose.appendChild(mi);
mi.addEventListener(Events.ON_CLICK, new EventListener() {
public void onEvent(Event event) throws Exception {
int currentTabIndex = tab.getIndex();
int focusTabIndex = 1;
closeTabs(tab, 1, currentTabIndex - 1, focusTabIndex);
}
});
mi = new Menuitem(Msg.getMsg(Env.getCtx(), OPTION_CLOSE_WINDOWS_TO_THE_RIGHT));
mi.setAttribute("option", OPTION_CLOSE_WINDOWS_TO_THE_RIGHT);
popupClose.appendChild(mi);
mi.addEventListener(Events.ON_CLICK, new EventListener() {
public void onEvent(Event event) throws Exception {
int currentTabIndex = tab.getIndex();
closeTabs(tab, currentTabIndex + 1, -1, currentTabIndex);
}
});
}
mi = new Menuitem(Msg.getMsg(Env.getCtx(), OPTION_CLOSE_ALL_WINDOWS));
mi.setAttribute("option", OPTION_CLOSE_ALL_WINDOWS);
popupClose.appendChild(mi);
mi.addEventListener(Events.ON_CLICK, new EventListener() {
public void onEvent(Event event) throws Exception {
int focusTabIndex = 0;
closeTabs(tab, 1, -1, focusTabIndex);
}
});
ZKUpdateUtil.setWidth(popupClose, "auto");
popupClose.setPage(tab.getPage());
tab.setContext(popupClose);
if (isShowTabList())
updateTabListButton();
return tab;
}
/**
* Close tabs from start to end, set focus to focus index parameter.
* @param tab
* @param start
* @param end
* @param focus
*/
protected void closeTabs(Tab tab, int start, int end, int focus) {
List tabs = tabbox.getTabs().getChildren();
if (end == -1) {
end = tabs.size() - 1;
}
for (int i = end; i >= start; i--) {
((Tab)tabs.get( i )).setSelected(false);
((Tab)tabs.get( i )).onClose();
}
tabbox.setSelectedIndex(focus);
Events.postEvent(ON_AFTER_TAB_CLOSE, tabbox, null);
}
/**
* Update label and visibility of tabs drop down list button.
*/
private void updateTabListButton() {
if (isShowTabList() && tabListBtn != null) {
int cnt = tabbox.getTabs().getChildren().size()-1;
if (cnt > 0) {
tabListBtn.setLabel(Integer.toString(cnt));
tabListBtn.setVisible(true);
} else {
tabListBtn.setLabel("");
tabListBtn.setVisible(false);
}
}
}
/**
* Set tab title by windowNo
* @param title
* @param windowNo
*/
public void setTabTitle(String title, int windowNo) {
setTabTitle(title, getTab(windowNo));
}
/**
* IDEMPIERE-2333 / getTab - get tab by windowNo
* @param windowNo
* @return org.zkoss.zul.Tab
*/
public org.zkoss.zul.Tab getTab(int windowNo) {
org.zkoss.zul.Tabpanels panels = tabbox.getTabpanels();
List> childrens = panels.getChildren();
for (Object child : childrens)
{
Tabpanel panel = (Tabpanel) child;
Component component = panel.getFirstChild();
Object att = component != null ? component.getAttribute(TabbedDesktop.WINDOWNO_ATTRIBUTE) : null;
if (att != null && (att instanceof Integer))
{
if (windowNo == (Integer)att)
{
org.zkoss.zul.Tab tab = panel.getLinkedTab();
return tab;
}
}
}
return null;
}
/**
* Set title of tab
* @param title
* @param tab
*/
public void setTabTitle(String title, org.zkoss.zul.Tab tab) {
if (tab == null)
return;
tab.setTooltiptext(title);
if (title.length() <= getMaxTitleLength())
{
tab.setLabel(title);
}
else
{
title = title.substring(0, getMaxTitleLength()-3) + "...";
tab.setLabel(title);
}
}
/**
* @return max length of tab title
*/
private int getMaxTitleLength() {
return MSysConfig.getIntValue(MSysConfig.ZK_DESKTOP_TAB_MAX_TITLE_LENGTH, DEFAULT_MAX_TITLE_LENGTH, Env.getAD_Client_ID(Env.getCtx()));
}
/**
* Insert comp as new tab after refTab.
* @param refTab
* @param comp
* @param title
* @param closeable
* @param enable
* @param decorateInfo
* @return new tab
*/
public Tab insertAfter(Tab refTab, Component comp, String title, boolean closeable, boolean enable, DecorateInfo decorateInfo)
{
if (refTab == null)
return addWindow(comp, title, closeable, enable, decorateInfo);
else
return insertBefore((Tab)refTab.getNextSibling(), comp, title, closeable, enable, decorateInfo);
}
/**
* IDEMPIERE-5275 - Tabular Report Re-Run button/close parameter window.
* Replace content of refTab with comp.
* @param refTab
* @param comp
* @param title
* @return org.zkoss.zul.Tab
*/
public org.zkoss.zul.Tab replace(org.zkoss.zul.Tab refTab, Window comp, String title) {
if (refTab == null)
{
throw new IllegalArgumentException();
}
else
{
org.zkoss.zul.Tabpanel refpanel = refTab.getLinkedPanel();
Component firstChild = refpanel.getFirstChild();
if(firstChild instanceof Window) {
if(firstChild instanceof ProcessDialog)
((ProcessDialog)firstChild).unlockUI(null);
else if(firstChild instanceof ZkReportViewer)
((ZkReportViewer)firstChild).hideBusyMask();
else if(firstChild instanceof AbstractADWindowContent)
((AbstractADWindowContent)firstChild).hideBusyMask();
((Window) firstChild).onClose();
comp.setParent(refpanel);
}
else {
firstChild.detach();
comp.setParent(refpanel);
}
}
if (title != null)
{
setTabTitle(title, refTab);
}
return refTab;
}
/**
* Set tab as selected tab.
* @param tab
*/
public void setSelectedTab(org.zkoss.zul.Tab tab)
{
if (isMobile())
updateMobileTabState(tab);
tabbox.setSelectedTab(tab);
}
/**
* Set tab to visible, other tabs to invisible.
* @param tab new selected tab to be set as visible
*/
private void updateMobileTabState(org.zkoss.zul.Tab tab) {
if (isMobile() && tabListBtn != null)
{
List tabs = tabbox.getTabs().getChildren();
for(Component c: tabs) {
if (c instanceof Tab) {
Tab t = (Tab) c;
t.setVisible(t == tab);
t.getLinkedPanel().setVisible(t == tab);
if (t.isVisible()) {
Events.postEvent(ON_MOBILE_SET_SELECTED_TAB, t.getLinkedPanel(), null);
}
}
}
}
}
/**
* @return true if browser client is visible
*/
private boolean isMobile() {
return ClientInfo.isMobile();
}
/**
* Close current active window (tab)
* @return true if successfully close the active window
*/
public boolean closeActiveWindow()
{
Tab tab = (Tab) tabbox.getSelectedTab();
tabbox.getSelectedTab().onClose();
if (tab.getParent() == null)
return true;
else
return false;
}
/**
* Get current selected tab
* @return Tab
*/
public Tab getSelectedTab() {
return (Tab) tabbox.getSelectedTab();
}
/**
* @param tabNo
* @param title
* @param tooltip
*/
public void setTabTitle(int tabNo, String title, String tooltip)
{
if (tabNo < 0 || tabNo >= tabbox.getTabs().getChildren().size())
return;
org.zkoss.zul.Tabs tabs = tabbox.getTabs();
Tab tab = (Tab) tabs.getChildren().get(tabNo);
setTabTitle(title, tab);
if (tooltip != null && tooltip.trim().length() > 0)
{
tab.setTooltiptext(tooltip);
}
}
/**
* @return Tabbox
*/
public Tabbox getComponent() {
return tabbox;
}
/**
* @return toolbar
*/
public ToolBar getToobar() {
return toolbar;
}
@Override
public void onEvent(Event event) throws Exception {
if (event.getTarget() == tabbox && "onPageDetached".equals(event.getName())) {
try {
SessionManager.getSessionApplication().getKeylistener().removeEventListener(Events.ON_CTRL_KEY, this);
} catch (Exception e) {}
}else if (event.getTarget() == tabbox && "onPageAttached".equals(event.getName())) {
try {
SessionManager.getSessionApplication().getKeylistener().addEventListener(Events.ON_CTRL_KEY, this);
} catch (Exception e) {}
}else if (event instanceof OpenEvent && event.getTarget() instanceof Menupopup) {
if (((OpenEvent)event).isOpen()) {
Menupopup popup = (Menupopup) event.getTarget();
List tabs = tabbox.getTabs().getChildren();
int tabsSize = tabs.size();
int currentTabIdx = -1;
if (popup.getAttribute("tab") != null) {
Tab currentTab = (Tab) popup.getAttribute("tab");
for ( int i = tabsSize - 1; i > 0; i-- ) {
Tab tab = ((Tab)tabs.get(i));
if (currentTab.equals(tab)) {
currentTabIdx = i;
break;
}
}
}
if (currentTabIdx > 0) {
List items = popup.getChildren();
for (Component item : items) {
if (item instanceof Menuitem) {
String option = (String) item.getAttribute("option");
boolean visible =
(OPTION_CLOSE.equals(option))
|| (tabsSize > 2 && (OPTION_CLOSE_OTHER_WINDOWS.equals(option) || OPTION_CLOSE_ALL_WINDOWS.equals(option)))
|| (currentTabIdx < tabsSize - 1 && OPTION_CLOSE_WINDOWS_TO_THE_RIGHT.equals(option))
|| (currentTabIdx > 1 && OPTION_CLOSE_WINDOWS_TO_THE_LEFT.equals(option));
item.setVisible(visible);
}
}
}
}
}else if (Events.ON_CTRL_KEY.equals(event.getName())) {
KeyEvent keyEvent = (KeyEvent) event;
if (keyEvent.isAltKey() && keyEvent.getKeyCode() == KeyEvent.PAGE_DOWN
&& tabbox.getSelectedTab() != null && tabbox.getSelectedTab().getNextSibling() != null) {
tabbox.setSelectedTab((org.zkoss.zul.Tab)tabbox.getSelectedTab().getNextSibling());
keyEvent.stopPropagation();
}else if (keyEvent.isAltKey() && keyEvent.getKeyCode() == KeyEvent.PAGE_UP
&& tabbox.getSelectedTab() != null && tabbox.getSelectedTab().getPreviousSibling() != null) {
tabbox.setSelectedTab((org.zkoss.zul.Tab)tabbox.getSelectedTab().getPreviousSibling());
keyEvent.stopPropagation();
}
}
}
}