Saturday, July 28, 2012

ANSI C: N Queens Problem

Introduction

The n queens puzzle is the problem of placing n chess queens on an n*n chessboard so that no two queens attack each other.

The Program

queens_ori.c

``````
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>

/**
* The n queens puzzle is the problem of
* placing n chess queens on an n×n chessboard
* so that no two queens attack each other.
*/

// define some values to shorten the code

// status message and params
// printf(statmsg, statparam); will become
// printf("there are %d queens in a %d x %d chessboard\n\n answer(s): \n\n", number_of_queens, number_of_queens, number_of_queens);
#define statmsg "there are %d queens in a %d x %d chessboard\n\n answer(s): \n\n"
#define statparam number_of_queens, number_of_queens, number_of_queens
// answer message and params
#define ansmsg "put col[%d] queen to row %d\n"
#define ansparam outIdx, col[outIdx]
int number_of_queens;  // n queens in nxn chessboard
// note: don't too large (ex, over 25)
int *col;  // chessboard
FILE *outptr; // output file
int cnt; // result count

// function to solve this problem
void queens( int currentCol );
// function to determing whether the status is valid
bool promising( int currentCol );

int main()
{

cnt = 0;

printf("please enter the number of queens:\n");
scanf("%d", &number_of_queens);
// col[0] not used, start from col[1]
col = (int*) malloc ((number_of_queens+1)*sizeof(int));
outptr = fopen("QueenSol.txt", "w" );

printf(statmsg, statparam);
fprintf(outptr, statmsg, statparam);
// call function to solve problem
// pass 0 into it but it will then start from 1
queens( 0 );

if (cnt == 0) {
printf(" no result\n\n");
fprintf(outptr, " no result\n\n");
}
fclose( outptr );
free(col);

system("PAUSE");
return 0;
}

void queens( int currentCol )
{
int row;    // row index to test
int outIdx; // index for output result
if( promising(currentCol) )  // if valid
{
if( currentCol == number_of_queens )  // output if at latest col
{
cnt++;
for( outIdx = 1; outIdx <= number_of_queens; outIdx++ )
{
printf(ansmsg, ansparam);
fprintf(outptr, ansmsg, ansparam);
}
printf("\n\n");
fprintf(outptr, "\n\n");
}

// call function recursively if not latest col
else
{
for(row = 1; row <= number_of_queens; row++ )  // test next col from row 1 to row n
{
col[currentCol + 1] = row;
queens( currentCol + 1 );
}
}

}
}

// check whether current stats is valid
bool promising( int currentCol )
{
int idx = 1; // loop index
bool isValid = true; // is valid? default to true

// test whether previous queens will attack current queen
while( (idx < currentCol) && isValid )
{
// found invalid status
// in the same row
// or diagonal
if( (col[currentCol] == col[idx])
|| (abs( col[currentCol] - col[idx]) == currentCol - idx) )
{
isValid = false;  // set to invalid, stop loop
}
idx++;  // increase index and contiune

}
return isValid;
}
``````

The Result

Reference
http://en.wikipedia.org/wiki/Eight_queens_puzzle

The files are at github
https://github.com/benbai123/C_Cplusplus_Practice/tree/master/C_Algorithm/N_Quenes

Thursday, July 26, 2012

ZK: Mask page manually

Introduction

Sometimes we may need to load something for a while and the page may seems ugly before it loaded (e.g., we are loading something for fancy style). We can mask the page to hide the ugly page if needed.

The Page

``````<zk>
<script type="text/javascript"><![CDATA[
// mask a while
setTimeout(function () {
some = {};
}, 2000);
var timer = setInterval(function () {
// log, can be removed
zk.log(' checking... ');
if (some && some.loaded && some.loaded.data) {
zAu.cmd0.clearBusy(null);
clearInterval(timer);
}
}, 500);
]]></script>
<window border="normal" title="test win">
test
</window>
</zk>``````

The Result
View the demo flash on line
http://screencast.com/t/jNxbQoyffH0

You can find the flash file at github:

The file is at github

Reading and writing text files in Java

Introduction

Just simple log

Program fragment

where the "data.txt" is under project root

``````            File srcFile = new File( "data.txt" );
new FileInputStream(srcFile), "UTF-8"));
while( br.ready() ) {
}
br.close();
``````

Write text to file

