diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/LayoutUtils.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/LayoutUtils.java index 9758fc0b04..f2ea109029 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/LayoutUtils.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/LayoutUtils.java @@ -74,6 +74,11 @@ public final class LayoutUtils { || ((" " + sclass + " ").indexOf(" " + cls + " ") > -1); } + /** + * + * @param label + * @return wrapped label + */ public static Component makeRightAlign(Label label) { Div div = new Div(); div.setStyle("text-align: right"); @@ -154,6 +159,10 @@ public final class LayoutUtils { Clients.response("_openPopupWindow_", new AuScript(window, script.toString())); } + /** + * + * @param component + */ public static void redraw(AbstractComponent component) { StringWriter writer = new StringWriter(1024); try { @@ -163,4 +172,20 @@ public final class LayoutUtils { e.printStackTrace(); } } + + /** + * @param component + * @return true if the component and all its parent are visible + */ + public static boolean isReallyVisible(Component component) { + if (!component.isVisible()) return false; + Component parent = component.getParent(); + while (parent != null) { + if (!parent.isVisible()) + return false; + + parent = parent.getParent(); + } + return true; + } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/ValuePreference.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/ValuePreference.java index 02986f5ae4..7c2e238abf 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/ValuePreference.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/ValuePreference.java @@ -229,16 +229,9 @@ public class ValuePreference extends Window implements EventListener } } // ValuePreference - private AbstractADWindowContent findADWindowContent(Component ref) { - Component parent = ref.getParent(); - while(parent != null) { - if (parent.getAttribute(ADWindow.AD_WINDOW_ATTRIBUTE_KEY) != null) { - ADWindow adwindow = (ADWindow) parent.getAttribute(ADWindow.AD_WINDOW_ATTRIBUTE_KEY); - return adwindow.getADWindowContent(); - } - parent = parent.getParent(); - } - return null; + private AbstractADWindowContent findADWindowContent(Component comp) { + ADWindow adwindow = ADWindow.findADWindow(comp); + return adwindow != null ? adwindow.getADWindowContent() : null; } private Properties m_ctx; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADSortTab.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADSortTab.java index 6100d35095..8bd7778d2b 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADSortTab.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADSortTab.java @@ -936,7 +936,7 @@ public class ADSortTab extends Panel implements IADTabpanel } @Override - public boolean isActive() { + public boolean isActivated() { return active; } @@ -979,5 +979,14 @@ public class ADSortTab extends Panel implements IADTabpanel public int getTabNo() { return tabNo; } + + @Override + public void setDetailPane(DetailPane detailPane) { + } + + @Override + public DetailPane getDetailPane() { + return null; + } } //ADSortTab diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADTabpanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADTabpanel.java index 5eaaca78cf..6917c7ec07 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADTabpanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADTabpanel.java @@ -55,11 +55,15 @@ import org.compiere.model.DataStatusListener; import org.compiere.model.GridField; import org.compiere.model.GridTab; import org.compiere.model.GridWindow; +import org.compiere.model.I_AD_Preference; import org.compiere.model.MLookup; +import org.compiere.model.MPreference; +import org.compiere.model.MTable; import org.compiere.model.MToolBarButton; import org.compiere.model.MToolBarButtonRestrict; import org.compiere.model.MTree; import org.compiere.model.MTreeNode; +import org.compiere.model.Query; import org.compiere.model.X_AD_FieldGroup; import org.compiere.model.X_AD_ToolBarButton; import org.compiere.util.CLogger; @@ -70,13 +74,13 @@ import org.compiere.util.Msg; import org.compiere.util.Util; import org.zkoss.zk.au.out.AuFocus; import org.zkoss.zk.ui.Component; -import org.zkoss.zk.ui.Desktop; import org.zkoss.zk.ui.Executions; import org.zkoss.zk.ui.HtmlBasedComponent; import org.zkoss.zk.ui.IdSpace; 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.OpenEvent; import org.zkoss.zk.ui.util.Clients; import org.zkoss.zul.Button; import org.zkoss.zul.Cell; @@ -84,6 +88,7 @@ import org.zkoss.zul.Center; import org.zkoss.zul.DefaultTreeNode; import org.zkoss.zul.Div; import org.zkoss.zul.Separator; +import org.zkoss.zul.South; import org.zkoss.zul.Space; import org.zkoss.zul.Style; import org.zkoss.zul.TreeModel; @@ -108,6 +113,8 @@ import org.zkoss.zul.impl.XulElement; public class ADTabpanel extends Div implements Evaluatee, EventListener, DataStatusListener, IADTabpanel, IdSpace { + private static final String ON_SAVE_OPEN_PREFERENCE_EVENT = "onSaveOpenPreference"; + public static final String ON_POST_INIT_EVENT = "onPostInit"; public static final String ON_SWITCH_VIEW_EVENT = "onSwitchView"; @@ -159,17 +166,17 @@ DataStatusListener, IADTabpanel, IdSpace List allCollapsibleGroups = new ArrayList(); - private Component formContainer = null; + private Borderlayout formContainer = null; private ADTreePanel treePanel = null; private GridTabDataBinder dataBinder; - private boolean active = false; + private boolean activated = false; private Group currentGroup; - private Component detailPane; + private DetailPane detailPane; private boolean detailPaneMode; @@ -195,6 +202,7 @@ DataStatusListener, IADTabpanel, IdSpace } }); addEventListener(ON_POST_INIT_EVENT, this); + addEventListener(ON_SAVE_OPEN_PREFERENCE_EVENT, this); } private void initComponents() @@ -214,19 +222,32 @@ DataStatusListener, IADTabpanel, IdSpace listPanel.getListbox().addEventListener(Events.ON_DOUBLE_CLICK, this); } - public void addDetails(Component component) { + public void setDetailPane(DetailPane component) { detailPane = component; - if (formContainer instanceof Borderlayout) { - Borderlayout borderLayout = (Borderlayout) formContainer; - borderLayout.appendSouth(detailPane); - - borderLayout.getSouth().setCollapsible(true); - borderLayout.getSouth().setSplittable(true); - borderLayout.getSouth().setOpen(true); - borderLayout.getSouth().setSclass("adwindow-gridview-detail"); - } else { - formContainer.appendChild(component); - } + + Borderlayout borderLayout = (Borderlayout) formContainer; + South south = borderLayout.getSouth(); + if (south == null) { + south = new South(); + borderLayout.appendChild(south); + south.setWidgetOverride("doClick_", "function (evt){this.$doClick_(evt);" + + "var target = evt.domTarget;if (!target.id) target = target.parentNode;" + + "if(this.$n('colled') == target) {" + + "var se = new zk.Event(this, 'onSlide', null, {toServer: true}); zAu.send(se); } }"); + south.addEventListener(Events.ON_OPEN, this); + south.addEventListener("onSlide", this); + } + south.appendChild(component); + + south.setVisible(true); + south.setCollapsible(true); + south.setSplittable(true); + south.setOpen(isOpenDetailPane()); + south.setSclass("adwindow-gridview-detail"); + } + + public DetailPane getDetailPane() { + return detailPane; } /** @@ -291,6 +312,7 @@ DataStatusListener, IADTabpanel, IdSpace div.setHflex("1"); div.setSclass("adtab-form"); div.setStyle("overflow-y: visible;"); + div.setSpacing("0px"); layout.appendChild(center); formContainer = layout; @@ -305,6 +327,7 @@ DataStatusListener, IADTabpanel, IdSpace div.setStyle("overflow-y: visible;"); div.setVflex("1"); div.setWidth("100%"); + div.setSpacing("0px"); StringBuilder cssContent = new StringBuilder(); cssContent.append(".adtab-form-borderlayout .z-south-colpsd:before { "); @@ -867,7 +890,7 @@ DataStatusListener, IADTabpanel, IdSpace setAttribute(ATTR_ON_ACTIVATE_POSTED, Boolean.TRUE); } - active = activate; + activated = activate; if (listPanel.isVisible()) { if (activate) listPanel.activate(gridTab); @@ -940,18 +963,72 @@ DataStatusListener, IADTabpanel, IdSpace else if (WPaymentEditor.ON_SAVE_PAYMENT.equals(event.getName())) { windowPanel.onSavePayment(); } - else if (ON_POST_INIT_EVENT.equals(event.getName())) { + else if (ON_POST_INIT_EVENT.equals(event.getName())) { + if (isDetailVisible() && detailPane.getSelectedADTabpanel() != null) { + detailPane.getSelectedADTabpanel().activate(true); + } + } + else if (event.getTarget() instanceof South) { if (detailPane != null) { - Desktop desktop = Executions.getCurrent().getDesktop(); - //for unknown reason, this is needed once per desktop to fixed the layout of the detailpane. - if (desktop.getAttribute("adtabpanel.detailpane.postinit.redraw") == null) { - desktop.setAttribute("adtabpanel.detailpane.postinit.redraw", Boolean.TRUE); - Events.postEvent(new Event(LayoutUtils.ON_REDRAW_EVENT, detailPane)); + boolean openEvent = event instanceof OpenEvent; + if (openEvent) { + Events.echoEvent(ON_SAVE_OPEN_PREFERENCE_EVENT, this, ((OpenEvent)event).isOpen()); + if (!((OpenEvent)event).isOpen()) { + return; + } } + if (detailPane.getParent() == null) { + formContainer.appendSouth(detailPane); + } + IADTabpanel tabPanel = detailPane.getSelectedADTabpanel(); + if (tabPanel != null) { + if (!tabPanel.isActivated()) { + tabPanel.activate(true); + } + if (!tabPanel.isGridView()) { + tabPanel.switchRowPresentation(); + } + } + } + } + else if (event.getName().equals(ON_SAVE_OPEN_PREFERENCE_EVENT)) { + Boolean value = (Boolean) event.getData(); + int windowId = getGridTab().getAD_Window_ID(); + int adTabId = getGridTab().getAD_Tab_ID(); + if (windowId > 0 && adTabId > 0) { + Query query = new Query(Env.getCtx(), MTable.get(Env.getCtx(), I_AD_Preference.Table_ID), "AD_Window_ID=? AND Attribute=?", null); + MPreference preference = query.setOnlyActiveRecords(true) + .setApplyAccessFilter(true) + .setParameters(windowId, adTabId+"|DetailPane.IsOpen") + .first(); + if (preference != null && preference.getAD_Preference_ID() > 0) { + preference.setValue(value ? "Y" : "N"); + } else { + preference = new MPreference(Env.getCtx(), 0, null); + preference.setAD_Window_ID(windowId); + preference.setAttribute(adTabId+"|DetailPane.IsOpen"); + preference.setValue(value ? "Y" : "N"); + } + preference.save(); + //update current context + Env.getCtx().setProperty("P"+windowId+"|"+adTabId+"|DetailPane.IsOpen", value ? "Y" : "N"); } } } + private boolean isOpenDetailPane() { + boolean open = true; + int windowId = getGridTab().getAD_Window_ID(); + int adTabId = getGridTab().getAD_Tab_ID(); + if (windowId > 0 && adTabId > 0) { + String preference = Env.getPreference(Env.getCtx(), windowId, adTabId+"|DetailPane.IsOpen", false); + if (preference != null && preference.trim().length() > 0) { + open = "Y".equals(preference); + } + } + return open; + } + private void navigateTo(DefaultTreeNode value) { MTreeNode treeNode = value.getData(); // We Have a TreeNode @@ -1177,6 +1254,10 @@ DataStatusListener, IADTabpanel, IdSpace listPanel.focus(); } + /** + * + * @param columnName + */ public void setFocusToField(String columnName) { if (formContainer.isVisible()) { boolean found = false; @@ -1220,25 +1301,40 @@ DataStatusListener, IADTabpanel, IdSpace return listPanel; } - public boolean isActive() { - return active; + @Override + public boolean isActivated() { + return activated; } - + @Override public void setDetailPaneMode(boolean detailPaneMode) { if (this.detailPaneMode != detailPaneMode) { this.detailPaneMode = detailPaneMode; if (detailPaneMode) { - detailPane = null; - if (formContainer instanceof Borderlayout) { - Borderlayout borderLayout = (Borderlayout) formContainer; - if (borderLayout.getSouth() != null) { - borderLayout.getSouth().detach(); - } - } - } + hideDetail(); + } else { + showDetail(); + } this.setVflex("true"); listPanel.setDetailPaneMode(detailPaneMode); + } + } + + private void showDetail() { + if (formContainer.getSouth() != null) { + formContainer.getSouth().setVisible(true); + if (formContainer.getSouth().isOpen() && detailPane != null && detailPane.getParent() == null) { + formContainer.appendSouth(detailPane); + } + } + } + + private void hideDetail() { + if (formContainer.getSouth() != null) { + formContainer.getSouth().setVisible(false); + if (detailPane != null && detailPane.getParent() != null) { + detailPane.detach(); + } } } @@ -1287,5 +1383,46 @@ DataStatusListener, IADTabpanel, IdSpace public int getTabNo() { return tabNo; } + + /** + * activate current selected detail tab if it is visible + */ + public void activateDetailIfVisible() { + if (isDetailVisible()) { + IADTabpanel tabPanel = detailPane.getSelectedADTabpanel(); + if (tabPanel != null && !tabPanel.isActivated()) { + tabPanel.activate(true); + if (!tabPanel.isGridView()) { + tabPanel.switchRowPresentation(); + } + } + } + + } + + /** + * + * @return true if the detailpane is visible + */ + public boolean isDetailVisible() { + if (formContainer.getSouth() == null || !formContainer.getSouth().isVisible() + || !formContainer.getSouth().isOpen()) { + return false; + } + + return detailPane != null; + } + + /** + * + * @return true if have one or more detail tabs + */ + public boolean hasDetailTabs() { + if (formContainer.getSouth() == null || !formContainer.getSouth().isVisible()) { + return false; + } + + return detailPane != null && detailPane.getTabcount() > 0; + } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindow.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindow.java index c6303ceca6..725cc3f135 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindow.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindow.java @@ -51,11 +51,22 @@ public class ADWindow extends AbstractUIPart private static final CCache imageCache = new CCache(null, "WindowImageCache", 5, false); + /** + * + * @param ctx + * @param adWindowId + */ public ADWindow(Properties ctx, int adWindowId) { this(ctx, adWindowId, null); } + /** + * + * @param ctx + * @param adWindowId + * @param query + */ public ADWindow(Properties ctx, int adWindowId, MQuery query) { if(adWindowId <= 0) @@ -75,11 +86,19 @@ public class ADWindow extends AbstractUIPart image = windowContent.getImage(); } + /** + * + * @return title of window + */ public String getTitle() { return _title; } + /** + * + * @return image for the country + */ public MImage getMImage() { return image; @@ -118,6 +137,7 @@ public class ADWindow extends AbstractUIPart } } + @Override public Component getComponent() { return windowPanelComponent; } @@ -129,7 +149,28 @@ public class ADWindow extends AbstractUIPart return windowContent; } + /** + * + * @param windowNo + * @return adwindow instance for windowNo ( if any ) + */ public static ADWindow get(int windowNo) { return (ADWindow) SessionManager.getAppDesktop().findWindow(windowNo); } + + /** + * @param comp + * @return adwindow instance if found, null otherwise + */ + public static ADWindow findADWindow(Component comp) { + Component parent = comp.getParent(); + while(parent != null) { + if (parent.getAttribute(AD_WINDOW_ATTRIBUTE_KEY) != null) { + ADWindow adwindow = (ADWindow) parent.getAttribute(AD_WINDOW_ATTRIBUTE_KEY); + return adwindow; + } + parent = parent.getParent(); + } + return null; + } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindowContent.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindowContent.java index 0d80540643..054fb12a94 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindowContent.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindowContent.java @@ -75,6 +75,7 @@ public class ADWindowContent extends AbstractADWindowContent } else { layout.setPage(page); } + layout.setSpacing("0px"); //toolbar Div north = new Div(); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java index d431865ae6..a1a5071957 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java @@ -140,7 +140,9 @@ import org.zkoss.zul.Window.Mode; public abstract class AbstractADWindowContent extends AbstractUIPart implements ToolbarListener, EventListener, DataStatusListener, ActionListener { - private static final CLogger logger; + private static final String ON_DEFER_SET_DETAILPANE_SELECTION_EVENT = "onDeferSetDetailpaneSelection"; + + private static final CLogger logger; static { @@ -213,6 +215,7 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements Component comp = super.createPart(parent); comp.addEventListener(LayoutUtils.ON_REDRAW_EVENT, this); + comp.addEventListener(ON_DEFER_SET_DETAILPANE_SELECTION_EVENT, this); return comp; } @@ -976,7 +979,7 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements if (eventData != null && eventData instanceof Object[] && ((Object[])eventData).length == 2) { Object[] indexes = (Object[]) eventData; - int newTabIndex = (Integer)indexes[1]; + final int newTabIndex = (Integer)indexes[1]; final int originalTabIndex = adTabbox.getSelectedIndex(); final int originalTabRow = adTabbox.getSelectedGridTab().getCurrentRow(); @@ -986,7 +989,14 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements public void onCallback(Boolean result) { if (result) { - adTabbox.setDetailpaneSelection(originalTabIndex, originalTabRow); + if (newTabIndex < originalTabIndex) + { + if (adTabbox.isDetailPaneLoaded()) + adTabbox.setDetailPaneSelectedTab(originalTabIndex, originalTabRow); + else { + Events.echoEvent(new Event(ON_DEFER_SET_DETAILPANE_SELECTION_EVENT, getComponent(), new Integer[]{originalTabIndex, originalTabRow})); + } + } } else { @@ -1027,6 +1037,10 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements } LayoutUtils.redraw((AbstractComponent) getComponent()); } + else if (event.getName().equals(ON_DEFER_SET_DETAILPANE_SELECTION_EVENT)) { + Integer[] data = (Integer[]) event.getData(); + adTabbox.setDetailPaneSelectedTab(data[0], data[1]); + } } private void setActiveTab(final int newTabIndex, final Callback callback) { @@ -1099,10 +1113,10 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements IADTabpanel newTabpanel = adTabbox.getSelectedTabpanel(); - boolean activated = newTabpanel.isActive(); + boolean activated = newTabpanel.isActivated(); if (oldTabpanel != null) oldTabpanel.activate(false); - if (activated) + if (!activated) newTabpanel.activate(true); back = (newTabIndex < oldTabIndex); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/BreadCrumb.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/BreadCrumb.java index 8e1fbd3487..8faebf134a 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/BreadCrumb.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/BreadCrumb.java @@ -28,6 +28,7 @@ import org.adempiere.webui.component.Tabpanel; import org.adempiere.webui.component.ToolBar; import org.adempiere.webui.component.ToolBarButton; import org.adempiere.webui.component.Window; +import org.adempiere.webui.component.ZkCssHelper; import org.adempiere.webui.event.ToolbarListener; import org.adempiere.webui.window.WRecordInfo; import org.compiere.model.DataStatusEvent; @@ -37,6 +38,7 @@ import org.compiere.util.Env; import org.compiere.util.Msg; import org.compiere.util.Util; import org.zkoss.zhtml.Text; +import org.zkoss.zk.au.out.AuScript; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Execution; import org.zkoss.zk.ui.Executions; @@ -62,6 +64,10 @@ import org.zkoss.zul.Space; */ public class BreadCrumb extends Div implements EventListener { + private static final String ON_MOUSE_OVER_ECHO_EVENT = "onMouseOverEcho"; + + private static final String ON_MOUSE_OUT_ECHO_EVENT = "onMouseOutEcho"; + private static final String INFO_INDICATOR_IMAGE = "/images/InfoIndicator16.png"; private static final String ERROR_INDICATOR_IMAGE = "/images/ErrorIndicator16.png"; @@ -160,12 +166,24 @@ public class BreadCrumb extends Div implements EventListener { toolbar.setStyle("background-image: none; background-color: transparent; border: none;"); setWidgetAttribute(AdempiereWebUI.WIDGET_INSTANCE_NAME, "breadcrumb"); + + this.addEventListener(ON_MOUSE_OUT_ECHO_EVENT, this); } + /** + * + * @param listener + */ public void setToolbarListener(ToolbarListener listener) { this.toolbarListener = listener; } + /** + * + * @param label + * @param id + * @param clickable + */ public void addPath(String label, String id, boolean clickable) { if (clickable) { BreadCrumbLink a = new BreadCrumbLink(); @@ -193,6 +211,10 @@ public class BreadCrumb extends Div implements EventListener { } } + /** + * + * @return list of parent links + */ public List getParentLinks() { List parents = new ArrayList(); for(Component component : layout.getChildren()) { @@ -202,20 +224,63 @@ public class BreadCrumb extends Div implements EventListener { return parents; } + /** + * add links to other tabs at the same level + * @param links + */ public void addLinks(LinkedHashMap links) { this.links = links; final Label pathLabel = (Label) layout.getChildren().get(layout.getChildren().size()-2); - pathLabel.setStyle("cursor: pointer; font-weight: bold"); + pathLabel.setStyle("cursor: pointer; font-weight: bold; padding-right: 10px;"); EventListener listener = new EventListener() { @Override public void onEvent(Event event) throws Exception { - if (linkPopup != null ) { - if (linkPopup.getPage() != null && linkPopup.isVisible()) { - return; + if (linkPopup != null && linkPopup.getPage() != null && linkPopup.isVisible()) { + if (event.getName().equals(Events.ON_MOUSE_OUT)) { + linkPopup.setAttribute(ON_MOUSE_OUT_ECHO_EVENT, Boolean.TRUE); + StringBuilder script = new StringBuilder("setTimeout(function(){var w=zk('#") + .append(BreadCrumb.this.getUuid()).append("').$();") + .append("var e=new zk.Event(w, '") + .append(ON_MOUSE_OUT_ECHO_EVENT) + .append("', null, {toServer:true});") + .append("zAu.send(e);},500)"); + final AuScript response = new AuScript(script.toString()); + Clients.response(response); } + return; } - linkPopup = new Menupopup(); + if (event.getName().equals(Events.ON_CLICK)) { + if (linkPopup != null && linkPopup.getPage() != null) + linkPopup.detach(); + linkPopup = new Menupopup(); + showLinksMenu(pathLabel); + } else if (event.getName().equals(Events.ON_MOUSE_OVER)) { + if (linkPopup == null || !linkPopup.isVisible()) { + if (linkPopup != null && linkPopup.getPage() != null) + linkPopup.detach(); + linkPopup = new Menupopup(); + StringBuilder script = new StringBuilder("setTimeout(function(){var w=zk('#") + .append(event.getTarget().getUuid()).append("').$();") + .append("var e=new zk.Event(w, '") + .append(ON_MOUSE_OVER_ECHO_EVENT) + .append("', null, {toServer:true});") + .append("zAu.send(e);},500)"); + AuScript response = new AuScript(script.toString()); + Clients.response(response); + } + } else if (event.getName().equals(Events.ON_MOUSE_OUT)) { + if (linkPopup != null && linkPopup.getPage() == null) { + linkPopup = null; + } + } else if (event.getName().equals(ON_MOUSE_OVER_ECHO_EVENT)) { + if (linkPopup != null && linkPopup.getPage() == null) { + showLinksMenu(pathLabel); + } + } + } + + private void showLinksMenu(final Label pathLabel) { for(Map.Entryentry : BreadCrumb.this.links.entrySet()) { final Menuitem item = new Menuitem(); item.setLabel(entry.getValue()); @@ -223,12 +288,41 @@ public class BreadCrumb extends Div implements EventListener { item.addEventListener(Events.ON_CLICK, BreadCrumb.this); linkPopup.appendChild(item); } + + StringBuilder script = new StringBuilder("setTimeout(function(){var w=zk('#") + .append(BreadCrumb.this.getUuid()).append("').$();") + .append("var e=new zk.Event(w, '") + .append(ON_MOUSE_OUT_ECHO_EVENT) + .append("', null, {toServer:true});") + .append("zAu.send(e);},500)"); + final AuScript response = new AuScript(script.toString()); + linkPopup.addEventListener(Events.ON_MOUSE_OUT, new EventListener() { + @Override + public void onEvent(Event event) throws Exception { + if (linkPopup != null) { + linkPopup.setAttribute(ON_MOUSE_OUT_ECHO_EVENT, Boolean.TRUE); + Clients.response(response); + } + } + }); + linkPopup.addEventListener(Events.ON_MOUSE_OVER, new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + if (linkPopup != null && linkPopup.isVisible()) { + linkPopup.removeAttribute(ON_MOUSE_OUT_ECHO_EVENT); + } + } + }); linkPopup.setPage(pathLabel.getPage()); - linkPopup.open(pathLabel); + linkPopup.open(pathLabel); } }; pathLabel.addEventListener(Events.ON_CLICK, listener); pathLabel.addEventListener(Events.ON_MOUSE_OVER, listener); + pathLabel.addEventListener(Events.ON_MOUSE_OUT, listener); + pathLabel.addEventListener(ON_MOUSE_OVER_ECHO_EVENT, listener); + ZkCssHelper.appendStyle(pathLabel, "background: transparent url('images/downarrow.png') no-repeat right center"); } @Override @@ -241,10 +335,9 @@ public class BreadCrumb extends Div implements EventListener { String title = Msg.getMsg(Env.getCtx(), "Who") + m_text; new WRecordInfo (title, m_dse); - }else if(event.getTarget() instanceof RecordLink){ + } else if(event.getTarget() instanceof RecordLink){ doZoom((RecordLink)event.getTarget()); - } - else if (event.getTarget().getParent() == messageContainer) { + } else if (event.getTarget().getParent() == messageContainer) { showPopup(); } else if (event.getTarget() == btnFirst) { if (toolbarListener != null) @@ -258,23 +351,42 @@ public class BreadCrumb extends Div implements EventListener { } else if (event.getTarget() == btnLast) { if (toolbarListener != null) toolbarListener.onLast(); + } else if (event.getName().equals(ON_MOUSE_OUT_ECHO_EVENT)) { + if (linkPopup != null && linkPopup.getPage() != null && linkPopup.isVisible() + && linkPopup.getAttribute(ON_MOUSE_OUT_ECHO_EVENT) != null) { + linkPopup.detach(); + linkPopup = null; + } } else { Events.sendEvent(this, event); } } + /** + * remove all links + */ public void reset() { - layout.getChildren().clear(); - layout.appendChild(toolbarContainer); - this.links = null; + if (layout.getChildren().size() == 0 || layout.getChildren().size() > 1) { + layout.getChildren().clear(); + layout.appendChild(toolbarContainer); + this.links = null; + } } + /** + * enable/disable first record and previous record toolbar button + * @param enabled + */ public void enableFirstNavigation(boolean enabled) { this.btnFirst.setDisabled(!enabled); this.btnPrevious.setDisabled(!enabled); } + /** + * enable or disable the next record and last record toolbar button + * @param enabled + */ public void enableLastNavigation(boolean enabled) { this.btnLast.setDisabled(!enabled); @@ -505,7 +617,6 @@ public class BreadCrumb extends Div implements EventListener { msgPopup.setContentStyle("overflow: auto"); msgPopup.setWidth("500px"); msgPopup.appendChild(msgPopupCnt); -// msgPopup.setPage(SessionManager.getAppDesktop().getComponent().getPage()); msgPopup.setShadow(true); msgPopupCaption = new Caption(); msgPopup.appendChild(msgPopupCaption); @@ -524,10 +635,17 @@ public class BreadCrumb extends Div implements EventListener { linkPopup.detach(); } + /** + * + * @param visible + */ public void setNavigationToolbarVisibility(boolean visible) { toolbarContainer.setVisible(visible); } + /** + * @return true if there are one or more parent link + */ public boolean hasParentLink() { for(Component c : layout.getChildren()) { if (c instanceof BreadCrumbLink) { @@ -537,6 +655,10 @@ public class BreadCrumb extends Div implements EventListener { return false; } + /** + * + * @return process logs + */ public ProcessInfoLog[] getPLogs() { return pInfoLogs; } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/CompositeADTabbox.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/CompositeADTabbox.java index 3065122612..6e94047fd2 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/CompositeADTabbox.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/CompositeADTabbox.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; +import java.util.logging.Level; import org.adempiere.util.Callback; import org.adempiere.webui.component.ADTabListModel; @@ -54,10 +55,11 @@ import org.zkoss.zul.Vlayout; */ public class CompositeADTabbox extends AbstractADTabbox { + private static final String ON_POST_TAB_SELECTION_CHANGED_EVENT = "onPostTabSelectionChanged"; + public static final String ON_SELECTION_CHANGED_EVENT = "onSelectionChanged"; /** Logger */ - @SuppressWarnings("unused") private static CLogger log = CLogger.getCLogger (CompositeADTabbox.class); private List tabLabelList = new ArrayList(); @@ -66,17 +68,17 @@ public class CompositeADTabbox extends AbstractADTabbox private Vlayout layout; - protected DetailPane detailPane; - private EventListener selectionListener; private IADTabpanel headerTab; private int selectedIndex = 0; - public CompositeADTabbox() - { - detailPane = new DetailPane(); + public CompositeADTabbox(){ + } + + protected DetailPane createDetailPane() { + DetailPane detailPane = new DetailPane(); detailPane.setEventListener(new EventListener() { @Override @@ -84,8 +86,8 @@ public class CompositeADTabbox extends AbstractADTabbox if (DetailPane.ON_EDIT_EVENT.equals(event.getName())) { if (headerTab.getGridTab().isNew()) return; - final int row = detailPane.getSelectedADTabpanel() != null - ? detailPane.getSelectedADTabpanel().getGridTab().getCurrentRow() + final int row = getSelectedDetailADTabpanel() != null + ? getSelectedDetailADTabpanel().getGridTab().getCurrentRow() : 0; final boolean formView = event.getData() != null ? (Boolean)event.getData() : true; adWindowPanel.saveAndNavigate(new Callback() { @@ -99,8 +101,8 @@ public class CompositeADTabbox extends AbstractADTabbox else if (DetailPane.ON_NEW_EVENT.equals(event.getName())) { if (headerTab.getGridTab().isNew()) return; - final int row = detailPane.getSelectedADTabpanel() != null - ? detailPane.getSelectedADTabpanel().getGridTab().getCurrentRow() + final int row = getSelectedDetailADTabpanel() != null + ? getSelectedDetailADTabpanel().getGridTab().getCurrentRow() : 0; adWindowPanel.saveAndNavigate(new Callback() { @Override @@ -116,7 +118,7 @@ public class CompositeADTabbox extends AbstractADTabbox else if (DetailPane.ON_DELETE_EVENT.equals(event.getName())) { if (headerTab.getGridTab().isNew()) return; - final IADTabpanel tabPanel = detailPane.getSelectedADTabpanel(); + final IADTabpanel tabPanel = getSelectedDetailADTabpanel(); if (tabPanel != null && tabPanel.getGridTab().getRowCount() > 0 && tabPanel.getGridTab().getCurrentRow() >= 0) { FDialog.ask(tabPanel.getGridTab().getWindowNo(), null, "DeleteRecord?", new Callback() { @@ -134,12 +136,14 @@ public class CompositeADTabbox extends AbstractADTabbox } } } - }); + }); + + return detailPane; } - + protected void onEditDetail(int row, boolean formView) { int oldIndex = selectedIndex; - IADTabpanel selectedPanel = detailPane.getSelectedADTabpanel(); + IADTabpanel selectedPanel = getSelectedDetailADTabpanel(); if (selectedPanel == null) return; int newIndex = selectedPanel.getTabNo(); @@ -168,6 +172,13 @@ public class CompositeADTabbox extends AbstractADTabbox } else { layout.setPage(page); } + + layout.addEventListener(ON_POST_TAB_SELECTION_CHANGED_EVENT, new EventListener() { + @Override + public void onEvent(Event event) throws Exception { + onPostTabSelectionChanged(); + } + }); BreadCrumb breadCrumb = getBreadCrumb(); breadCrumb.addEventListener(Events.ON_CLICK, new EventListener() { @@ -210,12 +221,10 @@ public class CompositeADTabbox extends AbstractADTabbox return; IADTabpanel tabPanel = (IADTabpanel) event.getTarget(); - if (tabPanel == headerTab) { + if (tabPanel != headerTab) { if (b != null && b.booleanValue()) { - activateDetailADTabpanel(); - } - } else { - onActivateDetail(tabPanel); + onActivateDetail(tabPanel); + } } } }); @@ -225,26 +234,26 @@ public class CompositeADTabbox extends AbstractADTabbox public void onEvent(Event event) throws Exception { final IADTabpanel tabPanel = (IADTabpanel) event.getTarget(); int oldIndex = (Integer) event.getData(); - if (oldIndex != detailPane.getSelectedIndex()) { - IADTabpanel prevTabPanel = detailPane.getADTabpanel(oldIndex); + if (oldIndex != headerTab.getDetailPane().getSelectedIndex()) { + IADTabpanel prevTabPanel = headerTab.getDetailPane().getADTabpanel(oldIndex); if (prevTabPanel != null && prevTabPanel.needSave(true, true)) { - final int newIndex = detailPane.getSelectedIndex(); - detailPane.setSelectedIndex(oldIndex); + final int newIndex = headerTab.getDetailPane().getSelectedIndex(); + headerTab.getDetailPane().setSelectedIndex(oldIndex); adWindowPanel.saveAndNavigate(new Callback() { @Override public void onCallback(Boolean result) { if (result) { - detailPane.setSelectedIndex(newIndex); - onActivateDetail(tabPanel); + headerTab.getDetailPane().setSelectedIndex(newIndex); + tabPanel.activate(true); } } }); } else { - detailPane.setSelectedIndex(detailPane.getSelectedIndex()); - onActivateDetail(tabPanel); + headerTab.getDetailPane().setSelectedIndex(headerTab.getDetailPane().getSelectedIndex()); + tabPanel.activate(true); } } else { - onActivateDetail(tabPanel); + tabPanel.activate(true); } } }); @@ -259,7 +268,8 @@ public class CompositeADTabbox extends AbstractADTabbox if (detailPanel != null) { detailPanel.setDetailPaneMode(true); } - detailPane.setVflex("true"); + if (headerTab.getDetailPane() != null) + headerTab.getDetailPane().setVflex("true"); } } }); @@ -272,7 +282,7 @@ public class CompositeADTabbox extends AbstractADTabbox if (tabPanel == headerTab) { adWindowPanel.onToggle(); } else { - detailPane.onEdit(true); + headerTab.getDetailPane().onEdit(true); } } @@ -295,19 +305,18 @@ public class CompositeADTabbox extends AbstractADTabbox headerTab = tabPanel; updateBreadCrumb(); } else if (tabLabel.tabLevel <= 1) { - if (detailPane.getParent() == null) { - ADTabpanel adtabpanel = (ADTabpanel) headerTab; - adtabpanel.addDetails(detailPane); + if (headerTab.getDetailPane() == null) { + headerTab.setDetailPane(createDetailPane()); } else tabPanel.setVisible(false); - detailPane.setHflex("1"); - detailPane.addADTabpanel(tabPanel, tabLabel); + headerTab.getDetailPane().setHflex("1"); + headerTab.getDetailPane().addADTabpanel(tabPanel, tabLabel); tabPanel.setDetailPaneMode(true); - detailPane.setVflex("true"); + headerTab.getDetailPane().setVflex("true"); } else { - detailPane.addADTabpanel(tabPanel, tabLabel, false); + headerTab.getDetailPane().addADTabpanel(tabPanel, tabLabel, false); tabPanel.setDetailPaneMode(true); - detailPane.setVflex("true"); + headerTab.getDetailPane().setVflex("true"); } HtmlBasedComponent htmlComponent = (HtmlBasedComponent) tabPanel; htmlComponent.setVflex("1"); @@ -316,39 +325,33 @@ public class CompositeADTabbox extends AbstractADTabbox tabPanel.getGridTab().addDataStatusListener(new SyncDataStatusListener(tabPanel)); } - private void activateDetailADTabpanel() { - if (detailPane != null && detailPane.getParent() != null) { - IADTabpanel tabPanel = detailPane.getSelectedADTabpanel(); - if (tabPanel != null) { - tabPanel.activate(true); - if (!tabPanel.isGridView()) { - tabPanel.switchRowPresentation(); - } - } + private void activateDetailIfVisible() { + if (headerTab instanceof ADTabpanel) { + ((ADTabpanel)headerTab).activateDetailIfVisible(); } } @Override protected void updateTabState() { - if (detailPane != null && detailPane.getTabcount() > 0) + if (isDetailPaneLoaded()) { - for(int i = 0; i < detailPane.getTabcount(); i++) + for(int i = 0; i < headerTab.getDetailPane().getTabcount(); i++) { - IADTabpanel adtab = detailPane.getADTabpanel(i); + IADTabpanel adtab = headerTab.getDetailPane().getADTabpanel(i); if (adtab.getDisplayLogic() != null && adtab.getDisplayLogic().trim().length() > 0) { if (!Evaluator.evaluateLogic(headerTab, adtab.getDisplayLogic())) { - detailPane.setTabVisibility(i, false); + headerTab.getDetailPane().setTabVisibility(i, false); } else { - detailPane.setTabVisibility(i, true); + headerTab.getDetailPane().setTabVisibility(i, true); } } } - int selected = detailPane.getSelectedIndex(); - if (detailPane.getADTabpanel(selected) == null || !detailPane.isTabVisible(selected)) { - for(int i = 0; i < detailPane.getTabcount(); i++) { + int selected = headerTab.getDetailPane().getSelectedIndex(); + if (headerTab.getDetailPane().getADTabpanel(selected) == null || !headerTab.getDetailPane().isTabVisible(selected)) { + for(int i = 0; i < headerTab.getDetailPane().getTabcount(); i++) { if (selected == i) continue; - if (detailPane.isTabVisible(i)) { - detailPane.setSelectedIndex(i); + if (headerTab.getDetailPane().isTabVisible(i)) { + headerTab.getDetailPane().setSelectedIndex(i); break; } } @@ -387,46 +390,68 @@ public class CompositeADTabbox extends AbstractADTabbox layout.getChildren().clear(); layout.appendChild(headerTab); - detailPane.detach(); - detailPane.reset(); - - int currentLevel = headerTab.getTabLevel(); - for (int i = selectedIndex + 1; i< tabPanelList.size(); i++) { - IADTabpanel tabPanel = tabPanelList.get(i); - int tabLevel = tabPanel.getTabLevel(); - ADTabListModel.ADTabLabel tabLabel = tabLabelList.get(i); - if ((tabLevel - currentLevel) == 1 || (tabLevel == 0 && currentLevel == 0)) { - if (tabPanel.isActive() && !tabPanel.isGridView()) { - tabPanel.switchRowPresentation(); - } - if (tabPanel.getParent() != null) tabPanel.detach(); - detailPane.addADTabpanel(tabPanel, tabLabel); - tabPanel.setDetailPaneMode(true); - } else if (tabLevel > currentLevel ){ - detailPane.addADTabpanel(tabPanel, tabLabel, false); - tabPanel.setDetailPaneMode(true); - } else { - break; - } - } - - if (detailPane.getTabcount() > 0 && !headerTab.getGridTab().isSortTab()) { - ADTabpanel adtabpanel = (ADTabpanel) headerTab; - adtabpanel.addDetails(detailPane); - detailPane.setVflex("true"); - detailPane.setSelectedIndex(0); - activateDetailADTabpanel(); - } - + //set state headerTab.setDetailPaneMode(false); + getBreadCrumb().getFirstChild().setVisible(false); - updateBreadCrumb(); + Events.echoEvent(new Event(ON_POST_TAB_SELECTION_CHANGED_EVENT, layout)); } - private void updateBreadCrumb() { + private void onPostTabSelectionChanged() { + if (headerTab instanceof ADTabpanel) { + DetailPane detailPane = headerTab.getDetailPane(); + if (detailPane == null) { + detailPane = createDetailPane(); + } + + int tabIndex = -1; + int currentLevel = headerTab.getTabLevel(); + for (int i = selectedIndex + 1; i< tabPanelList.size(); i++) { + IADTabpanel tabPanel = tabPanelList.get(i); + int tabLevel = tabPanel.getTabLevel(); + ADTabListModel.ADTabLabel tabLabel = tabLabelList.get(i); + if ((tabLevel - currentLevel) == 1 || (tabLevel == 0 && currentLevel == 0)) { + if (tabPanel.isActivated() && !tabPanel.isGridView()) { + tabPanel.switchRowPresentation(); + } + if (tabPanel.getParent() != null) tabPanel.detach(); + tabIndex++; + detailPane.setADTabpanel(tabIndex, tabPanel, tabLabel); + tabPanel.setDetailPaneMode(true); + } else if (tabLevel > currentLevel ){ + tabIndex++; + detailPane.setADTabpanel(tabIndex, tabPanel, tabLabel, false); + tabPanel.setDetailPaneMode(true); + } else { + break; + } + } + + if (detailPane.getTabcount() > 0 && !headerTab.getGridTab().isSortTab()) { + detailPane.setVflex("true"); + detailPane.setSelectedIndex(0); + if (headerTab.getDetailPane() == null) { + headerTab.setDetailPane(detailPane); + } + activateDetailIfVisible(); + } + } + + updateBreadCrumb(); + getBreadCrumb().getFirstChild().setVisible(true); + + updateTabState(); + + ADWindow adwindow = ADWindow.findADWindow(layout); + if (adwindow != null) { + adwindow.getADWindowContent().getToolbar().enableTabNavigation(getBreadCrumb().hasParentLink(), + headerTab.getDetailPane() != null && headerTab.getDetailPane().getTabcount() > 0); + } + } + + private void updateBreadCrumb() { BreadCrumb breadCrumb = getBreadCrumb(); breadCrumb.reset(); - if (selectedIndex > 0) { List parents = new ArrayList(); List parentIndex = new ArrayList(); @@ -510,14 +535,15 @@ public class CompositeADTabbox extends AbstractADTabbox Execution execution = Executions.getCurrent(); if (execution == null) return; - if (tabPanel == headerTab && detailPane.getPage() != null && e.getChangedColumn() == -1) { + if (tabPanel == headerTab && e.getChangedColumn() == -1 + && isDetailActivated()) { ArrayList parentColumnNames = new ArrayList(); GridField[] parentFields = headerTab.getGridTab().getFields(); for (GridField parentField : parentFields) { parentColumnNames.add(parentField.getColumnName()); } - IADTabpanel detailTab = detailPane.getSelectedADTabpanel(); + IADTabpanel detailTab = getSelectedDetailADTabpanel(); if (detailTab != null) { //check data action String uuid = (String) execution.getAttribute(CompositeADTabbox.class.getName()+".dataAction"); @@ -540,7 +566,7 @@ public class CompositeADTabbox extends AbstractADTabbox detailTab.activate(true); detailTab.setDetailPaneMode(true); } - detailPane.setVflex("true"); + headerTab.getDetailPane().setVflex("true"); } } @@ -548,13 +574,24 @@ public class CompositeADTabbox extends AbstractADTabbox @Override public void onDetailRecord() { - if (detailPane != null && detailPane.getSelectedADTabpanel() != null) { + if (headerTab.getDetailPane() != null && getSelectedDetailADTabpanel() != null) { try { - detailPane.onEdit(false); - } catch (Exception e) {} + headerTab.getDetailPane().onEdit(false); + } catch (Exception e) { + log.log(Level.SEVERE, e.getLocalizedMessage(), e); + } } } + public boolean isDetailActivated() { + if (headerTab instanceof ADTabpanel) { + ADTabpanel atp = (ADTabpanel) headerTab; + return atp.hasDetailTabs() && getSelectedDetailADTabpanel() != null && + getSelectedDetailADTabpanel().isActivated(); + } + return false; + } + @Override public boolean isSortTab() { return headerTab != null ? headerTab.getGridTab().isSortTab() : false; @@ -562,8 +599,8 @@ public class CompositeADTabbox extends AbstractADTabbox @Override public IADTabpanel getSelectedDetailADTabpanel() { - if (detailPane != null && detailPane.getParent() != null) { - return detailPane.getSelectedADTabpanel(); + if (headerTab instanceof ADTabpanel && ((ADTabpanel)headerTab).hasDetailTabs()) { + return headerTab.getDetailPane().getSelectedADTabpanel(); } return null; } @@ -612,7 +649,7 @@ public class CompositeADTabbox extends AbstractADTabbox @Override public void setDetailPaneStatusMessage(String status, boolean error) { - detailPane.setStatusMessage(status, error); + headerTab.getDetailPane().setStatusMessage(status, error); } @Override @@ -636,9 +673,9 @@ public class CompositeADTabbox extends AbstractADTabbox tabPanel.switchRowPresentation(); } tabPanel.setDetailPaneMode(true); - detailPane.setVflex("true"); + headerTab.getDetailPane().setVflex("true"); if (tabPanel instanceof ADSortTab) { - detailPane.updateToolbar(false, true); + headerTab.getDetailPane().updateToolbar(false, true); } else { tabPanel.dynamicDisplay(0); } @@ -648,7 +685,7 @@ public class CompositeADTabbox extends AbstractADTabbox String msg = CLogger.retrieveErrorString(null); if (msg != null) { - detailPane.setStatusMessage(Msg.getMsg(Env.getCtx(), msg), true); + headerTab.getDetailPane().setStatusMessage(Msg.getMsg(Env.getCtx(), msg), true); } //other error will be catch in the dataStatusChanged event } @@ -656,24 +693,36 @@ public class CompositeADTabbox extends AbstractADTabbox @Override public void updateDetailPaneToolbar(boolean changed, boolean readOnly) { if (headerTab.getGridTab().isNew() || headerTab.getGridTab().getRowCount() == 0) - detailPane.disableToolbar(); + headerTab.getDetailPane().disableToolbar(); else - detailPane.updateToolbar(changed, readOnly); + headerTab.getDetailPane().updateToolbar(changed, readOnly); } @Override - public void setDetailpaneSelection(int tabIndex, int currentRow) { - if (detailPane.getTabcount() > 0) { - for(int i = 0; i < detailPane.getTabcount(); i++) { - IADTabpanel adtab = detailPane.getADTabpanel(i); - int index = adtab.getTabNo(); - if (index == tabIndex) { - if (!detailPane.isTabVisible(i) || !detailPane.isTabEnabled(i)) { + public boolean isDetailPaneLoaded() { + if (headerTab.getDetailPane() == null || headerTab.getDetailPane().getTabcount() == 0) + return false; + for(int i = 0; i < headerTab.getDetailPane().getTabcount(); i++) { + if (headerTab.getDetailPane().getADTabpanel(i) == null) + return false; + } + return true; + } + + @Override + public void setDetailPaneSelectedTab(int adTabNo, int currentRow) { + if (headerTab instanceof ADTabpanel && ((ADTabpanel) headerTab).hasDetailTabs()) { + for(int i = 0; i < headerTab.getDetailPane().getTabcount(); i++) { + IADTabpanel adtab = headerTab.getDetailPane().getADTabpanel(i); + if (adtab == null) continue; + int tabNo = adtab.getTabNo(); + if (tabNo == adTabNo) { + if (!headerTab.getDetailPane().isTabVisible(i) || !headerTab.getDetailPane().isTabEnabled(i)) { return; } - if (i != detailPane.getSelectedIndex()) { - detailPane.setSelectedIndex(i); - detailPane.fireActivateDetailEvent(); + if (i != headerTab.getDetailPane().getSelectedIndex()) { + headerTab.getDetailPane().setSelectedIndex(i); + headerTab.getDetailPane().fireActivateDetailEvent(); } if (adtab.getGridTab().getCurrentRow() != currentRow) adtab.getGridTab().setCurrentRow(currentRow, true); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/DetailPane.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/DetailPane.java index c3d04b92be..c8798b88f0 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/DetailPane.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/DetailPane.java @@ -114,15 +114,25 @@ public class DetailPane extends Panel implements EventListener, IdSpace { setId("detailPane"); } + /** + * @return selected tab index + */ public int getSelectedIndex() { return tabbox.getSelectedIndex(); } + /** + * set selected tab index + * @param curTabIndex + */ public void setSelectedIndex(int curTabIndex) { tabbox.setSelectedIndex(curTabIndex); prevSelectedIndex = curTabIndex; } + /** + * @return number of tabs + */ public int getTabcount() { int count = 0; Tabs tabs = tabbox.getTabs(); @@ -131,18 +141,64 @@ public class DetailPane extends Panel implements EventListener, IdSpace { return count; } + /** + * undo last tab selection + */ public void undoLastTabSelection() { tabbox.setSelectedIndex(prevSelectedIndex); } + /** + * redraw tabbox + */ public void refresh() { tabbox.invalidate(); } + /** + * replace of add + * @param index + * @param tabPanel + * @param tabLabel + */ + public void setADTabpanel(int index, IADTabpanel tabPanel, ADTabLabel tabLabel) { + if (index < getTabcount()) { + tabbox.getTabpanel(index).appendChild(tabPanel); + } else { + addADTabpanel(tabPanel, tabLabel); + } + } + + /** + * replace or add + * @param index + * @param tabPanel + * @param tabLabel + * @param enabled + */ + public void setADTabpanel(int index, IADTabpanel tabPanel, ADTabLabel tabLabel, boolean enabled) { + if (index < getTabcount()) { + tabbox.getTabpanel(index).appendChild(tabPanel); + } else { + addADTabpanel(tabPanel, tabLabel, enabled); + } + } + + /** + * + * @param tabPanel + * @param tabLabel + */ public void addADTabpanel(IADTabpanel tabPanel, ADTabLabel tabLabel) { addADTabpanel(tabPanel, tabLabel, true); } + /** + * + * @param tabPanel + * @param tabLabel + * @param enabled + */ public void addADTabpanel(IADTabpanel tabPanel, ADTabLabel tabLabel, boolean enabled) { Tabs tabs = tabbox.getTabs(); if (tabs == null) { @@ -280,10 +336,17 @@ public class DetailPane extends Panel implements EventListener, IdSpace { LayoutUtils.openPopupWindow(button, popup, "after_start"); } + /** + * + * @param listener + */ public void setEventListener(EventListener listener) { eventListener = listener; } + /** + * remove all tabs and tabpanels + */ public void reset() { if (tabbox.getTabs() != null) { tabbox.getTabs().getChildren().clear(); @@ -294,6 +357,10 @@ public class DetailPane extends Panel implements EventListener, IdSpace { } + /** + * @param index + * @return adtabpanel at index + */ public IADTabpanel getADTabpanel(int index) { if (index < 0 || index >= tabbox.getTabpanels().getChildren().size()) return null; @@ -306,6 +373,10 @@ public class DetailPane extends Panel implements EventListener, IdSpace { return null; } + /** + * + * @return selected adtabpanel + */ public IADTabpanel getSelectedADTabpanel() { org.zkoss.zul.Tabpanel selectedPanel = tabbox.getSelectedPanel(); if (selectedPanel != null) { @@ -317,6 +388,11 @@ public class DetailPane extends Panel implements EventListener, IdSpace { return null; } + /** + * + * @param status + * @param error + */ public void setStatusMessage(String status, boolean error) { IADTabpanel tabPanel = getSelectedADTabpanel(); if (tabPanel == null) return; @@ -404,7 +480,8 @@ public class DetailPane extends Panel implements EventListener, IdSpace { createPopupContent(status); showPopup(error, messageContainer); } else if (event.getName().equals(ADTabpanel.ON_DYNAMIC_DISPLAY_EVENT)) { - updateProcessToolbar(); + if (LayoutUtils.isReallyVisible(this)) + updateProcessToolbar(); } else if (event.getName().equals(LayoutUtils.ON_REDRAW_EVENT)) { ExecutionCtrl ctrl = (ExecutionCtrl) Executions.getCurrent(); Event evt = ctrl.getNextEvent(); @@ -463,6 +540,11 @@ public class DetailPane extends Panel implements EventListener, IdSpace { tabbox.setVflex(flex); } + /** + * update toolbar button state + * @param changed + * @param readOnly + */ public void updateToolbar(boolean changed, boolean readOnly) { int index = getSelectedIndex(); if (index < 0 || index >= getTabcount()) return; @@ -503,6 +585,7 @@ public class DetailPane extends Panel implements EventListener, IdSpace { Toolbar toolbar = (Toolbar) tabpanel.getFirstChild(); IADTabpanel adtab = getADTabpanel(index); + if (adtab == null) return; for(Component c : toolbar.getChildren()) { if (c instanceof ToolBarButton) { @@ -519,11 +602,19 @@ public class DetailPane extends Panel implements EventListener, IdSpace { } } + /** + * Edit current record + * @param formView + * @throws Exception + */ public void onEdit(boolean formView) throws Exception { Event openEvent = new Event(ON_EDIT_EVENT, DetailPane.this, Boolean.valueOf(formView)); eventListener.onEvent(openEvent); } + /** + * fire the on activate detail event + */ public void fireActivateDetailEvent() { int index = tabbox.getSelectedIndex(); IADTabpanel tabPanel = (IADTabpanel) tabbox.getTabpanel(index).getChildren().get(1); @@ -531,11 +622,15 @@ public class DetailPane extends Panel implements EventListener, IdSpace { Events.sendEvent(activateEvent); } - public void setTabVisibility(int i, boolean visible) { - if (i < 0 || tabbox.getTabs() == null || i >= tabbox.getTabs().getChildren().size()) + /** + * @param tabIndex + * @param visible + */ + public void setTabVisibility(int tabIndex, boolean visible) { + if (tabIndex < 0 || tabbox.getTabs() == null || tabIndex >= tabbox.getTabs().getChildren().size()) return; - Tab tab = (Tab) tabbox.getTabs().getChildren().get(i); + Tab tab = (Tab) tabbox.getTabs().getChildren().get(tabIndex); tab.setVisible(visible); if (tab.isSelected()) { tab.setSelected(false); @@ -545,29 +640,46 @@ public class DetailPane extends Panel implements EventListener, IdSpace { } } - public boolean isTabVisible(int i) { - if (i < 0 || tabbox.getTabs() == null || i >= tabbox.getTabs().getChildren().size()) + /** + * + * @param tabIndex + * @return true if tab at tabIndex is visible + */ + public boolean isTabVisible(int tabIndex) { + if (tabIndex < 0 || tabbox.getTabs() == null || tabIndex >= tabbox.getTabs().getChildren().size()) return false; - return tabbox.getTabs().getChildren().get(i).isVisible(); + return tabbox.getTabs().getChildren().get(tabIndex).isVisible(); } - public boolean isTabEnabled(int i) { - if (i < 0 || tabbox.getTabs() == null || i >= tabbox.getTabs().getChildren().size()) + /** + * @param tabIndex + * @return true if tab at tabIndex is enable + */ + public boolean isTabEnabled(int tabIndex) { + if (tabIndex < 0 || tabbox.getTabs() == null || tabIndex >= tabbox.getTabs().getChildren().size()) return false; - Tab tab = (Tab) tabbox.getTabs().getChildren().get(i); + Tab tab = (Tab) tabbox.getTabs().getChildren().get(tabIndex); return !tab.isDisabled(); } - public void setTabEnabled(int i, boolean enabled) { - if (i < 0 || tabbox.getTabs() == null || i >= tabbox.getTabs().getChildren().size()) + /** + * + * @param tabIndex + * @param enabled + */ + public void setTabEnabled(int tabIndex, boolean enabled) { + if (tabIndex < 0 || tabbox.getTabs() == null || tabIndex >= tabbox.getTabs().getChildren().size()) return; - Tab tab = (Tab) tabbox.getTabs().getChildren().get(i); + Tab tab = (Tab) tabbox.getTabs().getChildren().get(tabIndex); tab.setDisabled(!enabled); } + /** + * disable toolbar + */ public void disableToolbar() { int index = getSelectedIndex(); if (index < 0 || index >= getTabcount()) return; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/IADTabbox.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/IADTabbox.java index c98d589062..519aa569ec 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/IADTabbox.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/IADTabbox.java @@ -109,25 +109,72 @@ public interface IADTabbox extends UIPart { */ public void setADWindowPanel(AbstractADWindowContent abstractADWindowPanel); + /** + * drill down to the current selected adtabpanel + */ public void onDetailRecord(); + /** + * @return true if current header tab is a sort tab + */ public boolean isSortTab(); + /** + * @param rowChange + * @param onlyRealChange + * @return true if there are changes pending to be save + */ public boolean needSave(boolean rowChange, boolean onlyRealChange); + /** + * ignore all pending changes + */ public void dataIgnore(); + /** + * @return selected header grid tab + */ public GridTab getSelectedGridTab(); + /** + * + * @param onSaveEvent + * @return true if save is successfull + */ public boolean dataSave(boolean onSaveEvent); + /** + * + * @param status + * @param error + */ public void setDetailPaneStatusMessage(String status, boolean error); + /** + * @return the currently selected detail adtabpanel + */ IADTabpanel getSelectedDetailADTabpanel(); + /** + * @return dirty adtabpanel that need save ( if any ) + */ IADTabpanel getDirtyADTabpanel(); + /** + * + * @param changed + * @param readOnly + */ public void updateDetailPaneToolbar(boolean changed, boolean readOnly); - public void setDetailpaneSelection(int tabIndex, int currentRow); + /** + * @param tabIndex + * @param currentRow + */ + public void setDetailPaneSelectedTab(int tabIndex, int currentRow); + + /** + * @return true if all the tabs of detail pane have been linked up with adtabpanel + */ + boolean isDetailPaneLoaded(); } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/IADTabpanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/IADTabpanel.java index cc2242bf16..aa1efe2c12 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/IADTabpanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/IADTabpanel.java @@ -120,19 +120,64 @@ public interface IADTabpanel extends Component, Evaluatee { */ public boolean isGridView(); - public boolean isActive(); + /** + * @return true if the panel have been activated + */ + public boolean isActivated(); + /** + * + * @param detailMode + */ public void setDetailPaneMode(boolean detailMode); + /** + * + * @return true if the panel is in detailpane node + */ public boolean isDetailPaneMode(); + /** + * + * @return gridview instance + */ public abstract GridView getGridView(); + /** + * + * @param rowChange + * @param onlyRealChange + * @return true if there are pending changes + */ public boolean needSave(boolean rowChange, boolean onlyRealChange); + /** + * @param onSaveEvent + * @return true if the save operation completed successfully + */ public boolean dataSave(boolean onSaveEvent); + /** + * + * @param tabNo + */ public void setTabNo(int tabNo); - public int getTabNo(); + /** + * + * @return tab no ( ad_tab.tabno ) + */ + public int getTabNo(); + + /** + * + * @param detailPane + */ + public void setDetailPane(DetailPane detailPane); + + /** + * + * @return detailpane + */ + public DetailPane getDetailPane(); } diff --git a/org.adempiere.ui.zk/theme/default/css/theme.css.dsp b/org.adempiere.ui.zk/theme/default/css/theme.css.dsp index a4c04a101a..1016ee24d2 100644 --- a/org.adempiere.ui.zk/theme/default/css/theme.css.dsp +++ b/org.adempiere.ui.zk/theme/default/css/theme.css.dsp @@ -488,6 +488,7 @@ div.wc-modal, div.wc-modal-none, div.wc-highlighted, div.wc-highlighted-none { border: none; width: 100%; height: 100%; + background-color: #F9F9F9; } .adwindow-layout .z-center { @@ -577,10 +578,12 @@ div.wc-modal, div.wc-modal-none, div.wc-highlighted, div.wc-highlighted-none { .adwindow-gridview-detail + .z-south-splt { border-top: 1px solid #C5C5C5; + border-bottom: 1px solid #C5C5C5; } .adwindow-gridview-detail .z-south-body { padding-top: 1px; + background-color: #D3D3D3; } .adwindow-gridview-borderlayout { @@ -807,6 +810,12 @@ tr.z-group { font-family: Helvetica,Arial,sans-serif; } +.z-group td.z-group-inner { + overflow: hidden !important; + border-bottom: 1px solid #CFCFCF !important; + border-top: 1px solid #CFCFCF !important; +} + <%-- Tablet --%> .tablet-scrolling { -webkit-overflow-scrolling: touch; @@ -1043,12 +1052,6 @@ tbody.z-grid-empty-body td { width: 85% !important; } -.z-group td.z-group-inner { - overflow: hidden !important; - border-bottom: 1px solid #CFCFCF !important; - border-top: 1px solid #CFCFCF !important; -} - .embedded-dialog { position: absolute; }