Processing...
Description & Source Code
  • Description
  • View
    hierarchy.zul
    season.zul
    month.zul
  • Controller
    HierarchyController.java
    FormatElNumber.java
  • Model
    StockModel.java
    Stock.java
    Quarter.java
    Month.java

ZK allows components to contain other components to form a hierarchy of components where the inner components can be loaded only when they are needed this is done using ZK's detail tag and the fulfill attribute set to the event "onOpen"

hierarchy.zul
<?xel-method prefix="c" name="formatStock" class="demo.grid.hierarchy.FormatElNumber"
   signature="java.lang.String formatStock(double)"?>
<zk>
	<style src="/widgets/grid/hierarchy/style.css" />
	<div apply="demo.grid.hierarchy.HierarchyController">
		<grid id="hGrid" model="${$composer.stocks }">
			<columns>
				<column width="40px" />
				<column label="Stock Name" sort="auto(name)" />
				<column label="Avg. High" sort="auto(averageHigh)" align="center"/>
				<column label="Avg. Low" sort="auto(averageLow)" align="center"/>
				<column label="Avg. Volume" sort="auto(averageVolume)" align="center"/>
			</columns>
			<template name="model">
				<row>
					<!-- use custom-attributes to store quarters and stock in row, 
				 		so it can be accessed later when detail onOpen -->				
					<custom-attributes quarters="${each.quarters}" stock="${each}" />
					<detail open="false" fulfill="onOpen">
						<include src="/widgets/grid/hierarchy/season.zul" 
							stock="${stock}" quarters="${quarters}" />
					</detail>
					<label value="${each.name}" />
					<label value="${c:formatStock(each.averageHigh)}" style="color:red;"/>
					<label value="${c:formatStock(each.averageLow)}" style="color:green;"/>
					<label value="${c:formatStock(each.averageVolume)}" style="font-weight:bold;"/>
				</row>
			</template>
		</grid>
	</div>
</zk>

season.zul
<grid model="${arg.quarters}" sclass="inner-grid">
	<columns>
		<column width="40px" />
		<column label="Season" />
		<column label="Avg. High" sort="auto(averageHigh)" align="center"/>
		<column label="Avg. Low" sort="auto(averageLow)" align="center"/>
		<column label="Avg. Volume" sort="auto(averageVolume)" align="center"/>
	</columns>
	<template name="model">
		<row value="${forEachStatus.index}">
			<!-- use custom-attributes to store quarter and months in row, 
				 so it can be accessed later when detail onOpen -->
			<custom-attributes quarter="${each}" months="${each.months}" />
			<detail open="false" fulfill="onOpen">
				<include src="/widgets/grid/hierarchy/month.zul" 
					quarter="${quarter}" months="${months}" />
			</detail>
			<label value="Q${each.quarter}" />
			<label value="${c:formatStock(each.averageHigh)}" />
			<label value="${c:formatStock(each.averageLow)}" />
			<label value="${c:formatStock(each.averageVolume)}" />
		</row>
	</template>
	<foot>
		<footer width="40px" />
		<footer label="Avg:" />
		<footer label="${c:formatStock(arg.stock.averageHigh)}" />
		<footer label="${c:formatStock(arg.stock.averageLow)}" />
		<footer label="${c:formatStock(arg.stock.averageVolume)}" />
	</foot>
</grid>
month.zul
<zk>
	<grid model="${arg.months}">
		<columns>
			<column label="Month" />
			<column label="High" sort="auto(high)" align="center"/>
			<column label="Low" sort="auto(low)" align="center"/>
			<column label="Volume" sort="auto(volume)" align="center"/>
		</columns>
		<template name="model">
			<row sclass="last">
				<label value="${each.month}" />
				<label value="${c:formatStock(each.high)}" />
				<label value="${c:formatStock(each.low)}" />
				<label value="${c:formatStock(each.volume)}" />
			</row>
		</template>
	</grid>
	<chart type="line" width="600px" height="200px" bgColor="#fafafa"
		model="${arg.quarter.chartModel}" />
</zk>
HierarchyController.java
package demo.grid.hierarchy;

import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.ListModelList;

public class HierarchyController extends SelectorComposer<Component> {
	private static final long serialVersionUID = 1L;
	
	final StockModel stockData = new StockModel();
	
	public ListModel<Stock> getStocks() {
		return new ListModelList<Stock>(stockData.getStocks());
	}
}
FormatElNumber.java
package demo.grid.hierarchy;