``````            File destFile = new File("dest.txt");
if (!destFile.exists()) {
destFile.createNewFile();
}
BufferedWriter bw =
new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(destFile), "UTF-8"));
bw.write("test\n");
bw.write("test test");
bw.flush();
bw.close();``````

Reference
http://docs.oracle.com/javase/tutorial/i18n/text/stream.html

Sunday, July 22, 2012

ANSI C: Hamiltonian cycle

Introduction

A Hamiltonian path (or traceable path) is a path in an undirected graph that visits each vertex exactly once. A Hamiltonian cycle (or Hamiltonian circuit) is a Hamiltonian path that is a cycle.

In this post, we will implement an ANSI C program that will display all Hamiltonian cycle of a given graph array.

The Program

hamiltonian.c

``````#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>

/**
* A Hamiltonian path (or traceable path)
* is a path in an undirected graph that
* visits each vertex exactly once.
* A Hamiltonian cycle (or Hamiltonian circuit) is
* a Hamiltonian path that is a cycle.
* From wiki: http://en.wikipedia.org/wiki/Hamiltonian_path
*/

// the number of nodes in the test graphic
int node_amount = 12;
// the number of Hamiltonian cycles
int hamiltonian_cycle_amount = 0;

// Graph Representation with nodes
// not use [0][x] and [x][0]
int graph_array[13][13] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,0,0,1,0,0,0,0,0,0,0,
0,1,0,1,0,0,0,1,1,0,0,0,0,
0,0,1,0,1,0,0,0,1,0,0,0,0,
0,0,0,1,0,1,0,0,0,1,0,0,0,
0,1,0,0,0,0,1,0,0,0,1,0,0,
0,0,0,0,0,1,0,1,0,0,0,1,0,
0,0,1,0,0,0,1,0,1,0,0,0,0,
0,0,1,1,0,0,0,1,0,1,0,0,0,
0,0,0,0,1,0,0,0,1,0,1,0,1,
0,0,0,0,0,1,0,0,0,0,0,1,0,
0,0,0,0,0,0,1,0,0,0,1,0,1,
0,1,0,0,0,0,0,0,0,1,0,1,0
};

// the array store the result through recursive
int result_array[13] = {0};

/**
* The function that find all Hamiltonian cycle
* and output to console
* param node_index: int, nth node in path
*/
void hamiltonian ( int node_index );
/**
* The function that check whether current node
* is valid in Hamiltonian cycle.
*/
bool promising ( int node_index );

int main()
{
printf("\n");
result_array[1] = 1;  // start from first node
hamiltonian( 1 );  // start to find all Hamiltonian cycles recursively

if( hamiltonian_cycle_amount == 0 )  // no Hamiltonian cycles found
printf("\nThere is no Hamiltonian cycles in this graph\n\n");

printf("\n");

system("PAUSE");
return 0;
}

void hamiltonian ( int node_index )
{
int j, k;
if( promising(node_index) )  // current node is valid in a Hamiltonian cycles
{
if( node_index == (node_amount) )  // at latest node
{  hamiltonian_cycle_amount = 1;  // increase hamiltonian_cycle_amount
printf(" v%d", result_array[1]);  // print out the result
for( k = 2;k <= node_amount;k ++ )
printf(" → v%d", result_array[k]);
printf("\n\n");
}
else  // not latest node
{
for( j = 2;j <= node_amount;j ++ )  // recursively scan from second node to latest node
{
result_array[node_index+1] = j; // store result
hamiltonian( node_index+1 );  // call function recursively
}
}
}

}

bool promising ( int node_index )
{
int j, k;
bool isValid = true; // default to valid

j = 1;

if (node_index == 1) // first node, valid
isValid =  true;
if( (node_index == (node_amount)) && (!graph_array[result_array[node_index]][result_array[1]]) )
isValid =  false;  // latest node but not connected to first node, invalid

else if( ( node_index > 1 ) && (!graph_array[result_array[node_index-1]][result_array[node_index]]) )
isValid =  false;  // not connected between current node and previous node, invalid

else
{
while( (j < node_index) && isValid)  // check all previous nodes
{
if( result_array[node_index] == result_array [j] )
isValid = false;  // current point already in path, invalid
j++;
}
}
return isValid;  // return whether current node is valid
}
``````

The Result

