diff --git a/org.adempiere.ui.zk/WEB-INF/src/metainfo/zk/lang-addon.xml b/org.adempiere.ui.zk/WEB-INF/src/metainfo/zk/lang-addon.xml index eb25926ccf..01943e5c0e 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/metainfo/zk/lang-addon.xml +++ b/org.adempiere.ui.zk/WEB-INF/src/metainfo/zk/lang-addon.xml @@ -57,6 +57,6 @@ Copyright (C) 2007 Ashley G Ramdass (ADempiere WebUI). - + diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WDocumentStatusIndicator.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WDocumentStatusIndicator.java index 87b2700515..c0d83a5b9f 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WDocumentStatusIndicator.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WDocumentStatusIndicator.java @@ -57,6 +57,16 @@ public class WDocumentStatusIndicator extends Panel implements EventListener queue = EventQueues.lookup(IDesktop.ACTIVITIES_EVENT_QUEUE, true); - Event event = new Event(IDesktop.ON_ACTIVITIES_CHANGED_EVENT, null, count); - queue.publish(event); + } - public void updateUI() { + public void updateUI() { for (WDocumentStatusIndicator indicator : indicatorList) { indicator.updateUI(); } + EventQueue queue = EventQueues.lookup(IDesktop.ACTIVITIES_EVENT_QUEUE, true); + Event event = new Event(IDesktop.ON_ACTIVITIES_CHANGED_EVENT, null, lastRefreshCount); + queue.publish(event); } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPActivities.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPActivities.java index eb240118aa..4feed62654 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPActivities.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPActivities.java @@ -178,4 +178,9 @@ public class DPActivities extends DashboardPanel implements EventListener } } } + + @Override + public boolean isLazy() { + return true; + } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPCalendar.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPCalendar.java index 63d16f8ed3..6f34a9becc 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPCalendar.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPCalendar.java @@ -597,4 +597,9 @@ public class DPCalendar extends DashboardPanel implements EventListener, trx.removeTrxEventListener(this); } } + + @Override + public boolean isLazy() { + return true; + } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPDocumentStatus.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPDocumentStatus.java index c74e8cb71a..e17c078627 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPDocumentStatus.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPDocumentStatus.java @@ -52,7 +52,7 @@ public class DPDocumentStatus extends DashboardPanel implements EventListener 0){ - parentCtr.paPanel.setGoals(performanceData, (Options)null); - if (parentCtr.getAttribute(ON_POST_RENDER_ATTR) == null) { - parentCtr.setAttribute(ON_POST_RENDER_ATTR, Boolean.TRUE); - Events.echoEvent("onPostRender", parentCtr, null); - } - } - } - }); - - } - } public void refresh(ServerPushTemplate template) { - super.refresh(template); + performanceData = WPAPanel.loadGoal(); if (Executions.getCurrent() != null) { + updateUI(); if (this.getAttribute(ON_POST_RENDER_ATTR) == null && paPanel.getChildren().size() > 0) { setAttribute(ON_POST_RENDER_ATTR, Boolean.TRUE); Events.echoEvent("onPostRender", this, null); } + } else { + template.executeAsync(this); } } @@ -121,4 +93,15 @@ public class DPPerformance extends DashboardPanel { this.getFirstChild().invalidate(); } } + + @Override + public void updateUI() { + paPanel.setGoals(performanceData, (Options)null); + performanceData = null; + } + + @Override + public boolean isLazy() { + return true; + } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPRecentItems.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPRecentItems.java index e041b878db..d280cd65b4 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPRecentItems.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPRecentItems.java @@ -93,7 +93,6 @@ public class DPRecentItems extends DashboardPanel implements EventListener { @Override public void onMessage(Integer message) { diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPRunningJobs.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPRunningJobs.java index 533445cff6..e2e6a9e56b 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPRunningJobs.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPRunningJobs.java @@ -82,7 +82,6 @@ public class DPRunningJobs extends DashboardPanel implements EventListener { @Override public void onMessage(Integer message) { diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DashboardPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DashboardPanel.java index a6e702eef4..43c78643b6 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DashboardPanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DashboardPanel.java @@ -33,9 +33,11 @@ public abstract class DashboardPanel extends Window implements IDashboardPanel { super(); } + @Override public void refresh(ServerPushTemplate template) { } + @Override public void updateUI() { } @@ -45,4 +47,12 @@ public abstract class DashboardPanel extends Window implements IDashboardPanel { public boolean isPooling() { return false; } + + /** + * Override this together with refresh and updateUI to implement background loading of gadget + * @return true if panel created without loading of data + */ + public boolean isLazy() { + return false; + } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/desktop/DashboardController.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/desktop/DashboardController.java index 832b325205..be1545a648 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/desktop/DashboardController.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/desktop/DashboardController.java @@ -33,10 +33,12 @@ import java.util.Properties; import java.util.logging.Level; import org.adempiere.exceptions.AdempiereException; +import org.adempiere.util.ContextRunnable; import org.adempiere.webui.ClientInfo; import org.adempiere.webui.Extensions; import org.adempiere.webui.LayoutUtils; import org.adempiere.webui.apps.AEnv; +import org.adempiere.webui.apps.BusyDialog; import org.adempiere.webui.apps.graph.IChartRendererService; import org.adempiere.webui.apps.graph.WGraph; import org.adempiere.webui.apps.graph.WPAWidget; @@ -49,8 +51,10 @@ import org.adempiere.webui.dashboard.DashboardRunnable; import org.adempiere.webui.report.HTMLExtension; import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.theme.ThemeManager; +import org.adempiere.webui.util.ServerPushTemplate; import org.adempiere.webui.util.ZKUpdateUtil; import org.adempiere.webui.window.ZkReportViewerProvider; +import org.compiere.Adempiere; import org.compiere.model.I_AD_Menu; import org.compiere.model.MChart; import org.compiere.model.MDashboardContent; @@ -200,7 +204,7 @@ public class DashboardController implements EventListener { int AD_User_ID = Env.getAD_User_ID(Env.getCtx()); int AD_Role_ID = Env.getAD_Role_ID(Env.getCtx()); - MDashboardPreference[] dps = MDashboardPreference.getForSession(AD_User_ID, AD_Role_ID, true); + MDashboardPreference[] dps = MDashboardPreference.getForSession(AD_User_ID, AD_Role_ID, true); MDashboardContent [] dcs = MDashboardContentAccess.get(Env.getCtx(), AD_Role_ID, AD_User_ID, null); if(dps.length == 0){ @@ -245,9 +249,9 @@ public class DashboardController implements EventListener { { dashboardColumnLayout = new Vlayout(); dashboardColumnLayout.setSclass("dashboard-column"); - dashboardColumnLayout.setAttribute(COLUMN_NO_ATTRIBUTE, columnNo); - dashboardColumnLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); - dashboardColumnLayout.setAttribute(IS_ADDITIONAL_COLUMN_ATTRIBUTE, false); + dashboardColumnLayout.setAttribute(COLUMN_NO_ATTRIBUTE, columnNo); + dashboardColumnLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); + dashboardColumnLayout.setAttribute(IS_ADDITIONAL_COLUMN_ATTRIBUTE, false); Anchorchildren dashboardColumn = new Anchorchildren(); dashboardColumn.setAnchor(width + "%" + " 100%"); if (!ClientInfo.isMobile()) @@ -269,19 +273,48 @@ public class DashboardController implements EventListener { } else { panel = newGadgetPanel(dp, dc); } - if (panel != null && panel.getAttribute(PANEL_EMPTY_ATTRIBUTE) == null) + if (panel != null && panel.getAttribute(PANEL_EMPTY_ATTRIBUTE) == null) dashboardColumnLayout.appendChild(panel); if (!update) { - renderGadgetPanel(dc, panel); + final Panel fp = panel; + ServerPushTemplate spt = new ServerPushTemplate(dashboardLayout.getDesktop()); + IDesktop appDesktop = SessionManager.getAppDesktop(); + String contextPath = Executions.getCurrent().getContextPath(); + Panelchildren panelChildren = new Panelchildren(); + fp.appendChild(panelChildren); + BusyDialog busyDialog = new BusyDialog(); + busyDialog.setShadow(false); + panelChildren.appendChild(busyDialog); + //must create zulfile component in foreground UI thread + Component zComponent = null; + if (!Util.isEmpty(dc.getZulFilePath(), true)) { + try { + zComponent = Extensions.getDashboardGadget(dc.getZulFilePath(), panelChildren, dc); + } catch (Exception e) { + throw new AdempiereException(e); + } + } + final Component zulComponent = zComponent; + ContextRunnable cr = new ContextRunnable() { + @Override + protected void doRun() { + try { + asyncRenderGadgetPanel(spt, dc, fp, appDesktop, contextPath, panelChildren, zulComponent); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + Adempiere.getThreadPoolExecutor().submit(cr); } } if (dps.length == 0) { dashboardColumnLayout = new Vlayout(); - dashboardColumnLayout.setAttribute(COLUMN_NO_ATTRIBUTE, "0"); - dashboardColumnLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); - dashboardColumnLayout.setAttribute(IS_ADDITIONAL_COLUMN_ATTRIBUTE, true); + dashboardColumnLayout.setAttribute(COLUMN_NO_ATTRIBUTE, "0"); + dashboardColumnLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); + dashboardColumnLayout.setAttribute(IS_ADDITIONAL_COLUMN_ATTRIBUTE, true); Anchorchildren dashboardColumn = new Anchorchildren(); dashboardColumn.setAnchor((width-5) + "%" + " 100%"); if (!ClientInfo.isMobile()) @@ -299,9 +332,9 @@ public class DashboardController implements EventListener { // additional column dashboardColumnLayout = new Vlayout(); ZKUpdateUtil.setWidth(dashboardColumnLayout, "100%"); - dashboardColumnLayout.setAttribute(COLUMN_NO_ATTRIBUTE, currentColumnNo + 1); - dashboardColumnLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); - dashboardColumnLayout.setAttribute(IS_ADDITIONAL_COLUMN_ATTRIBUTE, true); + dashboardColumnLayout.setAttribute(COLUMN_NO_ATTRIBUTE, currentColumnNo + 1); + dashboardColumnLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); + dashboardColumnLayout.setAttribute(IS_ADDITIONAL_COLUMN_ATTRIBUTE, true); Anchorchildren dashboardColumn = new Anchorchildren(); dashboardColumn.setAnchor(extraWidth + "% 100%"); if (!ClientInfo.isMobile()) @@ -321,9 +354,9 @@ public class DashboardController implements EventListener { } // - if (!update && !dashboardRunnable.isEmpty()) + if (!update) { - startDashboardRunnable(parent); + startDashboardRunnable(parent); } } @@ -387,19 +420,50 @@ public class DashboardController implements EventListener { }); } - private void renderGadgetPanel(MDashboardContent dc, Panel panel) throws Exception { - Panelchildren content = new Panelchildren(); - panel.appendChild(content); - boolean panelEmpty = true; - panelEmpty = !render(content, dc, dashboardRunnable); - if (panelEmpty) { - panel.detach(); - panel.setAttribute(PANEL_EMPTY_ATTRIBUTE, Boolean.TRUE); - } + /** + * Render gadget panel in background thread + * @param spt + * @param dashboardContent + * @param panel + * @param appDesktop + * @param contextPath + * @param panelChildren + * @param zulComponent + * @throws Exception + */ + private void asyncRenderGadgetPanel(ServerPushTemplate spt, MDashboardContent dashboardContent, Panel panel, IDesktop appDesktop, String contextPath, + Panelchildren panelChildren, Component zulComponent) throws Exception { + List components = new ArrayList<>(); + asyncRenderComponents(dashboardContent, dashboardRunnable, appDesktop, contextPath, panelChildren, components, zulComponent); + if (components.size() > 0) { + for(Component c : components) { + if (c.getParent() != panelChildren) { + spt.executeAsync(() -> panelChildren.appendChild(c)); + } + if (c instanceof DashboardPanel) { + DashboardPanel dpanel = (DashboardPanel) c; + if (dpanel.isLazy()) { + try { + dpanel.refresh(spt); + } catch (Exception e) { + logger.log(Level.SEVERE, e.getMessage(), e); + } + } + } + } + spt.executeAsync(() -> { + if (panelChildren.getFirstChild() != null && panelChildren.getFirstChild() instanceof BusyDialog) + panelChildren.getFirstChild().detach(); + }); + } else { + spt.executeAsync(() -> { + panel.detach(); + panel.setAttribute(PANEL_EMPTY_ATTRIBUTE, Boolean.TRUE); + }); + } } - + private void startDashboardRunnable(Component parent) { - dashboardRunnable.refreshDashboard(false); // default Update every one minutes int interval = MSysConfig.getIntValue(MSysConfig.ZK_DASHBOARD_REFRESH_INTERVAL, 60000); dashboardTimer = new Timer(); @@ -442,7 +506,7 @@ public class DashboardController implements EventListener { int AD_User_ID = Env.getAD_User_ID(Env.getCtx()); int AD_Role_ID = Env.getAD_Role_ID(Env.getCtx()); - MDashboardPreference[] dps = MDashboardPreference.getForSession(AD_User_ID, AD_Role_ID, false); + MDashboardPreference[] dps = MDashboardPreference.getForSession(AD_User_ID, AD_Role_ID, false); MDashboardContent [] dcs = MDashboardContentAccess.get(Env.getCtx(), AD_Role_ID, AD_User_ID, null); if(dps.length == 0){ @@ -478,12 +542,12 @@ public class DashboardController implements EventListener { int lineNo = dp.getLine().intValue(); int flexGrow = (flexGrow = dp.getFlexGrow()) > 0 ? flexGrow : DEFAULT_FLEX_GROW; - if(dashboardLineLayout == null || currentLineNo != lineNo) + if(dashboardLineLayout == null || currentLineNo != lineNo) { dashboardLineLayout = new Hlayout(); - dashboardLineLayout.setAttribute(LINE_ATTRIBUTE, lineNo); - dashboardLineLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); - dashboardLineLayout.setAttribute(IS_ADDITIONAL_ROW_ATTRIBUTE, false); + dashboardLineLayout.setAttribute(LINE_ATTRIBUTE, lineNo); + dashboardLineLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); + dashboardLineLayout.setAttribute(IS_ADDITIONAL_ROW_ATTRIBUTE, false); dashboardLineLayout.setSclass("dashboard-row"); Anchorchildren dashboardLine = new Anchorchildren(); dashboardLine.setAnchor(width + "%"); @@ -503,24 +567,53 @@ public class DashboardController implements EventListener { if (update) { panel = findPanel(dp.getPA_DashboardContent_ID(), dp.getPA_DashboardPreference_ID()); } else { - panel = newGadgetPanel(dp, dc); - panel.setAttribute(FLEX_GROW_ATTRIBUTE, String.valueOf(flexGrow)); + panel = newGadgetPanel(dp, dc); + panel.setAttribute(FLEX_GROW_ATTRIBUTE, String.valueOf(flexGrow)); ZKUpdateUtil.setHflex(panel, String.valueOf(flexGrow)); } - if (panel != null && panel.getAttribute(PANEL_EMPTY_ATTRIBUTE) == null) { + if (panel != null && panel.getAttribute(PANEL_EMPTY_ATTRIBUTE) == null) { dashboardLineLayout.appendChild(panel); } if (!update) { - renderGadgetPanel(dc, panel); + final Panel fp = panel; + ServerPushTemplate spt = new ServerPushTemplate(dashboardLayout.getDesktop()); + IDesktop appDesktop = SessionManager.getAppDesktop(); + String contextPath = Executions.getCurrent().getContextPath(); + Panelchildren panelChildren = new Panelchildren(); + fp.appendChild(panelChildren); + BusyDialog busyDialog = new BusyDialog(); + busyDialog.setShadow(false); + panelChildren.appendChild(busyDialog); + //must create zulfile component in foreground UI thread + Component zComponent = null; + if (!Util.isEmpty(dc.getZulFilePath(), true)) { + try { + zComponent = Extensions.getDashboardGadget(dc.getZulFilePath(), panelChildren, dc); + } catch (Exception e) { + throw new AdempiereException(e); + } + } + final Component zulComponent = zComponent; + ContextRunnable cr = new ContextRunnable() { + @Override + protected void doRun() { + try { + asyncRenderGadgetPanel(spt, dc, fp, appDesktop, contextPath, panelChildren, zulComponent); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + Adempiere.getThreadPoolExecutor().submit(cr); } } if (dps.length == 0) { dashboardLineLayout = new Hlayout(); - dashboardLineLayout.setAttribute(LINE_ATTRIBUTE, "0"); - dashboardLineLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); - dashboardLineLayout.setAttribute(IS_ADDITIONAL_ROW_ATTRIBUTE, true); + dashboardLineLayout.setAttribute(LINE_ATTRIBUTE, "0"); + dashboardLineLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); + dashboardLineLayout.setAttribute(IS_ADDITIONAL_ROW_ATTRIBUTE, true); dashboardLineLayout.setSclass("dashboard-row"); Anchorchildren dashboardColumn = new Anchorchildren(); dashboardColumn.setAnchor((width-5) + "%" + " 100%"); @@ -539,9 +632,9 @@ public class DashboardController implements EventListener { // additional row dashboardLineLayout = new Hlayout(); ZKUpdateUtil.setWidth(dashboardLineLayout, "100%"); - dashboardLineLayout.setAttribute(LINE_ATTRIBUTE, currentLineNo + 1); - dashboardLineLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); - dashboardLineLayout.setAttribute(IS_ADDITIONAL_ROW_ATTRIBUTE, true); + dashboardLineLayout.setAttribute(LINE_ATTRIBUTE, currentLineNo + 1); + dashboardLineLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); + dashboardLineLayout.setAttribute(IS_ADDITIONAL_ROW_ATTRIBUTE, true); dashboardLineLayout.setSclass("dashboard-row"); Anchorchildren dashboardLine = new Anchorchildren(); dashboardLine.setAnchor(width + "% 1%"); @@ -564,9 +657,9 @@ public class DashboardController implements EventListener { } // - if (!update && !dashboardRunnable.isEmpty()) + if (!update) { - startDashboardRunnable(parent); + startDashboardRunnable(parent); } } @@ -585,18 +678,20 @@ public class DashboardController implements EventListener { } /** - * - * @param content - * @param dc + * Create gadget components in background thread + * @param dashboardContent * @param dashboardRunnable - * @return + * @param appDesktop + * @param contextPath + * @param parentComponent + * @param components + * @param zulComponent * @throws Exception */ - public boolean render(Component content, MDashboardContent dc, DashboardRunnable dashboardRunnable) throws Exception { - boolean empty = true; - + private void asyncRenderComponents(MDashboardContent dashboardContent, DashboardRunnable dashboardRunnable, IDesktop appDesktop, String contextPath, + HtmlBasedComponent parentComponent, List components, Component zulComponent) throws Exception { // HTML content - String htmlContent = dc.get_ID() > 0 ? dc.get_Translation(MDashboardContent.COLUMNNAME_HTML) : null; + String htmlContent = dashboardContent.get_ID() > 0 ? dashboardContent.get_Translation(MDashboardContent.COLUMNNAME_HTML) : null; if(htmlContent != null) { StringBuilder result = new StringBuilder(""); @@ -614,8 +709,7 @@ public class DashboardController implements EventListener { result.append(""); } catch (Exception e1) { logger.log(Level.SEVERE, e1.getLocalizedMessage(), e1); - } - finally{ + } finally{ if (bufferedReader != null) { try { bufferedReader.close(); @@ -629,56 +723,58 @@ public class DashboardController implements EventListener { Html html = new Html(); html.setContent(result.toString()); - content.appendChild(html); - empty = false; + components.add(html); } // Window - int AD_Window_ID = dc.getAD_Window_ID(); + int AD_Window_ID = dashboardContent.getAD_Window_ID(); if(AD_Window_ID > 0) { - int AD_Menu_ID = dc.getAD_Menu_ID(); + int AD_Menu_ID = dashboardContent.getAD_Menu_ID(); Div div = new Div(); ToolBarButton btn = new ToolBarButton(String.valueOf(AD_Menu_ID)); - I_AD_Menu menu = dc.getAD_Menu(); + I_AD_Menu menu = dashboardContent.getAD_Menu(); btn.setLabel(menu.getName()); btn.setAttribute("AD_Menu_ID", AD_Menu_ID); btn.addEventListener(Events.ON_CLICK, this); div.appendChild(btn); - content.appendChild(div); - empty = false; + components.add(div); } //Report & Process - int AD_Process_ID = dc.getAD_Process_ID(); + int AD_Process_ID = dashboardContent.getAD_Process_ID(); if(AD_Process_ID > 0) { String sql = "SELECT AD_MENU_ID FROM AD_MENU WHERE AD_Process_ID=?"; - int AD_Menu_ID = DB.getSQLValue(null, sql, AD_Process_ID); + int AD_Menu_ID = DB.getSQLValueEx(null, sql, AD_Process_ID); ToolBarButton btn = new ToolBarButton(); MMenu menu = new MMenu(Env.getCtx(), AD_Menu_ID, null); btn.setAttribute("AD_Menu_ID", AD_Menu_ID); btn.addEventListener(Events.ON_CLICK, this); - empty = false; - if (dc.isEmbedReportContent()) + if (dashboardContent.isEmbedReportContent()) { - String processParameters = dc.getProcessParameters(); + String processParameters = dashboardContent.getProcessParameters(); + Div layout = new Div(); + layout.setHeight("100%"); + layout.setStyle("display: flex;flex-direction: column;"); + components.add(layout); Iframe iframe = new Iframe(); iframe.setSclass("dashboard-report-iframe"); - content.appendChild(iframe); - iframe.setContent(generateReport(AD_Process_ID, dc.getAD_PrintFormat_ID(), processParameters)); + iframe.setStyle("flex-grow: 1;"); + layout.appendChild(iframe); + iframe.setContent(generateReport(AD_Process_ID, dashboardContent.getAD_PrintFormat_ID(), processParameters, appDesktop, contextPath)); Toolbar toolbar = new Toolbar(); - content.appendChild(toolbar); + layout.appendChild(toolbar); btn.setLabel(Msg.getMsg(Env.getCtx(), "OpenRunDialog")); toolbar.appendChild(btn); btn = new ToolBarButton(); btn.setAttribute("AD_Process_ID", AD_Process_ID); btn.setAttribute("ProcessParameters", processParameters); - btn.setAttribute("AD_PrintFormat_ID", dc.getAD_PrintFormat_ID()); + btn.setAttribute("AD_PrintFormat_ID", dashboardContent.getAD_PrintFormat_ID()); btn.addEventListener(Events.ON_CLICK, this); btn.setLabel(Msg.getMsg(Env.getCtx(), "ViewReportInNewTab")); toolbar.appendChild(new Separator("vertical")); @@ -692,32 +788,30 @@ public class DashboardController implements EventListener { else btn.setImage(ThemeManager.getThemeResource("images/Refresh16.png")); - btn.addEventListener(Events.ON_CLICK, e -> iframe.setContent(generateReport(AD_Process_ID, dc.getAD_PrintFormat_ID(), processParameters))); - toolbar.appendChild(btn); + btn.addEventListener(Events.ON_CLICK, e -> iframe.setContent(generateReport(AD_Process_ID, dashboardContent.getAD_PrintFormat_ID(), processParameters, appDesktop, contextPath))); + toolbar.appendChild(btn); } else { btn.setLabel(menu.getName()); - content.appendChild(btn); + components.add(btn); } } // Goal - int PA_Goal_ID = dc.getPA_Goal_ID(); + int PA_Goal_ID = dashboardContent.getPA_Goal_ID(); if(PA_Goal_ID > 0) { - - String goalDisplay = dc.getGoalDisplay(); + String goalDisplay = dashboardContent.getGoalDisplay(); MGoal goal = new MGoal(Env.getCtx(), PA_Goal_ID, null); if(MDashboardContent.GOALDISPLAY_GaugeIndicator.equals(goalDisplay)) { WPerformanceIndicator.Options options = new WPerformanceIndicator.Options(); options.colorMap = new HashMap(); options.colorMap.put(WPerformanceIndicator.DIAL_BACKGROUND, new Color(224, 224, 224, 1)); - WPAWidget paWidget = new WPAWidget(goal, options, dc.isShowTitle()); - ((HtmlBasedComponent)content).setSclass("performance-gadget"); - content.appendChild(paWidget); - } - else { + WPAWidget paWidget = new WPAWidget(goal, options, dashboardContent.isShowTitle()); + components.add(paWidget); + LayoutUtils.addSclass("performance-gadget", parentComponent); + } else { //link to open performance detail Div div = new Div(); Toolbarbutton link = new Toolbarbutton(); @@ -734,57 +828,46 @@ public class DashboardController implements EventListener { } }); div.appendChild(link); - content.appendChild(div); + components.add(div); WGraph graph = new WGraph(goal, 55, false, true, !(MDashboardContent.GOALDISPLAY_Chart.equals(goalDisplay)), MDashboardContent.GOALDISPLAY_Chart.equals(goalDisplay)); - content.appendChild(graph); + components.add(graph); } - empty = false; } - // ZUL file url - String url = dc.getZulFilePath(); - if(url != null) + // Component created from ZUL file url + if(zulComponent != null) { try { - - Component component = Extensions.getDashboardGadget(url, content, dc); - if(component != null) - { - if (component instanceof Include) - component = component.getFirstChild(); - - if (component instanceof DashboardPanel) - { - DashboardPanel dashboardPanel = (DashboardPanel) component; - if (!dashboardPanel.getChildren().isEmpty()) { - content.appendChild(dashboardPanel); - addDashboardPanel(dashboardPanel); - empty = false; - } + if (zulComponent instanceof Include) + zulComponent = zulComponent.getFirstChild(); + + if (zulComponent instanceof DashboardPanel) + { + DashboardPanel dashboardPanel = (DashboardPanel) zulComponent; + if (!dashboardPanel.getChildren().isEmpty()) { + components.add(dashboardPanel); + addDashboardPanel(dashboardPanel); } - else - { - content.appendChild(component); - empty = false; - } - } + } + else + { + components.add(zulComponent); + } } catch (Exception e) { - logger.log(Level.WARNING, "Failed to create components. zul="+url, e); throw new AdempiereException(e); } } - + //chart - final int AD_Chart_ID = dc.getAD_Chart_ID(); + final int AD_Chart_ID = dashboardContent.getAD_Chart_ID(); if (AD_Chart_ID > 0) { final Div chartPanel = new Div(); chartPanel.setSclass("chart-gadget"); final MChart chartModel = new MChart(Env.getCtx(), AD_Chart_ID, null); - content.appendChild(chartPanel); - empty = false; + components.add(chartPanel); chartPanel.addEventListener(Events.ON_AFTER_SIZE, new EventListener() { @Override public void onEvent(AfterSizeEvent event) throws Exception { @@ -798,13 +881,13 @@ public class DashboardController implements EventListener { chartPanel.getChildren().clear(); ChartModel model = new ChartModel(); model.chart = chartModel; - renderChart(chartPanel, width, height, model, dc.isShowTitle()); + renderChart(chartPanel, width, height, model, dashboardContent.isShowTitle()); } }); } // Status Line - final int AD_StatusLine_ID = dc.getAD_StatusLine_ID(); + final int AD_StatusLine_ID = dashboardContent.getAD_StatusLine_ID(); if(AD_StatusLine_ID > 0) { MStatusLine sl = new MStatusLine(Env.getCtx(), AD_StatusLine_ID, null); final Html statusLineHtml = new Html(); @@ -812,11 +895,49 @@ public class DashboardController implements EventListener { Div div = new Div(); div.appendChild(statusLineHtml); div.setSclass("statusline-gadget"); - ((HtmlBasedComponent) content.getParent()).setSclass("statusline-wrapper"); - content.appendChild(div); - empty = false; + components.add(div); + LayoutUtils.addSclass("statusline-wrapper", ((HtmlBasedComponent) parentComponent.getParent())); } - + } + + /** + * Synchronous render of gadget content in foreground ui thread + * @param content must be an instanceof {@link HtmlBasedComponent} + * @param dashboardContent + * @param dashboardRunnable + * @return true if gadget dashboard is not empty + * @throws Exception + */ + public boolean render(Component content, MDashboardContent dashboardContent, DashboardRunnable dashboardRunnable) throws Exception { + List components = new ArrayList<>(); + Component zulComponent = null; + if (!Util.isEmpty(dashboardContent.getZulFilePath(), true)) { + try { + zulComponent = Extensions.getDashboardGadget(dashboardContent.getZulFilePath(), content, dashboardContent); + } catch (Exception e) { + throw new AdempiereException(e); + } + } + HtmlBasedComponent parentComponent = (HtmlBasedComponent) content; + asyncRenderComponents(dashboardContent, dashboardRunnable, SessionManager.getAppDesktop(), Executions.getCurrent().getContextPath(), parentComponent, components, zulComponent); + boolean empty = components.isEmpty(); + ServerPushTemplate spt = new ServerPushTemplate(content.getDesktop()); + for(Component c : components) { + if (c.getParent() != parentComponent) { + parentComponent.appendChild(c); + } + if (c instanceof DashboardPanel) { + DashboardPanel dpanel = (DashboardPanel) c; + if (dpanel.isLazy()) { + try { + dpanel.refresh(spt); + } catch (Exception e) { + logger.log(Level.SEVERE, e.getMessage(), e); + } + } + } + } + return !empty; } @@ -866,8 +987,8 @@ public class DashboardController implements EventListener { } panel.setSclass("dashboard-widget"); //following 2 line needed for restore to size the panel correctly - ZKUpdateUtil.setHflex(panel, (String)panel.getAttribute(FLEX_GROW_ATTRIBUTE)); - ZKUpdateUtil.setHeight(panel, "100%"); + ZKUpdateUtil.setHflex(panel, (String)panel.getAttribute(FLEX_GROW_ATTRIBUTE)); + ZKUpdateUtil.setHeight(panel, "100%"); } } else if(eventName.equals(Events.ON_CLICK)) @@ -964,7 +1085,7 @@ public class DashboardController implements EventListener { if(comp instanceof Panel) { Panel panel = (Panel) comp; - Object value = panel.getAttribute(MDashboardPreference.COLUMNNAME_PA_DashboardPreference_ID); + Object value = panel.getAttribute(MDashboardPreference.COLUMNNAME_PA_DashboardPreference_ID); if (value != null) { int PA_DashboardPreference_ID = Integer.parseInt(value.toString()); @@ -1064,7 +1185,7 @@ public class DashboardController implements EventListener { if (child instanceof Panel) { Panel panel = (Panel) child; - value = panel.getAttribute(MDashboardPreference.COLUMNNAME_PA_DashboardPreference_ID); + value = panel.getAttribute(MDashboardPreference.COLUMNNAME_PA_DashboardPreference_ID); if (value != null) { ++counter; @@ -1100,9 +1221,9 @@ public class DashboardController implements EventListener { // additional column Vlayout dashboardColumnLayout = new Vlayout(); - dashboardColumnLayout.setAttribute(COLUMN_NO_ATTRIBUTE, columnNo + 1); - dashboardColumnLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); - dashboardColumnLayout.setAttribute(IS_ADDITIONAL_COLUMN_ATTRIBUTE, true); + dashboardColumnLayout.setAttribute(COLUMN_NO_ATTRIBUTE, columnNo + 1); + dashboardColumnLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); + dashboardColumnLayout.setAttribute(IS_ADDITIONAL_COLUMN_ATTRIBUTE, true); Anchorchildren dashboardColumn = new Anchorchildren(); dashboardColumn.setAnchor(extraWidth + "% 100%"); if (!ClientInfo.isMobile()) { @@ -1149,7 +1270,7 @@ public class DashboardController implements EventListener { if (child instanceof Panel) { Panel panel = (Panel) child; - value = panel.getAttribute(MDashboardPreference.COLUMNNAME_PA_DashboardPreference_ID); + value = panel.getAttribute(MDashboardPreference.COLUMNNAME_PA_DashboardPreference_ID); if (value != null) { int PA_DashboardPreference_ID = Integer.parseInt(value.toString()); @@ -1197,9 +1318,9 @@ public class DashboardController implements EventListener { // additional row Hlayout dashboardLineLayout = new Hlayout(); ZKUpdateUtil.setWidth(dashboardLineLayout, "100%"); - dashboardLineLayout.setAttribute(LINE_ATTRIBUTE, lineNo + 1); - dashboardLineLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); - dashboardLineLayout.setAttribute(IS_ADDITIONAL_ROW_ATTRIBUTE, true); + dashboardLineLayout.setAttribute(LINE_ATTRIBUTE, lineNo + 1); + dashboardLineLayout.setAttribute(IS_SHOW_IN_DASHBOARD_ATTRIBUTE, isShowInDashboard); + dashboardLineLayout.setAttribute(IS_ADDITIONAL_ROW_ATTRIBUTE, true); dashboardLineLayout.setSclass("dashboard-row"); Anchorchildren dashboardLine = new Anchorchildren(); dashboardLine.setAnchor(width + "% 1%"); @@ -1315,12 +1436,12 @@ public class DashboardController implements EventListener { } - private AMedia generateReport(int AD_Process_ID, int AD_PrintFormat_ID, String parameters) throws Exception { + private AMedia generateReport(int AD_Process_ID, int AD_PrintFormat_ID, String parameters, IDesktop appDesktop, String contextPath) throws Exception { ReportEngine re = runReport(AD_Process_ID, AD_PrintFormat_ID, parameters); File file = FileUtil.createTempFile(re.getName(), ".html"); - re.createHTML(file, false, AEnv.getLanguage(Env.getCtx()), new HTMLExtension(Executions.getCurrent().getContextPath(), "rp", - SessionManager.getAppDesktop().getComponent().getUuid())); + re.createHTML(file, false, AEnv.getLanguage(Env.getCtx()), new HTMLExtension(contextPath, "rp", + appDesktop.getComponent().getUuid())); return new AMedia(re.getName(), "html", "text/html", file, false); } @@ -1448,8 +1569,8 @@ public class DashboardController implements EventListener { ts = (Timestamp)value; else ts = Timestamp.valueOf(value.toString()); - SimpleDateFormat dateFormat = DisplayType.getDateFormat(iPara.getDisplayType()); - String info = dateFormat.format(ts); + SimpleDateFormat dateFormat = DisplayType.getDateFormat(iPara.getDisplayType()); + String info = dateFormat.format(ts); if (isTo) { iPara.setP_Date_To(ts); iPara.setInfo_To(info); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WDashboardContentEditor.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WDashboardContentEditor.java index ba87797d53..2dc29c4007 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WDashboardContentEditor.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WDashboardContentEditor.java @@ -1,6 +1,27 @@ -/** - * - */ +/*********************************************************************** + * This file is part of iDempiere ERP Open Source * + * http://www.idempiere.org * + * * + * Copyright (C) Contributors * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * 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., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301, USA. * + * * + * Contributors: * + * - hengsin * + **********************************************************************/ package org.adempiere.webui.editor; import java.util.logging.Level; @@ -139,8 +160,6 @@ public class WDashboardContentEditor extends WEditor { DashboardRunnable dashboardRunnable = new DashboardRunnable(panel.getDesktop()); dashboardController.render(div, content, dashboardRunnable); - if (!dashboardRunnable.isEmpty()) - dashboardRunnable.refreshDashboard(false); pc.appendChild(div); } diff --git a/org.adempiere.ui.zk/WEB-INF/src/web/theme/default/css/fragment/gadget.css.dsp b/org.adempiere.ui.zk/WEB-INF/src/web/theme/default/css/fragment/gadget.css.dsp index 93a40775f6..d56afddb92 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/web/theme/default/css/fragment/gadget.css.dsp +++ b/org.adempiere.ui.zk/WEB-INF/src/web/theme/default/css/fragment/gadget.css.dsp @@ -17,8 +17,13 @@ width: calc(100% - 10px); } +.dashboard-widget.z-panel { + display: flex; + flex-direction: column; + justify-content: stretch; +} .dashboard-widget > .z-panel-body { - height: 100%; + flex-grow: 1; } .statusline-wrapper { @@ -95,7 +100,6 @@ border: 1px solid lightgray; margin:auto; width: 99%; - height: 90%; } .favourites-box {