import java.text.NumberFormat;
/*utility class of custom xel-method */
public class FormatElNumber {
	public static String formatStock(double stock) {
		final NumberFormat nf = NumberFormat.getInstance();
		nf.setMaximumFractionDigits(2);
		return nf.format(stock);
	}
}
StockModel.java
package demo.grid.hierarchy;

import java.util.ArrayList;
import java.util.List;

public class StockModel {
	
	private List<Stock> stock = new ArrayList<Stock>();
	
	public StockModel(){
		stock.add(generateStock("Csco"));
		stock.add(generateStock("Goog"));
		stock.add(generateStock("Yhoo"));
		stock.add(generateStock("Msft"));
		stock.add(generateStock("Orcl"));
		stock.add(generateStock("Amaz"));
		stock.add(generateStock("Fabc"));
	}

	public List<Stock> getStocks() {
		return stock;
	}
	
	private static Stock generateStock(String stockName) {
		return new Stock(stockName, getValue(), getValue(), getVolume(), generateQuarters());
	}
	
	private static List<Quarter> generateQuarters() {
		List<Quarter> quarters = new ArrayList<Quarter>();
		//generate each quarter
		for(int i =0; i<4; i++) {
			quarters.add(generateQuarter(i * 3));
		}
		return quarters;
	}
	
	private static Quarter generateQuarter(int start) {
		List<Month> months = new ArrayList<Month>();
		
		for(int i=0;i<3;i++) {
			months.add(new Month(start + i, getValue(), getValue(), getVolume()));
		}
		
		return new Quarter((start / 3) + 1, months);
	}
	
	private static double getValue() {
		return Math.random() * 50 + 40;
	}
	
	private static double getVolume() {
		return Math.random() * 50000 + 65536;
	}
}
Stock.java
package demo.grid.hierarchy;

import java.util.List;

import org.zkoss.zul.ListModel;
import org.zkoss.zul.ListModelList;

public class Stock {
	private String name;
	private List<Quarter> quarters;

	public Stock(String name, double high, double low,
			double volume, List<Quarter> quarters) {
		this.name = name;
		this.quarters = quarters;
	}

	public String getName() {
		return name;
	}

	public double getAverageHigh() {
		double total = 0;

		for (Quarter quarter : quarters) {
			total += quarter.getAverageHigh();
		}

		return total / quarters.size();
	}

	public double getAverageLow() {
		double total = 0;

		for (Quarter quarter : quarters) {
			total += quarter.getAverageLow();
		}

		return total / quarters.size();
	}

	public double getAverageVolume() {
		double total = 0;

		for (Quarter quarter : quarters) {
			total += quarter.getAverageVolume();
		}

		return total / quarters.size();
	}

	public ListModel<Quarter> getQuarters() {
		return new ListModelList<Quarter>(quarters);
	}

}
Quarter.java
package demo.grid.hierarchy;

import java.util.List;

import org.zkoss.zul.CategoryModel;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.SimpleCategoryModel;

public class Quarter {

	private List<Month> months;
	private int quarter;
	
	public Quarter(int quarter, List<Month> months) {
		this.months = months;
		this.quarter = quarter;
	}

	public ListModel<Month> getMonths() {
		return new ListModelList<Month>(this.months);
	}
	
	public int getQuarter() {
		return quarter;
	}

	public double getAverageHigh() {
		double total = 0;

		for (Month month : months) {
			total += month.getHigh();
		}

		return total / months.size();
	}

	public double getAverageLow() {
		double total = 0;

		for (Month month : months) {
			total += month.getLow();
		}

		return total / months.size();
	}

	public double getAverageVolume() {
		double total = 0;

		for (Month month : months) {
			total += month.getVolume();
		}

		return total / months.size();
	}

	public CategoryModel getChartModel() {
		
		CategoryModel categoryModel = new SimpleCategoryModel();
		
		for(Month month : months) {
			categoryModel.setValue("Performance", month.getMonth(), month.getVolume());
		}
		
		return categoryModel;
		
	}
}
Month.java
package demo.grid.hierarchy;

import java.text.SimpleDateFormat;
import java.util.Calendar;

public class Month {
	private final double high, low, volume;
	private final Calendar month = Calendar.getInstance();
	private final SimpleDateFormat monthFormat = new SimpleDateFormat("MMMM");
	private final String stringMonth;

	public Month(int month, double high, double low, double volume) {
		this.high = high;
		this.low = low;
		this.volume = volume;
		this.month.set(Calendar.MONTH, month);
		this.stringMonth = monthFormat.format(this.month.getTime());
	}

	public double getHigh() {
		return high;
	}

	public double getLow() {
		return low;
	}

	public double getVolume() {
		return volume;
	}

	public String getMonth() {
		return stringMonth;
	}
}