Reference
http://en.wikipedia.org/wiki/Hamiltonian_path

The files at github
https://github.com/benbai123/C_Cplusplus_Practice/tree/master/C_Algorithm/Hamiltonian_Cycle

Sunday, July 15, 2012

ANSI C: Coloring Problem

Introduction

The Coloring Problem is coloring the vertices of a graph such that no two adjacent vertices share the same color, in this post, we will try to implement it in ANSI C.

The Program

Coloring_Problem.c

``````#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>

/**
* Graph coloring
* Coloring the vertices of a graph such that
* no two adjacent vertices share the same color;
* Wiki: http://en.wikipedia.org/wiki/Graph_coloring
*/

FILE *res;

// The 2-D array denotes a graph adjacent status,
// For example, [a, b] are adjacent vertices,
// [a, d] are also adjacent vertices.
// the index starts from 1,
// [0][x] and [x][0] are not considered
// #,a,b,c,d,e,f
int _adjacentMatrix [7][7] = {0,0,0,0,0,0,0, // not use
0,0,1,0,1,0,0, // a
0,1,0,1,0,1,0, // b
0,0,1,0,0,0,1, // c
0,1,0,0,0,1,0, // d
0,0,1,0,1,0,1, // e
0,0,0,1,0,1,0  // f
};

int _verticeAmount = 6;  // six points

// three colors
char _colors[4][20] = { "NULL",
"RED",
"GREEN",
"WHITE"
};

// temp store the result
int _result[7] = {0};

void m_coloring( int i );
bool promising( int i );

int main()
{
res = fopen("result.txt", "w");
printf("there are %d vertices, the color combinations are as below: \n\n", _verticeAmount);
fprintf(res, "there are %d vertices, the color combinations are as below: \n\n", _verticeAmount);
m_coloring( 0 );
fclose( res );

system("PAUSE");
return 0;
}

/**
* The coloring function that will recursively create different combinations
* then call promising function to test whether the combination is valid.
*
* Three actions:
*         Output the result if
*         the current combination is valid and reach the latest vertice.
*
*         Continue add color - vertice to extend combination if
*         the current combination is valid but not reach the latest vertice.
*
*         Terminate the recursive to skip any combination
*         that starts with the current combination if
*         the current combination is not valid.
*
*/
void m_coloring ( int i )
{
int color; // color index for test
int j; // index for output result

if( promising(i) )  // coloring success
{
if( i == _verticeAmount ) // is latest vertice
{
for( j = 1;j <= _verticeAmount;j ++ )  // output the result
{
if (j > 1) {
printf(",");
fprintf(res, ", ");
}
printf("%s", _colors[_result[j]]);
fprintf(res, "%s", _colors[_result[j]]);
}
printf("\n\n");
fprintf(res, "\n\n");

}

else  // not latest vertice
{
for( color = 1;color <= 3;color ++ )  // test each color
{
_result[i+1] = color;  // set color to next vertice
m_coloring(i+1); // recursive to continue combination
}
}
}
}

/**
* check whether has adjacent virtice share color with current virtice
* return bool
* true: no adjacent vertice share the same color, can
* continue this combination
* false: has adjacent vertice share the same color,
* this combination should be terminated
*/
bool promising( int currentVerticeIndex )
{
int j = 1; // start from first virtice
bool sw = true;  // default to success (no two adjacent vertices share the same color)

while( (j < currentVerticeIndex) && sw)  // scan all previous vertices
{
// if found an adjacent vertice share the same color
if( _adjacentMatrix[currentVerticeIndex][j] && (_result[currentVerticeIndex] == _result[j])) {
sw = false;  // set to fail (has two adjacent vertices share the same color)
break;
}
j++;
}

return sw;  // return the result (success or fail)
}
``````

The promising function will return whether current combination is valid.

The m_coloring function that will recursively create different combinations then call promising function to test whether the combination is valid. It will do three different actions with respect to the different status and the result of promising function:

1. Output the result if the current combination is valid and reach the latest vertice.

2. Continue add color - vertice to extend combination if the current combination is valid but not reach the latest vertice.

3. Terminate the recursive to skip any combination that starts with the current combination if the current combination is not valid.

The Result

Reference
Wiki
http://en.wikipedia.org/wiki/Graph_coloring

