/****************************************************************************** * 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(); } } } }