/******************************************************************************
* Copyright (C) 2008 Low Heng Sin *
* Copyright (C) 2008 Idalica Corporation *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program is distributed in the hope *
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.adempiere.webui.desktop;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.net.URL;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.logging.Level;
import org.adempiere.webui.apps.ProcessDialog;
import org.adempiere.webui.apps.graph.WGraph;
import org.adempiere.webui.component.Accordion;
import org.adempiere.webui.component.Tabpanel;
import org.adempiere.webui.component.ToolBarButton;
import org.adempiere.webui.dashboard.DPActivities;
import org.adempiere.webui.dashboard.DPFavourites;
import org.adempiere.webui.dashboard.DashboardPanel;
import org.adempiere.webui.dashboard.DashboardRunnable;
import org.adempiere.webui.event.MenuListener;
import org.adempiere.webui.panel.ADForm;
import org.adempiere.webui.panel.HeaderPanel;
import org.adempiere.webui.panel.SidePanel;
import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.util.IServerPushCallback;
import org.adempiere.webui.util.ServerPushTemplate;
import org.adempiere.webui.util.UserPreference;
import org.adempiere.webui.window.ADWindow;
import org.compiere.model.MGoal;
import org.compiere.model.MMenu;
import org.compiere.model.X_AD_Menu;
import org.compiere.model.X_PA_DashboardContent;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.zkoss.zk.au.out.AuScript;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.DropEvent;
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.zkex.zul.Borderlayout;
import org.zkoss.zkex.zul.Center;
import org.zkoss.zkex.zul.North;
import org.zkoss.zkex.zul.West;
import org.zkoss.zkmax.zul.Portalchildren;
import org.zkoss.zkmax.zul.Portallayout;
import org.zkoss.zul.Div;
import org.zkoss.zul.Html;
import org.zkoss.zul.Panel;
import org.zkoss.zul.Panelchildren;
import org.zkoss.zul.Treeitem;
import org.zkoss.zul.Treerow;
/**
* @author hengsin
*/
public class NavBarDesktop extends TabbedDesktop implements MenuListener, Serializable, EventListener, IServerPushCallback
{
private static final long serialVersionUID = 4721048271543882164L;
private static final String FAVOURITES_PATH = "/zul/favourites.zul";
private static final String ACTIVITIES_PATH = "/zul/activities.zul";
private static final String VIEWS_PATH = "/zul/views.zul";
private static final CLogger logger = CLogger.getCLogger(DefaultDesktop.class);
private Center windowArea;
private Borderlayout layout;
private Thread dashboardThread;
private DashboardRunnable dashboardRunnable;
private Accordion navigationPanel;
private West leftRegion;
private DPFavourites favPanel;
private int noOfNotice;
private int noOfRequest;
private int noOfWorkflow;
public NavBarDesktop()
{
super();
}
protected Component doCreatePart(Component parent)
{
SidePanel pnlSide = new SidePanel();
HeaderPanel pnlHead = new HeaderPanel();
pnlSide.getMenuPanel().addMenuListener(this);
layout = new Borderlayout();
if (parent != null)
{
layout.setParent(parent);
layout.setWidth("100%");
layout.setHeight("100%");
layout.setStyle("position: absolute");
}
else
layout.setPage(page);
dashboardRunnable = new DashboardRunnable(layout.getDesktop(), this);
North n = new North();
layout.appendChild(n);
n.setCollapsible(false);
pnlHead.setParent(n);
leftRegion = new West();
layout.appendChild(leftRegion);
leftRegion.setWidth("300px");
leftRegion.setCollapsible(true);
leftRegion.setSplittable(true);
leftRegion.setTitle("Navigation");
leftRegion.setFlex(true);
leftRegion.addEventListener(Events.ON_OPEN, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
OpenEvent oe = (OpenEvent) event;
UserPreference pref = SessionManager.getSessionApplication().getUserPreference();
pref.setProperty(UserPreference.P_MENU_COLLAPSED, !oe.isOpen());
pref.savePreference();
}
});
UserPreference pref = SessionManager.getSessionApplication().getUserPreference();
boolean menuCollapsed= pref.isPropertyBool(UserPreference.P_MENU_COLLAPSED);
leftRegion.setOpen(!menuCollapsed);
navigationPanel = new Accordion();
navigationPanel.setParent(leftRegion);
navigationPanel.setWidth("100%");
navigationPanel.setHeight("100%");
navigationPanel.add(pnlSide, "Application Menu");
Div div = new Div();
favPanel = (DPFavourites) Executions.createComponents(FAVOURITES_PATH, div, null);
navigationPanel.add(div, "Favourites");
//setup drag and drop for favourites
div = navigationPanel.getHeader(1);
div.setDroppable(DPFavourites.FAVOURITE_DROPPABLE);
div.addEventListener(Events.ON_DROP, this);
div = new Div();
Component component = Executions.createComponents(ACTIVITIES_PATH, div, null);
if (component instanceof DashboardPanel)
{
DashboardPanel dashboardPanel = (DashboardPanel) component;
dashboardRunnable.add(dashboardPanel);
}
navigationPanel.add(div, "Activities");
div = new Div();
Executions.createComponents(VIEWS_PATH, div, null);
navigationPanel.add(div, Msg.getMsg(Env.getCtx(), "View").replaceAll("&", ""));
navigationPanel.setSelectedIndex(0);
windowArea = new Center();
windowArea.setParent(layout);
windowArea.setFlex(true);
windowContainer.createPart(windowArea);
createHomeTab();
return layout;
}
private void createHomeTab()
{
Tabpanel homeTab = new Tabpanel();
windowContainer.addWindow(homeTab, Msg.getMsg(Env.getCtx(), "Home").replaceAll("&", ""), false);
Portallayout portalLayout = new Portallayout();
portalLayout.setWidth("100%");
portalLayout.setHeight("100%");
portalLayout.setStyle("position: absolute; overflow: auto");
homeTab.appendChild(portalLayout);
// Dashboard content
Portalchildren portalchildren = null;
int currentColumnNo = 0;
String sql = "SELECT COUNT(DISTINCT COLUMNNO) "
+ "FROM PA_DASHBOARDCONTENT "
+ "WHERE (AD_CLIENT_ID=0 OR AD_CLIENT_ID=?) AND ISACTIVE='Y'";
int noOfCols = DB.getSQLValue(null, sql,
Env.getAD_Client_ID(Env.getCtx()));
int width = noOfCols <= 0 ? 100 : 100/noOfCols;
sql = "SELECT x.*, m.AD_MENU_ID "
+ "FROM PA_DASHBOARDCONTENT x "
+ "LEFT OUTER JOIN AD_MENU m ON x.AD_WINDOW_ID=m.AD_WINDOW_ID "
+ "WHERE (x.AD_CLIENT_ID=0 OR x.AD_CLIENT_ID=?) AND x.ISACTIVE='Y' "
+ "AND x.zulfilepath not in (?, ?, ?) "
+ "ORDER BY x.COLUMNNO, x.AD_CLIENT_ID, x.LINE ";
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(sql, null);
pstmt.setInt(1, Env.getAD_Client_ID(Env.getCtx()));
pstmt.setString(2, ACTIVITIES_PATH);
pstmt.setString(3, FAVOURITES_PATH);
pstmt.setString(4, VIEWS_PATH);
rs = pstmt.executeQuery();
while (rs.next())
{
int columnNo = rs.getInt(X_PA_DashboardContent.COLUMNNAME_ColumnNo);
if(portalchildren == null || currentColumnNo != columnNo)
{
portalchildren = new Portalchildren();
portalLayout.appendChild(portalchildren);
portalchildren.setWidth(width + "%");
portalchildren.setStyle("padding: 5px");
currentColumnNo = columnNo;
}
Panel panel = new Panel();
panel.setStyle("margin-bottom:10px");
panel.setTitle(rs.getString(X_PA_DashboardContent.COLUMNNAME_Name));
String description = rs.getString(X_PA_DashboardContent.COLUMNNAME_Description);
if(description != null)
panel.setTooltiptext(description);
String collapsible = rs.getString(X_PA_DashboardContent.COLUMNNAME_IsCollapsible);
panel.setCollapsible(collapsible.equals("Y"));
panel.setBorder("normal");
portalchildren.appendChild(panel);
Panelchildren content = new Panelchildren();
panel.appendChild(content);
boolean panelEmpty = true;
// HTML content
String htmlContent = rs.getString(X_PA_DashboardContent.COLUMNNAME_HTML);
if(htmlContent != null)
{
StringBuffer result = new StringBuffer("<html><head>");
URL url = getClass().getClassLoader().
getResource("org/compiere/images/PAPanel.css");
InputStreamReader ins;
try {
ins = new InputStreamReader(url.openStream());
BufferedReader bufferedReader = new BufferedReader( ins );
String cssLine;
while ((cssLine = bufferedReader.readLine()) != null)
result.append(cssLine + "\n");
} catch (IOException e1) {
logger.log(Level.SEVERE, e1.getLocalizedMessage(), e1);
}
result.append("</head><body><div class=\"content\">\n");
// if(description != null)
// result.append("<h2>" + description + "</h2>\n");
result.append(stripHtml(htmlContent, false) + "<br>\n");
result.append("</div>\n</body>\n</html>\n</html>");
Html html = new Html();
html.setContent(result.toString());
content.appendChild(html);
panelEmpty = false;
}
// Window
int AD_Window_ID = rs.getInt(X_PA_DashboardContent.COLUMNNAME_AD_Window_ID);
if(AD_Window_ID > 0)
{
int AD_Menu_ID = rs.getInt(X_AD_Menu.COLUMNNAME_AD_Menu_ID);
ToolBarButton btn = new ToolBarButton(String.valueOf(AD_Menu_ID));
MMenu menu = new MMenu(Env.getCtx(), AD_Menu_ID, null);
btn.setLabel(menu.getName());
btn.addEventListener(Events.ON_CLICK, this);
content.appendChild(btn);
panelEmpty = false;
}
// Goal
int PA_Goal_ID = rs.getInt(X_PA_DashboardContent.COLUMNNAME_PA_Goal_ID);
if(PA_Goal_ID > 0)
{
String goalDisplay = rs.getString(X_PA_DashboardContent.COLUMNNAME_GoalDisplay);
MGoal goal = new MGoal(Env.getCtx(), PA_Goal_ID, null);
WGraph graph = new WGraph(goal, 55, false, true,
!(X_PA_DashboardContent.GOALDISPLAY_Chart.equals(goalDisplay)),
X_PA_DashboardContent.GOALDISPLAY_Chart.equals(goalDisplay));
content.appendChild(graph);
panelEmpty = false;
}
// ZUL file url
String url = rs.getString(X_PA_DashboardContent.COLUMNNAME_ZulFilePath);
if(url != null)
{
try {
Component component = Executions.createComponents(url, content, null);
if(component != null)
{
if (component instanceof DashboardPanel)
{
DashboardPanel dashboardPanel = (DashboardPanel) component;
if (!dashboardPanel.getChildren().isEmpty()) {
content.appendChild(dashboardPanel);
dashboardRunnable.add(dashboardPanel);
panelEmpty = false;
}
}
else
{
content.appendChild(component);
panelEmpty = false;
}
}
} catch (Exception e) {
logger.log(Level.WARNING, "Failed to create components. zul="+url, e);
}
}
if (panelEmpty)
panel.detach();
}
} catch(Exception e) {
logger.log(Level.WARNING, "Failed to create dashboard content", e);
} finally {
DB.close(rs, pstmt);
}
//
//register as 0
registerWindow(homeTab);
if (!portalLayout.getDesktop().isServerPushEnabled())
portalLayout.getDesktop().enableServerPush(true);
dashboardRunnable.refreshDashboard();
dashboardThread = new Thread(dashboardRunnable, "UpdateInfo");
dashboardThread.setDaemon(true);
dashboardThread.start();
}
public void onEvent(Event event)
{
Component comp = event.getTarget();
String eventName = event.getName();
if(eventName.equals(Events.ON_CLICK))
{
if(comp instanceof ToolBarButton)
{
ToolBarButton btn = (ToolBarButton) comp;
int menuId = 0;
try
{
menuId = Integer.valueOf(btn.getName());
}
catch (Exception e) {
}
if(menuId > 0) onMenuSelected(menuId);
}
}
else if(eventName.equals(Events.ON_DROP))
{
DropEvent de = (DropEvent) event;
Component dragged = de.getDragged();
if(dragged instanceof Treerow)
{
Treerow treerow = (Treerow) dragged;
Treeitem treeitem = (Treeitem) treerow.getParent();
favPanel.addItem(treeitem);
}
}
}
public void onServerPush(ServerPushTemplate template)
{
noOfNotice = DPActivities.getNoticeCount();
noOfRequest = DPActivities.getRequestCount();
noOfWorkflow = DPActivities.getWorkflowCount();
template.execute(this);
}
/**
*
* @param page
*/
public void setPage(Page page) {
if (this.page != page) {
layout.setPage(page);
this.page = page;
}
if (dashboardThread != null && dashboardThread.isAlive()) {
dashboardRunnable.stop();
dashboardThread.interrupt();
DashboardRunnable tmp = dashboardRunnable;
dashboardRunnable = new DashboardRunnable(tmp, layout.getDesktop(), this);
dashboardThread = new Thread(dashboardRunnable, "UpdateInfo");
dashboardThread.setDaemon(true);
dashboardThread.start();
}
}
/**
* Get the root component
* @return Component
*/
public Component getComponent() {
return layout;
}
public void logout() {
if (dashboardThread != null && dashboardThread.isAlive()) {
dashboardRunnable.stop();
dashboardThread.interrupt();
}
}
public void updateUI() {
int total = noOfNotice + noOfRequest + noOfWorkflow;
navigationPanel.setLabel(2, "Activities (" + total + ")");
navigationPanel.setTooltiptext(2, Msg.translate(Env.getCtx(), "AD_Note_ID") + " : " + noOfNotice
+ ", " + Msg.translate(Env.getCtx(), "R_Request_ID") + " : " + noOfRequest
+ ", " + Msg.getMsg (Env.getCtx(), "WorkflowActivities") + " : " + noOfWorkflow);
}
private void autoHideMenu() {
if (layout.getWest().isCollapsible() && !layout.getWest().isOpen())
{
//using undocumented js api, need to be retested after every version upgrade
String id = layout.getWest().getUuid() + "!real";
String btn = layout.getWest().getUuid() + "!btn";
String script = "zk.show('" + id + "', false);";
script += "$e('"+id+"')._isSlide = false;";
script += "$e('"+id+"')._lastSize = null;";
script += "$e('"+btn+"').style.display = '';";
AuScript aus = new AuScript(layout.getWest(), script);
Clients.response("autoHideWest", aus);
}
}
@Override
public ADWindow openWindow(int windowId) {
autoHideMenu();
return super.openWindow(windowId);
}
@Override
public ADForm openForm(int formId) {
autoHideMenu();
return super.openForm(formId);
}
@Override
public ProcessDialog openProcessDialog(int processId, boolean soTrx) {
autoHideMenu();
return super.openProcessDialog(processId, soTrx);
}
@Override
public void openTask(int taskId) {
autoHideMenu();
super.openTask(taskId);
}
@Override
public void openWorkflow(int workflowID) {
autoHideMenu();
super.openWorkflow(workflowID);
}
}