Files at github
https://github.com/benbai123/C_Cplusplus_Practice/tree/master/C_Algorithm/Coloring_Problem

Saturday, July 14, 2012

ZK: Modify tooltiop on gantt chart

Introduction

Chart is a component of ZK which can draw various kind of chart, in gantt chart it will show some default tooltip on the 'bar'.

This post is about how to change the tooltip of bars to customized value.

The ZUL Page

modify_tooltip_on_gantt_chart.zul

``````<zk xmlns:w="client">
<!-- prepare model -->
<zscript><![CDATA[

public Date date(int year, int month, int day) {
final java.util.Calendar calendar = java.util.Calendar.getInstance();
calendar.set(year, month-1, day);
final Date result = calendar.getTime();
return result;
}
//series, task (task description, start, end, complete percentage)
GanttModel ganttmodel = new GanttModel();
ganttmodel.addValue("Scheduled", new GanttTask("Write Proposal", date(2008,4,1), date(2008,4,5), 0.1));
ganttmodel.addValue("Scheduled", new GanttTask("Obtain Approval", date(2008,4,9), date(2008,4,9), 0.0));
ganttmodel.addValue("Scheduled", new GanttTask("Requirements Analysis", date(2008,4,10), date(2008,5,5), 0.0));
ganttmodel.addValue("Scheduled", new GanttTask("Design Phase", date(2008,5,6), date(2008,5,30), 0.0));
ganttmodel.addValue("Scheduled", new GanttTask("Design Signoff", date(2008,6,2), date(2008,6,2), 0.0));
ganttmodel.addValue("Scheduled", new GanttTask("Alpha Implementation", date(2008,6,3), date(2008,7,31), 0.2));
ganttmodel.addValue("Scheduled", new GanttTask("Design Review", date(2008,8,1), date(2008,8,8), 0.0));
ganttmodel.addValue("Scheduled", new GanttTask("Revised Design Signoff", date(2008,8,10), date(2008,8,10), 0.0));
ganttmodel.addValue("Scheduled", new GanttTask("Beta Implementation", date(2008,8,12), date(2008,9,12), 0.0));
ganttmodel.addValue("Scheduled", new GanttTask("Final Implementation", date(2008,11,1), date(2008,11,15), 0.0));

ganttmodel.addValue("Actual", new GanttTask("Write Proposal", date(2008,4,1), date(2008,4,3), 0.0));
ganttmodel.addValue("Actual", new GanttTask("Obtain Approval", date(2008,4,9), date(2008,4,9), 0.0));
ganttmodel.addValue("Actual", new GanttTask("Requirements Analysis", date(2008,4,10), date(2008,5,15), 0.0));
ganttmodel.addValue("Actual", new GanttTask("Design Phase", date(2008,5,15), date(2008,6,17), 0.0));
ganttmodel.addValue("Actual", new GanttTask("Design Signoff", date(2008,6,30), date(2008,6,30), 0.0));
ganttmodel.addValue("Actual", new GanttTask("Alpha Implementation", date(2008,7,1), date(2008,9,12), 0.0));
ganttmodel.addValue("Actual", new GanttTask("Design Review", date(2008,9,12), date(2008,9,22), 0.0));
ganttmodel.addValue("Actual", new GanttTask("Revised Design Signoff", date(2008,9,25), date(2008,9,27), 0.0));
ganttmodel.addValue("Actual", new GanttTask("Beta Implementation", date(2008,8,12), date(2008,9,12), 0.0));
ganttmodel.addValue("Actual", new GanttTask("Final Implementation", date(2008,11,18), date(2008,12,5), 0.0));
]]></zscript>
<chart id="gantt" title="Gantt Chart" width="700" height="400"
model="\${ganttmodel}"
type="gantt" threeD="false" fgAlpha="128" dateFormat="yyyy/MM/dd" >
<!-- override bind_ function to update the tooltip -->
<attribute w:name="bind_"><![CDATA[
function () {
this.\$bind_();
var areas = jq('area'),
len = areas.length;
if (len > 0) {
for (var i = 0; i < len; i++) {
var area = areas[i],
title;
// original format is 'percentage, start ~ end'
// extract the 'start' and 'end' to create new tooltip
if ((title = area.title) && title.indexOf(',') >= 0 && title.indexOf('~') >= 0) {
var range = title.split(',')[1].split('~'),
start = range[0].replace(/^\s\s*/, '').replace(/\s\s*\$/, ''),
end = range[1].replace(/^\s\s*/, '').replace(/\s\s*\$/, '');

// update title
area.title = 'Range: From ' + start + ' to ' + end;
}
}
}
}
]]></attribute>
</chart>
</zk>``````

