/******************************************************************************
* 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.apps.graph;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.logging.Level;
import org.adempiere.apps.graph.GraphBuilder;
import org.adempiere.apps.graph.GraphColumn;
import org.adempiere.webui.apps.AEnv;
import org.adempiere.webui.editor.WTableDirEditor;
import org.adempiere.webui.event.ValueChangeEvent;
import org.adempiere.webui.event.ValueChangeListener;
import org.compiere.model.MGoal;
import org.compiere.model.MLookup;
import org.compiere.model.MLookupFactory;
import org.compiere.model.MLookupInfo;
import org.compiere.model.MQuery;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.encoders.EncoderUtil;
import org.jfree.chart.encoders.ImageFormat;
import org.jfree.chart.entity.CategoryItemEntity;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.entity.PieSectionEntity;
import org.zkoss.image.AImage;
import org.zkoss.zhtml.A;
import org.zkoss.zhtml.Br;
import org.zkoss.zhtml.Table;
import org.zkoss.zhtml.Td;
import org.zkoss.zhtml.Text;
import org.zkoss.zhtml.Tr;
import org.zkoss.zk.ui.Component;
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.MouseEvent;
import org.zkoss.zkex.zul.Borderlayout;
import org.zkoss.zkex.zul.Center;
import org.zkoss.zkex.zul.East;
import org.zkoss.zul.Area;
import org.zkoss.zul.Div;
import org.zkoss.zul.Imagemap;
import org.zkoss.zul.Panel;
import org.zkoss.zul.Panelchildren;
import org.zkoss.zul.Toolbar;
/**
* Performance Graph
*
* @author hengsin
*/
public class WGraph extends Div implements IdSpace {
/**
*
*/
private static final long serialVersionUID = -975989183542113080L;
private static final String ZOOM_KEY = "queryZoom";
private boolean m_hideTitle;
private Panel panel;
private boolean m_renderTable = false;
private boolean m_renderChart = true;
/** Zero/Zero Coordinate point */
private Point m_point0_0 = null;
/** Logger */
private static CLogger log = CLogger.getCLogger(WGraph.class);
/** Y Axis Target Line Label */
private String m_Y_TargetLabel = null;
/**
* Load Performance Data
*/
ArrayList<GraphColumn> list = new ArrayList<GraphColumn>();
private GraphBuilder builder;
private boolean m_chartSelection;
private int zoomFactor = 0;
/**
* Constructor
*/
public WGraph() {
super();
builder = new GraphBuilder();
panel = new Panel();
} // BarGraph
/**
* Constructor
*
* @param goal
*/
public WGraph(MGoal goal) {
this(goal, 0, false, false, false, true);
}
/**
* Constructor
*
* @param goal
* @param zoom
* @param userSelection
* @param hideTitle
* @param showTable
* @param showChart
*/
public WGraph(MGoal goal, int zoom, boolean chartSelection,
boolean hideTitle, boolean renderTable, boolean renderChart) {
this();
setGoal(goal);
m_chartSelection = chartSelection;
zoomFactor = zoom;
m_hideTitle = hideTitle;
m_renderTable = renderTable;
m_renderChart = renderChart;
loadData();
render();
} // WGraph
/**
* @param goal
*/
public void setGoal(MGoal goal)
{
builder.setMGoal(goal);
builder.setYAxisLabel(goal.getName());
builder.setXAxisLabel(goal.getXAxisText());
}
/**
* @return true if the chart type selection control is available
*/
public boolean isChartSelection() {
return m_chartSelection;
}
/**
* show/hide the chart type selection control
* @param chartSelection
*/
public void setChartSelection(boolean chartSelection) {
m_chartSelection = chartSelection;
}
/**
* render chart and/or table
*/
public void render() {
Borderlayout layout = null;
this.getChildren().clear();
if (m_renderTable && m_renderChart) {
layout = new Borderlayout();
appendChild(layout);
layout.setStyle("height: 100%; width: 100%; position: absolute;");
Center center = new Center();
layout.appendChild(center);
center.appendChild(panel);
} else {
appendChild(panel);
}
if (m_renderChart) {
JFreeChart chart = builder.createChart(builder.getMGoal()
.getChartType());
render(chart);
}
if (m_renderTable) {
if (m_renderChart) {
East east = new East();
layout.appendChild(east);
renderTable(east);
} else {
Panelchildren pc = panel.getPanelchildren();
if (pc == null) {
pc = new Panelchildren();
panel.appendChild(pc);
} else {
pc.getChildren().clear();
}
renderTable(pc);
}
}
}
private void loadData() {
list = builder.loadData();
if (m_renderChart && m_chartSelection) {
Toolbar toolbar = new Toolbar();
panel.appendChild(toolbar);
int AD_Reference_Value_ID = DB.getSQLValue(null,
"SELECT AD_Reference_ID FROM AD_Reference WHERE Name = ?",
"PA_Goal ChartType");
MLookupInfo info = MLookupFactory.getLookup_List(Env
.getLanguage(Env.getCtx()), AD_Reference_Value_ID);
MLookup mLookup = new MLookup(info, 0);
WTableDirEditor editor = new WTableDirEditor("ChartType", false,
false, true, mLookup);
toolbar.appendChild(editor.getComponent());
editor.addValueChangeListener(new ValueChangeListener() {
public void valueChange(ValueChangeEvent evt) {
Object value = evt.getNewValue();
if (value == null || value.toString().trim().length() == 0)
return;
JFreeChart chart = null;
chart = builder.createChart(value.toString());
if (chart != null)
render(chart);
}
});
}
} // loadData
private void render(JFreeChart chart) {
ChartRenderingInfo info = new ChartRenderingInfo();
int width = 560;
int height = 400;
if (zoomFactor > 0) {
width = width * zoomFactor / 100;
height = height * zoomFactor / 100;
}
if (m_hideTitle) {
chart.setTitle("");
}
BufferedImage bi = chart.createBufferedImage(width, height,
BufferedImage.TRANSLUCENT, info);
try {
byte[] bytes = EncoderUtil.encode(bi, ImageFormat.PNG, true);
AImage image = new AImage("", bytes);
Imagemap myImage = new Imagemap();
myImage.setContent(image);
if (panel.getPanelchildren() != null) {
panel.getPanelchildren().getChildren().clear();
panel.getPanelchildren().appendChild(myImage);
} else {
Panelchildren pc = new Panelchildren();
panel.appendChild(pc);
pc.appendChild(myImage);
}
int count = 0;
for (Iterator<?> it = info.getEntityCollection().getEntities()
.iterator(); it.hasNext();) {
ChartEntity entity = (ChartEntity) it.next();
String key = null;
if (entity instanceof CategoryItemEntity) {
Comparable<?> colKey = ((CategoryItemEntity) entity)
.getColumnKey();
if (colKey != null) {
key = colKey.toString();
}
} else if (entity instanceof PieSectionEntity) {
Comparable<?> sectionKey = ((PieSectionEntity) entity)
.getSectionKey();
if (sectionKey != null) {
key = sectionKey.toString();
}
}
if (key == null) {
continue;
}
Area area = new Area();
myImage.appendChild(area);
area.setCoords(entity.getShapeCoords());
area.setShape(entity.getShapeType());
area.setTooltiptext(entity.getToolTipText());
area.setId(count+"_WG_" + key);
count++;
}
myImage.addEventListener(Events.ON_CLICK, new EventListener() {
public void onEvent(Event event) throws Exception {
MouseEvent me = (MouseEvent) event;
String areaId = me.getArea();
if (areaId != null) {
for (int i = 0; i < list.size(); i++) {
String s = "_WG_" + list.get(i).getLabel();
if (areaId.endsWith(s)) {
chartMouseClicked(i);
return;
}
}
}
}
});
} catch (Exception e) {
log.log(Level.SEVERE, "", e);
}
}
/**
* Get Point 0_0
*
* @return point
*/
public Point getPoint0_0() {
return m_point0_0;
} // getPoint0_0
/**
* @return Returns the x_AxisLabel.
*/
public String getX_AxisLabel() {
return builder.getXAxisLabel();
} // getX_AxisLabel
/**
* @param axisLabel
* The x_AxisLabel to set.
*/
public void setX_AxisLabel(String axisLabel) {
builder.setXAxisLabel(axisLabel);
} // setX_AxisLabel
/**
* @return Returns the y_AxisLabel.
*/
public String getY_AxisLabel() {
return builder.getYAxisLabel();
} // getY_AxisLabel
/**
* @param axisLabel
* The y_AxisLabel to set.
*/
public void setY_AxisLabel(String axisLabel) {
builder.setYAxisLabel(axisLabel);
} // setY_AxisLabel
/**
* @return Returns the y_TargetLabel.
*/
public String getY_TargetLabel() {
return m_Y_TargetLabel;
} // getY_TargetLabel
/**
* @param targetLabel
* The y_TargetLabel to set.
*/
public void setY_TargetLabel(String targetLabel, double target) {
m_Y_TargetLabel = targetLabel;
// m_Y_Target = target;
} // setY_TargetLabel
/**
* @return zoom in factor
*/
public int getZoomFactor() {
return zoomFactor;
}
/**
* set zoom in factor
*
* @param zoomFactor
*/
public void setZoomFactor(int zoomFactor) {
this.zoomFactor = zoomFactor;
}
/**
* @return true if the summary table for performance goal is render on screen
*/
public boolean isRenderTable() {
return m_renderTable;
}
/**
* hide/show the summary table for performance goal
* @param mRenderTable
*/
public void setRenderTable(boolean mRenderTable) {
m_renderTable = mRenderTable;
}
/**
* @return true if chart is render on screen
*/
public boolean isRenderChart() {
return m_renderChart;
}
/**
* hide/show chart for performance goal
* @param mRenderChart
*/
public void setRenderChart(boolean mRenderChart) {
m_renderChart = mRenderChart;
}
/**************************************************************************
* Paint Component
*
* @param g
* graphics
*/
public void chartMouseClicked(int index) {
GraphColumn bgc = list.get(index);
if (null == bgc)
return;
MQuery query = bgc.getMQuery(builder.getMGoal());
if (query != null)
AEnv.zoom(query);
else
log.warning("Nothing to zoom to - " + bgc);
}
public void chartMouseMoved(ChartMouseEvent event) {
}
/**
*
* @return GraphColumn[]
*/
public GraphColumn[] getGraphColumnList() {
GraphColumn[] array = new GraphColumn[list.size()];
for (int i = 0; i < list.size(); i++) {
array[i] = list.get(i);
}
return array;
}
private void renderTable(Component parent) {
Div div = new Div();
appendChild(div);
div.setSclass("pa-content");
parent.appendChild(div);
Table table = new Table();
table.setSclass("pa-dataGrid");
div.appendChild(table);
Tr tr = new Tr();
table.appendChild(tr);
Td td = new Td();
td.setSclass("pa-label");
tr.appendChild(td);
Text text = new Text("Target");
td.appendChild(text);
td = new Td();
td.setDynamicProperty("colspan", "2");
td.setSclass("pa-tdcontent");
tr.appendChild(td);
text = new Text(builder.getMGoal().getMeasureTarget().setScale(2,
BigDecimal.ROUND_HALF_UP).toPlainString());
td.appendChild(text);
tr = new Tr();
table.appendChild(tr);
td = new Td();
td.setSclass("pa-label");
tr.appendChild(td);
text = new Text("Actual");
td.appendChild(text);
td = new Td();
td.setDynamicProperty("colspan", "2");
td.setSclass("pa-tdcontent");
tr.appendChild(td);
text = new Text(builder.getMGoal().getMeasureActual().setScale(2,
BigDecimal.ROUND_HALF_UP).toPlainString());
td.appendChild(text);
GraphColumn[] bList = getGraphColumnList();
tr = new Tr();
table.appendChild(tr);
td = new Td();
tr.appendChild(td);
td.setDynamicProperty("rowspan", bList.length);
td.setSclass("pa-label");
td.setDynamicProperty("valign", "top");
text = new Text(builder.getMGoal().getXAxisText());
td.appendChild(text);
for (int k = 0; k < bList.length; k++) {
GraphColumn bgc = bList[k];
if (k > 0) {
tr = new Tr();
table.appendChild(tr);
}
td = new Td();
td.setSclass("pa-tdlabel");
tr.appendChild(td);
text = new Text(bgc.getLabel());
td.appendChild(text);
td = new Td();
td.setSclass("pa-tdvalue");
tr.appendChild(td);
BigDecimal value = new BigDecimal(bgc.getValue());
if (bgc.getMQuery(builder.getMGoal()) != null) {
A a = new A();
a.setSclass("pa-hrefNode");
td.appendChild(a);
a.setId(ZOOM_KEY + k);
a.addEventListener(Events.ON_CLICK, new EventListener() {
public void onEvent(Event event) throws Exception {
Component comp = event.getTarget();
String id = comp.getId();
if (id.startsWith(ZOOM_KEY)) {
String ss = id.substring(ZOOM_KEY.length());
int index = Integer.parseInt(String.valueOf(ss));
GraphColumn[] colList = getGraphColumnList();
if ((index >= 0) && (index < colList.length))
AEnv.zoom(colList[index].getMQuery(builder
.getMGoal()));
}
}
});
a.setDynamicProperty("href", "javascript:;");
text = new Text(value.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
a.appendChild(text);
} else {
text = new Text(value.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
}
}
tr = new Tr();
table.appendChild(tr);
td = new Td();
td.setDynamicProperty("colspan", "3");
tr.appendChild(td);
text = new Text(builder.getMGoal().getDescription());
td.appendChild(text);
Br br = new Br();
td.appendChild(br);
text = new Text(stripHtml(builder.getMGoal().getColorSchema()
.getDescription(), true));
td.appendChild(text);
}
private String stripHtml(String htmlString, boolean all) {
htmlString = htmlString.replace("<html>", "").replace("</html>", "")
.replace("<body>", "").replace("</body>", "").replace("<head>",
"").replace("</head>", "");
if (all)
htmlString = htmlString.replace(">", ">").replace("<", "<");
return htmlString;
}
} // BarGraph