The Result

Reference
http://books.zkoss.org/wiki/ZK_Component_Reference/Diagrams_and_Reports/Chart

https://github.com/benbai123/ZK_Practice/blob/master/Components/projects/Components_Practice/WebContent/modify_tooltip_on_gantt_chart.zul

Friday, July 13, 2012

ZK Pivottable: Display Data in ZK Pivottable

Introduction

ZK Pivottable is a ZK addon component that can display data in summarized view as MS-Excel's pivottable. In this post, we will try to display some fake data in pivottable.

The Composer

TestComposer.java

``````package test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import org.zkoss.pivot.PivotField;

import org.zkoss.pivot.impl.TabularPivotModel;

import org.zkoss.zk.ui.select.SelectorComposer;

/**
* Tested with ZK 6.0.1 CE and ZK Pivottable 2.0.0
*
*/
@SuppressWarnings("rawtypes")
public class TestComposer extends SelectorComposer {
/**
* generated serial version UID
*/
private static final long serialVersionUID = -2897873399288955635L;
private TabularPivotModel _pivotModel;

/**
* Get pivottable's model
* @return TabularPivotModel the pivottable's model
* @throws Exception
*/
public TabularPivotModel getPivotModel () throws Exception {
if (_pivotModel == null) {
_pivotModel = new TabularPivotModel(getData(), getColumns());

// assign rows, the order matches to the level of row node field
_pivotModel.setFieldType("Row_Level_001", PivotField.Type.ROW);
_pivotModel.setFieldType("Row_Level_002", PivotField.Type.ROW);
_pivotModel.setFieldType("Row_Level_003", PivotField.Type.ROW);
_pivotModel.setFieldType("Row_Level_004", PivotField.Type.ROW);

// assign columns, the order matches to the level of column node field
_pivotModel.setFieldType("Column_Level_001", PivotField.Type.COLUMN);
_pivotModel.setFieldType("Column_Level_002", PivotField.Type.COLUMN);

// assign datas, the order matches to the order of data field
_pivotModel.setFieldType("Data_Field_001", PivotField.Type.DATA);
_pivotModel.setFieldType("Data_Field_002", PivotField.Type.DATA);
_pivotModel.setFieldType("Data_Field_003", PivotField.Type.DATA);
}
return _pivotModel;
}
/**
* prepare the data for pivottable's model
* The order of object put into data list matches
* the order of column name's order
* @return
* @throws Exception
*/
public List<List<Object>> getData() throws Exception {
List<List<Object>> result = new ArrayList<List<Object>>();
Random r = new Random();

for (int i = 0; i < 10000; i++) {
List<Object> data = new ArrayList<Object>();
data.add("Row_Level_001 - " + (r.nextInt(10) + 1));
data.add("Row_Level_002 - " + (r.nextInt(10) + 1));
data.add("Row_Level_003 - " + (r.nextInt(10) + 1));
data.add("Row_Level_004 - " + (r.nextInt(10) + 1));
data.add("Column_Level_001 - " + (r.nextInt(10) + 1));
data.add("Column_Level_002 - " + (r.nextInt(10) + 1));
}
return result;
}
/**
* prepare columns name for pivottable's model
* @return
*/
public List<String> getColumns() {
return Arrays.asList(new String[]{
"Row_Level_001", "Row_Level_002", "Row_Level_003", "Row_Level_004",
"Column_Level_001", "Column_Level_002",
"Data_Field_001", "Data_Field_002", "Data_Field_003"
});
}

}
``````

Here only simply add some fake data / columns to pivot model.
The order of data will matches to the order of column automatically.

The ZUL Page

index.zul

``````<zk>
<!-- Tested with ZK 6.0.1 CE and ZK Pivottable 2.0.0 -->
<!-- window, apply a SelectorComposer -->
<window id="win" xmlns:w="client"
apply="test.TestComposer">
<!-- pivottable, get model from window's composer -->
<pivottable id="pivottable" model="\${win\$composer.pivotModel}" />
</window>
</zk>``````

The Result
View the demo flash on line
http://screencast.com/t/C2CxL4aeNHmZ

You can find the flash file at github:

Reference
http://books.zkoss.org/wiki/ZK_Pivottable_Essentials

The full project is at github

Sunday, July 8, 2012

JSP Custom Tag: Nested Tags

Introduction

In the previous post (http://ben-bai.blogspot.tw/2012/07/jsp-custom-tag-body-tag.html), we have implemented a body tag 'fadeoutBlock', in this post we will try the advanced body tag - 'Nested Tags' and implement a tag set 'tabbox, tabpanel'.

Pre-define

1. A tabbox can contain several tabpanels.
2. You can set the 'width' and 'height' of a tabbox.
3. A tabpanel can contains any JSP body content.
4. You can set the 'header' of a tabpanel.

The Program

Tabbox.java

``````package test.tag.custom;

import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.TagSupport;

/**
* Simple tabbox with poor look and feel
*/
public class Tabbox extends BodyTagSupport {
private int _panelCnt = 0;
private int _width = 100;
private int _height = 100;
private StringBuilder _headerContent = new StringBuilder("");
private StringBuilder _bodyContent = new StringBuilder("");

public void setWidth (int width) {
_width = width;
}
public void setHeight (int height) {
_height = height;
}
public int doStartTag() throws JspException {
try {
// output the out most area
JspWriter out = pageContext.getOut();
out.print("<div");
out.print(" style=\"overflow: auto; width: "+_width+"px; height: "+_height+"px; border: 1px solid #CCCCCC;\"");
out.print(">");
} catch (Exception e) {
throw new JspException("Error: IOException while writing to client");
}

// evaluate body content and output it directly
return EVAL_BODY_INCLUDE;
}

public int doEndTag() throws JspException {
try {
JspWriter out = pageContext.getOut();
// output the header/body of tabpanels
out.print("<div style=\"margin: 10px; border: 1px solid #3648AE;\">"+_bodyContent.toString()+"</div></div>");
} catch (Exception ex) {
throw new JspException(ex.getMessage());
}
release();
// continue evaluate page
return EVAL_PAGE;

}

public void release() {
// have to reset all field values since container may reuse this instance
_panelCnt = 0;
_width = 100;
_height = 100;
_bodyContent.setLength(0);
}

// called by Tabpanel, add header content
String style = _panelCnt == 0? "background-color: gray;" : "background-color: transparent;";
style += " margin-right: 5px; border: 1px solid #CCCCCC; border-bottom: 0px; cursor: pointer;";
.append(content)
.append("</span>");
}
public void addBodyContent (String content) {
// called by Tabpanel, add body contents
String style = _panelCnt == 0? "" : "display: none;";
_bodyContent.append("<div style=\""+style+"\">")
.append(content)
.append("</div>");
}

public void increaseCnt () {
// called by Tabpanel, tell Tabbox the number of tabpanel is increased
_panelCnt++;
}

// its better provided by a .js file
private String showMatchedPanel () {
// the javascript that executes while tabpanel's header clicked
StringBuilder cmd = new StringBuilder();

cmd.append("var headerContainer = this.parentNode,")
.append("    bodyContainer = headerContainer.nextSibling,")
.append("    bodyArray = bodyContainer.childNodes,")
.append("    ele, i, idx;")
.append("for (i = 0; i < headerArray.length; i++) {")
.append("    if ((ele = headerArray[i]) == this) {")
.append("        ele.style.backgroundColor = 'gray';")
.append("        idx = i;")
.append("    } else")
.append("        ele.style.backgroundColor = 'transparent';")
.append("}")
.append("for (i = 0; i < bodyArray.length; i++) {")
.append("    if (i == idx)")
.append("        bodyArray[i].style.display = 'block';")
.append("    else")
.append("        bodyArray[i].style.display = 'none';")
.append("}");
return cmd.toString();
}
}``````

Tabbox provide the API's for tabpanels to add their header/body content and then output them properly with the appropriate javascript action while header clicked.

Tabpanel.java

``````package test.tag.custom;

import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.TagSupport;

/**
* Simple tabpanel with poor look and feel
*/
public class Tabpanel extends BodyTagSupport {
private String _header = new String("tab header");

}

public int doStartTag() throws JspException {
// denotes evaluate body but do not output it, store it in buffer
return EVAL_BODY_BUFFERED;
}

public int doEndTag() throws JspException {
// find the parent tabbox
Tabbox parent = (Tabbox)findAncestorWithClass(this, Tabbox.class);
// get the buffered body content
String body = getBodyContent().getString();
// parent should not be null
if(parent == null)
throw new JspException("Tabpanel.doStartTag(): " + "No Tabbox ancestor");

// fix empty body
if (body == null || body.isEmpty())
body = "&nbsp;"; // at least a space char
// fix empty header
_header = "&nbsp;"; // at least a space char
// add header content to parent tabbox
// add body content to parent tabbox
parent.increaseCnt();
release();

return EVAL_PAGE;

}

public void release() {
// have to reset all field values since container may reuse this instance
}

}``````

Tabpanel will store its body content in a buffer then pass it and header to Tabbox to render.

The tag definition

Add the fragment below to the tld file which already created from previous post (http://ben-bai.blogspot.tw/2012/06/jsp-custom-tag-simple-tag.html) then export jar as described in the previous post.

``````<tag>
<!-- tag name -->
<name>tabbox</name>
<!-- tag class path -->
<tagclass>test.tag.custom.Tabbox</tagclass>
<!-- denotes the tag has JSP body content -->
<bodycontent>JSP</bodycontent>
<attribute>
<!-- attribute name -->
<name>width</name>
<!-- required or not -->
<required>false</required>
<!-- el enable or not (true denotes can be eval at runtime) -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- attribute name -->
<name>height</name>
<!-- required or not -->
<required>false</required>
<!-- el enable or not (true denotes can be eval at runtime) -->
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
<tag>
<!-- tag name -->
<name>tabpanel</name>
<!-- tag class path -->
<tagclass>test.tag.custom.Tabpanel</tagclass>
<!-- denotes the tag has JSP body content -->
<bodycontent>JSP</bodycontent>
<attribute>
<!-- attribute name -->
<!-- required or not -->
<required>false</required>
<!-- el enable or not (true denotes can be eval at runtime) -->
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>``````

Test Page

tabboxTest.jsp

``````<%@ page isErrorPage="true" language="java"
contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page isELIgnored ="false" %>
<!-- use the custom taglib with prefix ct -->
<%@taglib prefix="ct" uri="http://test.tag.custom/jsp/impl/taglib"%>
<html>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8"/>
<title>EL Math Practice</title>
<body>
<!-- the tabbox -->
<ct:tabbox width="500" height="300">
<!-- child tabpanels -->
this is the first panel of the tabbox
<div style="height: 150px; width: 150px; background-color: red;"></div>
</ct:tabpanel>
<div style="height: 200px; width: 200px; background-color: green;">
second panel
</div>
</ct:tabpanel>
the third panel
</ct:tabpanel>
</ct:tabbox>
</body>
</html>``````

The Result

View the demo flash on line
http://screencast.com/t/e5QqxXQ1O

You can find the flash file at github:
https://github.com/benbai123/JSP_Servlet_Practice/blob/master/demo_src/JSP/Custom_tag/tabbox_test.swf

Reference
http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPTags.html

The full project is at github
https://github.com/benbai123/JSP_Servlet_Practice/tree/master/Practice/CustomTagPractice

Sunday, July 1, 2012

JSP Custom Tag: Body Tag

Introduction

In the previous post (http://ben-bai.blogspot.tw/2012/06/jsp-custom-tag-simple-tag.html) we implement a simple tag 'errMsg' to display some error message, in this post, we will create a body tag 'fadeoutBlock' to display content in a fade-out block.

A body tag is a JSP custom tag that has a body, the only difference between simple-tag and body-tag is body-tag will evaluate its body content but simple-tag will not.

Pre-define
The spec of the fadeoutBlock tag:
1. Can contain any JSP content in its body.
2. Attributes:
style: the css style as normal html tag's style.
styleClass: the css class as normal html tag's class.
duration: the duration of fade-out action in milli seconds.
step: the value that the opacity will be 'decreased' in each fade-out step.
3. Do fade-out while clicked.

The Program

``````package test.tag.custom;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

/**
* Fadeout Block JSP Custom Tag, body tag, can contain jsp content body.
*
*/
public class FadeoutBlock extends TagSupport {

private static final long serialVersionUID = 3563006227719937104L;
private String _style = "background-color: CCBBEE;";
private String _styleClass = null; //--css class
private Integer _duration = 1000;
private float _step = 0.1f;

/**
* tag attribute setter
* @param style The style of this element
*/
public void setStyle(String style){
if (style != null && !style.isEmpty())
_style = style;
}
/**
* tag attribute setter
* @param styleClass The css class of this element
*/
public void setStyleClass(String styleClass){
_styleClass = styleClass;
}
/**
* tag attribute setter
* @param duration The duration of fade-out action
*/
public void setDuration (Integer duration) {
if (duration > 0)
_duration = duration;
}
/**
* tag attribute setter
* @param step The step value of each fade-out step
*/
public void setStep (float step) {
if (step > 0)
_step = step;
}
/**
* do start tag
*/
@Override
public int doStartTag() throws JspException {
try {
JspWriter out = pageContext.getOut();
// output div's start tag, style, class and fadeOut function
out.print("<div style=\""+_style+"\"");
if (_styleClass != null)
out.print(" class=\""+_styleClass+"\"");
} catch (Exception e) {
throw new JspException("Error: IOException while writing to client");
}
//-- continue process the body content
return EVAL_BODY_INCLUDE;
}
/**
* do end tag
*/
@Override
public int doEndTag() throws JspException {
try {
// output div's end tag
pageContext.getOut().print("</div>");
}
catch (IOException ioe) {
throw new JspException("Error: IOException while writing to client");
}
//-- continue process the page
return EVAL_PAGE;
}
/**
* The fadeOut function, its better provided from a js file.
* @return String, the fadeOut function
*/
private String fadeOut () {
StringBuilder sb = new StringBuilder();
sb.append("var ele = this, time = "+_duration / (1.0/_step)
+", eStyle = ele.style, inc = "+_step+", timer, value;")
.append("if (!eStyle.opacity) eStyle.opacity = 1;")
.append("if (!ele.fo) ele.fo = setInterval(function () {")
.append("if (eStyle.opacity > 0) {")
.append("value = eStyle.opacity; eStyle.opacity -= inc;")
.append("if (value == eStyle.opacity) value = eStyle.opacity = 0;")
.append("else value = eStyle.opacity;")
.append("eStyle.filter = 'alpha(opacity = ' + (value*100) + ')';")
.append("} else clearInterval(ele.fo);")
.append("}, time);");

return sb.toString();
}
}``````

The tag definition

Add the fragment below to the tld file which already created from previous post (http://ben-bai.blogspot.tw/2012/06/jsp-custom-tag-simple-tag.html) then export jar as described in the previous post.

``````<!-- fadeoutBlock tag -->
<tag>
<!-- tag name -->
<!-- tag class path -->
<!-- denotes the tag has JSP body content -->
<bodycontent>JSP</bodycontent>
<!-- attributes -->
<attribute>
<!-- attribute name -->
<name>style</name>
<!-- required or not -->
<required>false</required>
<!-- el enable or not (true denotes can be eval at runtime) -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- attribute name -->
<name>styleClass</name>
<!-- required or not -->
<required>false</required>
<!-- el enable or not (true denotes can be eval at runtime) -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- attribute name -->
<name>duration</name>
<!-- required or not -->
<required>false</required>
<!-- el enable or not (true denotes can be eval at runtime) -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- attribute name -->
<name>step</name>
<!-- required or not -->
<required>false</required>
<!-- el enable or not (true denotes can be eval at runtime) -->
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>``````

Test page

``````<%@ page isErrorPage="true" language="java"
contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page isELIgnored ="false" %>
<!-- use the custom taglib with prefix ct -->
<%@taglib prefix="ct" uri="http://test.tag.custom/jsp/impl/taglib"%>
<html>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8"/>
<title>EL Math Practice</title>
<style>
.msg_block {
position: absolute;
left: 300px;
top: 200px;
width: 300px;
height: 150px;
}
</style>
<body>
duration="3000" step="0.05">
<div style="margin: 20px; border: 1px solid #8463AE;">
test message, click to fade-out
</div>
</body>
</html>``````

The Result

View the demo flash on line
http://screencast.com/t/DAY7MfKaxtSg

You can find the flash file at github: