Browse Source

first commit

YinBin 1 year ago
commit
60706d338d

+ 1 - 0
README.md

@@ -0,0 +1 @@
+# JGrid-tang

+ 74 - 0
build.xml

@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="JGrid" default="default" basedir=".">
+    <description>Builds, tests, and runs the project JGrid.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single JUnit test
+      -post-compile-test-single: called after javac compilation of single JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar-with-manifest:    JAR building (if you are using a manifest)
+      -do-jar-without-manifest: JAR building (if you are not using a manifest)
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like this:
+
+        <target name="run" depends="JGrid-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only on 
+    the compile target as the regular run target does. Again, for a list of available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+</project>

+ 4 - 0
build/built-jar.properties

@@ -0,0 +1,4 @@
+#Tue, 23 Sep 2014 14:46:00 +0800
+
+
+C\:\\JDev\\myworkspaces\\JGrid=

BIN
build/classes/com/tang/taglib/grid/JGrid.class


BIN
build/classes/com/tang/taglib/grid/Paging.class


BIN
build/classes/com/tang/taglib/grid/SingleRecord.class


BIN
build/classes/com/tang/taglib/grid/SingleRecordComparator.class


BIN
build/classes/com/tang/taglib/grid/SingleRecordCreation.class


BIN
dist/JGrid.jar


+ 1411 - 0
nbproject/build-impl.xml

@@ -0,0 +1,1411 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT  ***
+***         EDIT ../build.xml INSTEAD         ***
+
+For the purpose of easier reading the script
+is divided into following sections:
+
+  - initialization
+  - compilation
+  - jar
+  - execution
+  - debugging
+  - javadoc
+  - test compilation
+  - test execution
+  - test debugging
+  - applet
+  - cleanup
+
+        -->
+<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="JGrid-impl">
+    <fail message="Please build using Ant 1.8.0 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.8.0"/>
+            </not>
+        </condition>
+    </fail>
+    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
+    <!-- 
+                ======================
+                INITIALIZATION SECTION 
+                ======================
+            -->
+    <target name="-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init" name="-init-private">
+        <property file="nbproject/private/config.properties"/>
+        <property file="nbproject/private/configs/${config}.properties"/>
+        <property file="nbproject/private/private.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private" name="-init-user">
+        <property file="${user.properties.file}"/>
+        <!-- The two properties below are usually overridden -->
+        <!-- by the active platform. Just a fallback. -->
+        <property name="default.javac.source" value="1.4"/>
+        <property name="default.javac.target" value="1.4"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
+        <property file="nbproject/configs/${config}.properties"/>
+        <property file="nbproject/project.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
+        <available file="${manifest.file}" property="manifest.available"/>
+        <condition property="splashscreen.available">
+            <and>
+                <not>
+                    <equals arg1="${application.splash}" arg2="" trim="true"/>
+                </not>
+                <available file="${application.splash}"/>
+            </and>
+        </condition>
+        <condition property="main.class.available">
+            <and>
+                <isset property="main.class"/>
+                <not>
+                    <equals arg1="${main.class}" arg2="" trim="true"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class">
+            <and>
+                <isset property="manifest.available"/>
+                <isset property="main.class.available"/>
+            </and>
+        </condition>
+        <condition property="do.archive">
+            <not>
+                <istrue value="${jar.archive.disabled}"/>
+            </not>
+        </condition>
+        <condition property="do.mkdist">
+            <and>
+                <isset property="do.archive"/>
+                <isset property="libs.CopyLibs.classpath"/>
+                <not>
+                    <istrue value="${mkdist.disabled}"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class+mkdist.available">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="do.mkdist"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available">
+            <and>
+                <isset property="manifest.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+main.class.available">
+            <and>
+                <isset property="main.class.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+splashscreen.available">
+            <and>
+                <isset property="splashscreen.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available+main.class">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="manifest.available-mkdist.available">
+            <or>
+                <istrue value="${manifest.available}"/>
+                <isset property="do.mkdist"/>
+            </or>
+        </condition>
+        <condition property="manifest.available+main.class-mkdist.available">
+            <or>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="do.mkdist"/>
+            </or>
+        </condition>
+        <condition property="have.tests">
+            <or>
+                <available file="${test.src.dir}"/>
+            </or>
+        </condition>
+        <condition property="have.sources">
+            <or>
+                <available file="${src.dir}"/>
+            </or>
+        </condition>
+        <condition property="netbeans.home+have.tests">
+            <and>
+                <isset property="netbeans.home"/>
+                <isset property="have.tests"/>
+            </and>
+        </condition>
+        <condition property="no.javadoc.preview">
+            <and>
+                <isset property="javadoc.preview"/>
+                <isfalse value="${javadoc.preview}"/>
+            </and>
+        </condition>
+        <property name="run.jvmargs" value=""/>
+        <property name="run.jvmargs.ide" value=""/>
+        <property name="javac.compilerargs" value=""/>
+        <property name="work.dir" value="${basedir}"/>
+        <condition property="no.deps">
+            <and>
+                <istrue value="${no.dependencies}"/>
+            </and>
+        </condition>
+        <property name="javac.debug" value="true"/>
+        <property name="javadoc.preview" value="true"/>
+        <property name="application.args" value=""/>
+        <property name="source.encoding" value="${file.encoding}"/>
+        <property name="runtime.encoding" value="${source.encoding}"/>
+        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
+            <and>
+                <isset property="javadoc.encoding"/>
+                <not>
+                    <equals arg1="${javadoc.encoding}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <property name="javadoc.encoding.used" value="${source.encoding}"/>
+        <property name="includes" value="**"/>
+        <property name="excludes" value=""/>
+        <property name="do.depend" value="false"/>
+        <condition property="do.depend.true">
+            <istrue value="${do.depend}"/>
+        </condition>
+        <path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
+        <condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
+            <length length="0" string="${endorsed.classpath}" when="greater"/>
+        </condition>
+        <condition else="false" property="jdkBug6558476">
+            <and>
+                <matches pattern="1\.[56]" string="${java.specification.version}"/>
+                <not>
+                    <os family="unix"/>
+                </not>
+            </and>
+        </condition>
+        <property name="javac.fork" value="${jdkBug6558476}"/>
+        <property name="jar.index" value="false"/>
+        <property name="jar.index.metainf" value="${jar.index}"/>
+        <property name="copylibs.rebase" value="true"/>
+        <available file="${meta.inf.dir}/persistence.xml" property="has.persistence.xml"/>
+        <condition property="junit.available">
+            <or>
+                <available classname="org.junit.Test" classpath="${run.test.classpath}"/>
+                <available classname="junit.framework.Test" classpath="${run.test.classpath}"/>
+            </or>
+        </condition>
+        <condition property="testng.available">
+            <available classname="org.testng.annotations.Test" classpath="${run.test.classpath}"/>
+        </condition>
+        <condition property="junit+testng.available">
+            <and>
+                <istrue value="${junit.available}"/>
+                <istrue value="${testng.available}"/>
+            </and>
+        </condition>
+        <condition else="testng" property="testng.mode" value="mixed">
+            <istrue value="${junit+testng.available}"/>
+        </condition>
+        <condition else="" property="testng.debug.mode" value="-mixed">
+            <istrue value="${junit+testng.available}"/>
+        </condition>
+    </target>
+    <target name="-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
+        <fail unless="src.dir">Must set src.dir</fail>
+        <fail unless="test.src.dir">Must set test.src.dir</fail>
+        <fail unless="build.dir">Must set build.dir</fail>
+        <fail unless="dist.dir">Must set dist.dir</fail>
+        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
+        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
+        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
+        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
+        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
+        <fail unless="dist.jar">Must set dist.jar</fail>
+    </target>
+    <target name="-init-macrodef-property">
+        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${@{value}}"/>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <mkdir dir="@{apgeneratedsrcdir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <compilerarg value="-processorpath"/>
+                    <compilerarg path="@{processorpath}:${empty.dir}"/>
+                    <compilerarg line="${ap.processors.internal}"/>
+                    <compilerarg line="${annotation.processing.processor.options}"/>
+                    <compilerarg value="-s"/>
+                    <compilerarg path="@{apgeneratedsrcdir}"/>
+                    <compilerarg line="${ap.proc.none.internal}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
+        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <sequential>
+                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </depend>
+            </sequential>
+        </macrodef>
+        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <sequential>
+                <fail unless="javac.includes">Must set javac.includes</fail>
+                <pathconvert pathsep="${line.separator}" property="javac.includes.binary">
+                    <path>
+                        <filelist dir="@{destdir}" files="${javac.includes}"/>
+                    </path>
+                    <globmapper from="*.java" to="*.class"/>
+                </pathconvert>
+                <tempfile deleteonexit="true" property="javac.includesfile.binary"/>
+                <echo file="${javac.includesfile.binary}" message="${javac.includes.binary}"/>
+                <delete>
+                    <files includesfile="${javac.includesfile.binary}"/>
+                </delete>
+                <delete>
+                    <fileset file="${javac.includesfile.binary}"/>
+                </delete>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${junit.available}" name="-init-macrodef-junit-init">
+        <condition else="false" property="nb.junit.batch" value="true">
+            <and>
+                <istrue value="${junit.available}"/>
+                <not>
+                    <isset property="test.method"/>
+                </not>
+            </and>
+        </condition>
+        <condition else="false" property="nb.junit.single" value="true">
+            <and>
+                <istrue value="${junit.available}"/>
+                <isset property="test.method"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-init-test-properties">
+        <property name="test.binaryincludes" value="&lt;nothing&gt;"/>
+        <property name="test.binarytestincludes" value=""/>
+        <property name="test.binaryexcludes" value=""/>
+    </target>
+    <target if="${nb.junit.single}" name="-init-macrodef-junit-single" unless="${nb.junit.batch}">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-batch" unless="${nb.junit.single}">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <batchtest todir="${build.test.results.dir}">
+                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+                            <filename name="@{testincludes}"/>
+                        </fileset>
+                        <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+                            <filename name="${test.binarytestincludes}"/>
+                        </fileset>
+                    </batchtest>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-init,-init-macrodef-junit-single, -init-macrodef-junit-batch" if="${junit.available}" name="-init-macrodef-junit"/>
+    <target if="${testng.available}" name="-init-macrodef-testng">
+        <macrodef name="testng" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}">
+                    <isset property="test.method"/>
+                </condition>
+                <union id="test.set">
+                    <fileset dir="${test.src.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}">
+                        <filename name="@{testincludes}"/>
+                    </fileset>
+                </union>
+                <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
+                <testng classfilesetref="test.set" failureProperty="tests.failed" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="JGrid" testname="TestNG tests" workingDir="${work.dir}">
+                    <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
+                    <propertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </propertyset>
+                    <customize/>
+                </testng>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-test-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <echo>No tests executed.</echo>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit" if="${junit.available}" name="-init-macrodef-junit-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:junit excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng" if="${testng.available}" name="-init-macrodef-testng-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:testng excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:testng>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-test-impl,-init-macrodef-junit-impl,-init-macrodef-testng-impl" name="-init-macrodef-test">
+        <macrodef name="test" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <sequential>
+                <j2seproject3:test-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize>
+                        <classpath>
+                            <path path="${run.test.classpath}"/>
+                        </classpath>
+                        <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                        <jvmarg line="${run.jvmargs}"/>
+                        <jvmarg line="${run.jvmargs.ide}"/>
+                    </customize>
+                </j2seproject3:test-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${junit.available}" name="-init-macrodef-junit-debug" unless="${nb.junit.batch}">
+        <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-debug-batch">
+        <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <batchtest todir="${build.test.results.dir}">
+                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+                            <filename name="@{testincludes}"/>
+                        </fileset>
+                        <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+                            <filename name="${test.binarytestincludes}"/>
+                        </fileset>
+                    </batchtest>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-debug,-init-macrodef-junit-debug-batch" if="${junit.available}" name="-init-macrodef-junit-debug-impl">
+        <macrodef name="test-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:junit-debug excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:junit-debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${testng.available}" name="-init-macrodef-testng-debug">
+        <macrodef name="testng-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <element name="customize2" optional="true"/>
+            <sequential>
+                <condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
+                    <isset property="test.method"/>
+                </condition>
+                <condition else="-suitename JGrid -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
+                    <matches pattern=".*\.xml" string="@{testClass}"/>
+                </condition>
+                <delete dir="${build.test.results.dir}" quiet="true"/>
+                <mkdir dir="${build.test.results.dir}"/>
+                <j2seproject3:debug classname="org.testng.TestNG" classpath="${debug.test.classpath}">
+                    <customize>
+                        <customize2/>
+                        <jvmarg value="-ea"/>
+                        <arg line="${testng.debug.mode}"/>
+                        <arg line="-d ${build.test.results.dir}"/>
+                        <arg line="-listener org.testng.reporters.VerboseReporter"/>
+                        <arg line="${testng.cmd.args}"/>
+                    </customize>
+                </j2seproject3:debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng-debug" if="${testng.available}" name="-init-macrodef-testng-debug-impl">
+        <macrodef name="testng-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <element implicit="true" name="customize2" optional="true"/>
+            <sequential>
+                <j2seproject3:testng-debug testClass="@{testClass}" testMethod="@{testMethod}">
+                    <customize2/>
+                </j2seproject3:testng-debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-debug-impl" if="${junit.available}" name="-init-macrodef-test-debug-junit">
+        <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <sequential>
+                <j2seproject3:test-debug-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize>
+                        <classpath>
+                            <path path="${run.test.classpath}"/>
+                        </classpath>
+                        <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                        <jvmarg line="${run.jvmargs}"/>
+                        <jvmarg line="${run.jvmargs.ide}"/>
+                    </customize>
+                </j2seproject3:test-debug-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng-debug-impl" if="${testng.available}" name="-init-macrodef-test-debug-testng">
+        <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <sequential>
+                <j2seproject3:testng-debug-impl testClass="@{testClass}" testMethod="@{testMethod}">
+                    <customize2>
+                        <syspropertyset>
+                            <propertyref prefix="test-sys-prop."/>
+                            <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                        </syspropertyset>
+                    </customize2>
+                </j2seproject3:testng-debug-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-test-debug-junit,-init-macrodef-test-debug-testng" name="-init-macrodef-test-debug"/>
+    <!--
+                pre NB7.2 profiling section; consider it deprecated
+            -->
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check" if="profiler.info.jvmargs.agent" name="profile-init"/>
+    <target if="profiler.info.jvmargs.agent" name="-profile-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="profiler.info.jvmargs.agent" name="-profile-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="profiler.info.jvmargs.agent" name="-profile-init-macrodef-profile">
+        <macrodef name="resolve">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${env.@{value}}"/>
+            </sequential>
+        </macrodef>
+        <macrodef name="profile">
+            <attribute default="${main.class}" name="classname"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property environment="env"/>
+                <resolve name="profiler.current.path" value="${profiler.info.pathvar}"/>
+                <java classname="@{classname}" dir="${profiler.info.dir}" fork="true" jvm="${profiler.info.jvm}">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="${profiler.info.jvmargs.agent}"/>
+                    <jvmarg line="${profiler.info.jvmargs}"/>
+                    <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+                    <arg line="${application.args}"/>
+                    <classpath>
+                        <path path="${run.classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile" if="profiler.info.jvmargs.agent" name="-profile-init-check">
+        <fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
+        <fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
+    </target>
+    <!--
+                end of pre NB7.2 profiling section
+            -->
+    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
+        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="name"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <attribute default="" name="stopclassname"/>
+            <sequential>
+                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </nbjpdastart>
+            </sequential>
+        </macrodef>
+        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${build.classes.dir}" name="dir"/>
+            <sequential>
+                <nbjpdareload>
+                    <fileset dir="@{dir}" includes="${fix.classes}">
+                        <include name="${fix.includes}*.class"/>
+                    </fileset>
+                </nbjpdareload>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-debug-args">
+        <property name="version-output" value="java version &quot;${ant.java.version}"/>
+        <condition property="have-jdk-older-than-1.4">
+            <or>
+                <contains string="${version-output}" substring="java version &quot;1.0"/>
+                <contains string="${version-output}" substring="java version &quot;1.1"/>
+                <contains string="${version-output}" substring="java version &quot;1.2"/>
+                <contains string="${version-output}" substring="java version &quot;1.3"/>
+            </or>
+        </condition>
+        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
+            <istrue value="${have-jdk-older-than-1.4}"/>
+        </condition>
+        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+            <os family="windows"/>
+        </condition>
+        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+            <isset property="debug.transport"/>
+        </condition>
+    </target>
+    <target depends="-init-debug-args" name="-init-macrodef-debug">
+        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <jvmarg line="${run.jvmargs.ide}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-java">
+        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${run.classpath}" name="classpath"/>
+            <attribute default="jvm" name="jvm"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <jvmarg line="${run.jvmargs.ide}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-copylibs">
+        <macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${manifest.file}" name="manifest"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+                <pathconvert property="run.classpath.without.build.classes.dir">
+                    <path path="${run.classpath}"/>
+                    <map from="${build.classes.dir.resolved}" to=""/>
+                </pathconvert>
+                <pathconvert pathsep=" " property="jar.classpath">
+                    <path path="${run.classpath.without.build.classes.dir}"/>
+                    <chainedmapper>
+                        <flattenmapper/>
+                        <filtermapper>
+                            <replacestring from=" " to="%20"/>
+                        </filtermapper>
+                        <globmapper from="*" to="lib/*"/>
+                    </chainedmapper>
+                </pathconvert>
+                <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
+                <copylibs compress="${jar.compress}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" rebase="${copylibs.rebase}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
+                    <fileset dir="${build.classes.dir}"/>
+                    <manifest>
+                        <attribute name="Class-Path" value="${jar.classpath}"/>
+                        <customize/>
+                    </manifest>
+                </copylibs>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-presetdef-jar">
+        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <jar compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}">
+                <j2seproject1:fileset dir="${build.classes.dir}"/>
+            </jar>
+        </presetdef>
+    </target>
+    <target name="-init-ap-cmdline-properties">
+        <property name="annotation.processing.enabled" value="true"/>
+        <property name="annotation.processing.processors.list" value=""/>
+        <property name="annotation.processing.processor.options" value=""/>
+        <property name="annotation.processing.run.all.processors" value="true"/>
+        <property name="javac.processorpath" value="${javac.classpath}"/>
+        <property name="javac.test.processorpath" value="${javac.test.classpath}"/>
+        <condition property="ap.supported.internal" value="true">
+            <not>
+                <matches pattern="1\.[0-5](\..*)?" string="${javac.source}"/>
+            </not>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-ap-cmdline-supported">
+        <condition else="" property="ap.processors.internal" value="-processor ${annotation.processing.processors.list}">
+            <isfalse value="${annotation.processing.run.all.processors}"/>
+        </condition>
+        <condition else="" property="ap.proc.none.internal" value="-proc:none">
+            <isfalse value="${annotation.processing.enabled}"/>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
+        <property name="ap.cmd.line.internal" value=""/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-test,-init-macrodef-test-debug,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
+    <!--
+                ===================
+                COMPILATION SECTION
+                ===================
+            -->
+    <target name="-deps-jar-init" unless="built-jar.properties">
+        <property location="${build.dir}/built-jar.properties" name="built-jar.properties"/>
+        <delete file="${built-jar.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
+        <echo level="warn" message="Cycle detected: JGrid was already built"/>
+    </target>
+    <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-jar.properties}" verbose="false"/>
+        <property file="${built-jar.properties}" prefix="already.built.jar."/>
+        <antcall target="-warn-already-built-jar"/>
+        <propertyfile file="${built-jar.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+    </target>
+    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
+    <target depends="init" name="-check-automatic-build">
+        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
+    </target>
+    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
+        <antcall target="clean"/>
+    </target>
+    <target depends="init,deps-jar" name="-pre-pre-compile">
+        <mkdir dir="${build.classes.dir}"/>
+    </target>
+    <target name="-pre-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-depend">
+        <pathconvert property="build.generated.subdirs">
+            <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="*"/>
+            </dirset>
+        </pathconvert>
+        <j2seproject3:depend srcdir="${src.dir}:${build.generated.subdirs}"/>
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
+        <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
+        <copy todir="${build.classes.dir}">
+            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target if="has.persistence.xml" name="-copy-persistence-xml">
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy todir="${build.classes.dir}/META-INF">
+            <fileset dir="${meta.inf.dir}" includes="persistence.xml orm.xml"/>
+        </copy>
+    </target>
+    <target name="-post-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
+    <target name="-pre-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile/>
+        <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}"/>
+    </target>
+    <target name="-post-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
+    <!--
+                ====================
+                JAR BUILDING SECTION
+                ====================
+            -->
+    <target depends="init" name="-pre-pre-jar">
+        <dirname file="${dist.jar}" property="dist.jar.dir"/>
+        <mkdir dir="${dist.jar.dir}"/>
+    </target>
+    <target name="-pre-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive" name="-do-jar-without-manifest" unless="manifest.available-mkdist.available">
+        <j2seproject1:jar/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class-mkdist.available">
+        <j2seproject1:jar manifest="${manifest.file}"/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
+        <j2seproject1:jar manifest="${manifest.file}">
+            <j2seproject1:manifest>
+                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
+            </j2seproject1:manifest>
+        </j2seproject1:jar>
+        <echo level="info">To run this application from the command line without Ant, try:</echo>
+        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <pathconvert property="run.classpath.with.dist.jar">
+            <path path="${run.classpath}"/>
+            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
+        </pathconvert>
+        <echo level="info">java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
+    </target>
+    <target depends="init" if="do.archive" name="-do-jar-with-libraries-create-manifest" unless="manifest.available">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <touch file="${tmp.manifest.file}" verbose="false"/>
+    </target>
+    <target depends="init" if="do.archive+manifest.available" name="-do-jar-with-libraries-copy-manifest">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <copy file="${manifest.file}" tofile="${tmp.manifest.file}"/>
+    </target>
+    <target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+main.class.available" name="-do-jar-with-libraries-set-main">
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="Main-Class" value="${main.class}"/>
+        </manifest>
+    </target>
+    <target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+splashscreen.available" name="-do-jar-with-libraries-set-splashscreen">
+        <basename file="${application.splash}" property="splashscreen.basename"/>
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy failonerror="false" file="${application.splash}" todir="${build.classes.dir}/META-INF"/>
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
+        </manifest>
+    </target>
+    <target depends="init,-init-macrodef-copylibs,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen" if="do.mkdist" name="-do-jar-with-libraries-pack">
+        <j2seproject3:copylibs manifest="${tmp.manifest.file}"/>
+        <echo level="info">To run this application from the command line without Ant, try:</echo>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <echo level="info">java -jar "${dist.jar.resolved}"</echo>
+    </target>
+    <target depends="-do-jar-with-libraries-pack" if="do.archive" name="-do-jar-with-libraries-delete-manifest">
+        <delete>
+            <fileset file="${tmp.manifest.file}"/>
+        </delete>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen,-do-jar-with-libraries-pack,-do-jar-with-libraries-delete-manifest" name="-do-jar-with-libraries"/>
+    <target name="-post-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
+    <!--
+                =================
+                EXECUTION SECTION
+                =================
+            -->
+    <target depends="init,compile" description="Run a main class." name="run">
+        <j2seproject1:java>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <target name="-do-not-recompile">
+        <property name="javac.includes.binary" value=""/>
+    </target>
+    <target depends="init,compile-single" name="run-single">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}"/>
+    </target>
+    <target depends="init,compile-test-single" name="run-test-with-main">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
+    </target>
+    <!--
+                =================
+                DEBUGGING SECTION
+                =================
+            -->
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
+        <j2seproject1:nbjpdastart name="${debug.class}"/>
+    </target>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
+    </target>
+    <target depends="init,compile" name="-debug-start-debuggee">
+        <j2seproject3:debug>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
+        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
+    </target>
+    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}"/>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
+    <target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
+    <target depends="init" name="-pre-debug-fix">
+        <fail unless="fix.includes">Must set fix.includes</fail>
+        <property name="javac.includes" value="${fix.includes}.java"/>
+    </target>
+    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
+        <j2seproject1:nbjpdareload/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
+    <!--
+                =================
+                PROFILING SECTION
+                =================
+            -->
+    <!--
+                pre NB7.2 profiler integration
+            -->
+    <target depends="profile-init,compile" description="Profile a project in the IDE." if="profiler.info.jvmargs.agent" name="-profile-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile/>
+    </target>
+    <target depends="profile-init,compile-single" description="Profile a selected class in the IDE." if="profiler.info.jvmargs.agent" name="-profile-single-pre72">
+        <fail unless="profile.class">Must select one file in the IDE or set profile.class</fail>
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="${profile.class}"/>
+    </target>
+    <target depends="profile-init,compile-single" if="profiler.info.jvmargs.agent" name="-profile-applet-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </profile>
+    </target>
+    <target depends="profile-init,compile-test-single" if="profiler.info.jvmargs.agent" name="-profile-test-single-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <junit dir="${profiler.info.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" jvm="${profiler.info.jvm}" showoutput="true">
+            <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+            <jvmarg value="${profiler.info.jvmargs.agent}"/>
+            <jvmarg line="${profiler.info.jvmargs}"/>
+            <test name="${profile.class}"/>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+            <syspropertyset>
+                <propertyref prefix="test-sys-prop."/>
+                <mapper from="test-sys-prop.*" to="*" type="glob"/>
+            </syspropertyset>
+            <formatter type="brief" usefile="false"/>
+            <formatter type="xml"/>
+        </junit>
+    </target>
+    <!--
+                end of pre NB72 profiling section
+            -->
+    <target if="netbeans.home" name="-profile-check">
+        <condition property="profiler.configured">
+            <or>
+                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-agentpath:"/>
+                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-javaagent:"/>
+            </or>
+        </condition>
+    </target>
+    <target depends="-profile-check,-profile-pre72" description="Profile a project in the IDE." if="profiler.configured" name="profile" unless="profiler.info.jvmargs.agent">
+        <startprofiler/>
+        <antcall target="run"/>
+    </target>
+    <target depends="-profile-check,-profile-single-pre72" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-single" unless="profiler.info.jvmargs.agent">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <startprofiler/>
+        <antcall target="run-single"/>
+    </target>
+    <target depends="-profile-test-single-pre72" description="Profile a selected test in the IDE." name="profile-test-single"/>
+    <target depends="-profile-check" description="Profile a selected test in the IDE." if="profiler.configured" name="profile-test" unless="profiler.info.jvmargs">
+        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+        <startprofiler/>
+        <antcall target="test-single"/>
+    </target>
+    <target depends="-profile-check" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-test-with-main">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <startprofiler/>
+        <antcal target="run-test-with-main"/>
+    </target>
+    <target depends="-profile-check,-profile-applet-pre72" if="profiler.configured" name="profile-applet" unless="profiler.info.jvmargs.agent">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <startprofiler/>
+        <antcall target="run-applet"/>
+    </target>
+    <!--
+                ===============
+                JAVADOC SECTION
+                ===============
+            -->
+    <target depends="init" if="have.sources" name="-javadoc-build">
+        <mkdir dir="${dist.javadoc.dir}"/>
+        <condition else="" property="javadoc.endorsed.classpath.cmd.line.arg" value="-J${endorsed.classpath.cmd.line.arg}">
+            <and>
+                <isset property="endorsed.classpath.cmd.line.arg"/>
+                <not>
+                    <equals arg1="${endorsed.classpath.cmd.line.arg}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
+            <classpath>
+                <path path="${javac.classpath}"/>
+            </classpath>
+            <fileset dir="${src.dir}" excludes="*.java,${excludes}" includes="${includes}">
+                <filename name="**/*.java"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/*.java"/>
+                <exclude name="*.java"/>
+            </fileset>
+            <arg line="${javadoc.endorsed.classpath.cmd.line.arg}"/>
+        </javadoc>
+        <copy todir="${dist.javadoc.dir}">
+            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/doc-files/**"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/doc-files/**"/>
+            </fileset>
+        </copy>
+    </target>
+    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
+        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
+    </target>
+    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
+    <!--
+                =========================
+                TEST COMPILATION SECTION
+                =========================
+            -->
+    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
+        <mkdir dir="${build.test.classes.dir}"/>
+    </target>
+    <target name="-pre-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-test-depend">
+        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
+    </target>
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" processorpath="${javac.test.processorpath}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
+    <target name="-pre-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" processorpath="${javac.test.processorpath}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
+    <!--
+                =======================
+                TEST EXECUTION SECTION
+                =======================
+            -->
+    <target depends="init" if="have.tests" name="-pre-test-run">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
+        <j2seproject3:test testincludes="**/*Test.java"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init" if="have.tests" name="test-report"/>
+    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
+    <target depends="init" if="have.tests" name="-pre-test-run-single">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
+        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+        <j2seproject3:test excludes="" includes="${test.includes}" testincludes="${test.includes}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single-method">
+        <fail unless="test.class">Must select some files in the IDE or set test.class</fail>
+        <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+        <j2seproject3:test excludes="" includes="${javac.includes}" testincludes="${test.class}" testmethods="${test.method}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method" if="have.tests" name="-post-test-run-single-method">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method,-post-test-run-single-method" description="Run single unit test." name="test-single-method"/>
+    <!--
+                =======================
+                TEST DEBUGGING SECTION
+                =======================
+            -->
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test">
+        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+        <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testincludes="${javac.includes}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test-method">
+        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+        <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+        <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testMethod="${test.method}" testincludes="${test.class}" testmethods="${test.method}"/>
+    </target>
+    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
+    <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test-method" name="debug-test-method"/>
+    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
+        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
+    <!--
+                =========================
+                APPLET EXECUTION SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" name="run-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject1:java classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <!--
+                =========================
+                APPLET DEBUGGING  SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject3:debug classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
+    <!--
+                ===============
+                CLEANUP SECTION
+                ===============
+            -->
+    <target name="-deps-clean-init" unless="built-clean.properties">
+        <property location="${build.dir}/built-clean.properties" name="built-clean.properties"/>
+        <delete file="${built-clean.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
+        <echo level="warn" message="Cycle detected: JGrid was already built"/>
+    </target>
+    <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-clean.properties}" verbose="false"/>
+        <property file="${built-clean.properties}" prefix="already.built.clean."/>
+        <antcall target="-warn-already-built-clean"/>
+        <propertyfile file="${built-clean.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+    </target>
+    <target depends="init" name="-do-clean">
+        <delete dir="${build.dir}"/>
+        <delete dir="${dist.dir}" followsymlinks="false" includeemptydirs="true"/>
+    </target>
+    <target name="-post-clean">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
+    <target name="-check-call-dep">
+        <property file="${call.built.properties}" prefix="already.built."/>
+        <condition property="should.call.dep">
+            <and>
+                <not>
+                    <isset property="already.built.${call.subproject}"/>
+                </not>
+                <available file="${call.script}"/>
+            </and>
+        </condition>
+    </target>
+    <target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
+        <ant antfile="${call.script}" inheritall="false" target="${call.target}">
+            <propertyset>
+                <propertyref prefix="transfer."/>
+                <mapper from="transfer.*" to="*" type="glob"/>
+            </propertyset>
+        </ant>
+    </target>
+</project>

+ 8 - 0
nbproject/genfiles.properties

@@ -0,0 +1,8 @@
+build.xml.data.CRC32=56c275ac
+build.xml.script.CRC32=491aa4f2
+build.xml.stylesheet.CRC32=28e38971@1.56.1.46
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=56c275ac
+nbproject/build-impl.xml.script.CRC32=ea9a3aac
+nbproject/build-impl.xml.stylesheet.CRC32=c6d2a60f@1.56.1.46

+ 0 - 0
nbproject/private/config.properties


+ 6 - 0
nbproject/private/private.properties

@@ -0,0 +1,6 @@
+compile.on.save=true
+do.depend=false
+do.jar=true
+javac.debug=true
+javadoc.preview=true
+user.properties.file=C:\\Users\\txijian\\.netbeans\\7.1.2\\build.properties

+ 5 - 0
nbproject/private/private.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
+    <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/1"/>
+    <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
+</project-private>

+ 74 - 0
nbproject/project.properties

@@ -0,0 +1,74 @@
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.processors.list=
+annotation.processing.run.all.processors=true
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+application.title=JGrid
+application.vendor=txijian
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+    ${run.classpath}
+debug.test.classpath=\
+    ${run.test.classpath}
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/JGrid.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+endorsed.classpath=
+excludes=
+includes=**
+jar.compress=false
+javac.classpath=\
+    ${libs.Oracle_JDBC.classpath}:\
+    ${libs.javaee-api-6.0.classpath}:\
+    ${libs.ApacheXML.classpath}
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.processorpath=\
+    ${javac.classpath}
+javac.source=1.6
+javac.target=1.6
+javac.test.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}
+javac.test.processorpath=\
+    ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=true
+platform.active=default_platform
+run.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project.
+# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
+# To set system properties for unit tests define test-sys-prop.name=value:
+run.jvmargs=
+run.test.classpath=\
+    ${javac.test.classpath}:\
+    ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=src
+test.src.dir=test

+ 15 - 0
nbproject/project.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.java.j2seproject</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
+            <name>JGrid</name>
+            <source-roots>
+                <root id="src.dir"/>
+            </source-roots>
+            <test-roots>
+                <root id="test.src.dir"/>
+            </test-roots>
+        </data>
+    </configuration>
+</project>

+ 1953 - 0
src/com/tang/taglib/grid/JGrid.java

@@ -0,0 +1,1953 @@
+/*
+Copyright 2009 Xijian (Jim) Tang
+This version of Software is free for using in non-commercial applications. For commercial use please contact txijian@yahoo.com to obtain license
+*/
+
+package com.tang.taglib.grid;
+
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.jsp.tagext.*;
+import javax.servlet.jsp.*;
+import java.io.PrintWriter;
+import java.util.*;
+import java.sql.*;
+import javax.sql.*;
+import javax.naming.*;
+import java.lang.reflect.*;
+
+
+public class JGrid extends TagSupport 
+{
+  private PageContext pageContext; 
+  
+  private int totalColNumber=0;
+  private int totalRowNumber=0;
+  private int pageRowNumber=0;
+  
+  private List resultSetArray = null;
+  
+  /*
+  tag attribute: queryString
+  */
+  private String queryString = "";
+  /*
+  tag attribute: dataSource
+  */
+  private String dataSource = "";
+  
+  private String[] captions = null;
+  private String[] sortFields = null;
+  private String[] fieldsWidth = null;
+  
+  /*
+  tag attribute: gridRows
+  */
+  private int gridRows = 15;
+  /*
+  tag attribute: changeRows
+  */
+  private boolean changeRows = true;
+  /*
+  tag attribute: totalSize
+  */
+  private int totalSize = -1;
+  
+  /*
+  tag attribute: pageName
+  */
+  private String pageName = "";
+  
+  /*
+  tag attribute: showCaption
+  */
+  private boolean showCaption = true;
+  /*
+  tag attribute: tableSetting
+  */
+  private String tableSetting = "<TABLE cellSpacing=1 cellPadding=1 bgcolor='white' border=1 style='WIDTH: 98%; HEIGHT: 50px'>";
+  /*
+  tag attribute: headClass
+  */
+  private String headClass = "";
+  /*
+  tag attribute: rowClass
+  */
+  private String rowClass = "";
+  /*
+  tag attribute: pageClass
+  */
+  private String pageClass = "";
+  /*
+  tag attribute: refresh
+  */
+  private boolean refresh = true;
+  
+  /*
+  tag attribute: name
+  */
+  private String name = "";
+  
+  private String emptyText = "无数据"; //"No Record Found";
+  private String altRowStyle = "BACKGROUND-COLOR: #eeeeee";
+  private String border = "1";
+  private String cellSpacing = "1";
+  private String cellPadding = "1";
+  private String bgcolor = "white";
+  private String style = "WIDTH: 100%; HEIGHT: 50px";
+  
+  //for paging
+  private int currPageNum = 0;
+  private int totalPageNum = 0;
+  private String pageType = "word";
+  private String PageFirstText = "第一页"; //First";
+  private String PageLastText = "最后一页"; //"Last";
+  private String PagePrevText = "上一页"; //Prev";
+  private String PageNextText = "下一页"; //Next";
+  private String PageText = "页"; //Page:";
+  
+  private String PageNumber="";
+  private String wordPageNav1="";
+  private String wordPageNav2="";
+  private String wordPageNav3="";
+  private String numPageNav1="";
+  private String numPageNav2="";
+  private String numPageNav3="";
+  private String changeRowsNum = "";
+  
+  private String sortMethod = "server";
+
+//new add
+  private String[][] headers = null;
+  private String[][] columns = null;
+  
+  private String[] fieldNames = null;
+  private String[] columnTypes = null;
+  private boolean[] columnSetup = null;
+  private String[] columnAttributes = null;
+  private String[] columnInnerValues = null;
+  private boolean treeGrid = false;
+  private boolean treeIcon = true;
+  private int treeStatus = 0;
+  
+  private int keyIndex = -1;
+  private String keyFieldName = "";
+  private int parentKeyIndex = -1;
+  private String parentKeyFieldName = "";
+ 
+  private boolean bPrintNavigation = true;
+  
+  public void setHeaders(String[][] headers)
+  {
+    this.headers = headers;
+  }
+
+  public String[][] getHeaders()
+  {
+    return this.headers;
+  }
+
+  public void setColumns(String[][] columns)
+  {
+    this.columns = columns;
+  }
+
+  public String[][] getColumns()
+  {
+    return this.columns;
+  }
+  
+  private void setUpIniNew(){ 
+    int i;  
+    
+    //  meaning              caption,    sort,   width,    column index/name 
+    //String[][] sHeaders = {{"STATUS",   "1",   "12%",      "0"},         {"NOTIFICATION SUBJECT","1","58%", "first_line"},{"RECEIVED", null, "10%"},{"DUE DATE","1", "10%", "3"},{"CHART","1","10%","4"}};
+    // caption: can be null or "", show as "&nbsp;". 
+    // sort: null or "", or "0" takes no sorting, any other means sorting
+    // width: can be px number or *%. null or "" takes no setting, using html default.
+    // column index/name: null, "" takes sHeaders array index. Can be resultset field index/name or any other name, but must be consistent with sColumns's column index/name, otherwise empty
+    //  meaning          column index/name,  column type,    attributes,      innerValues
+    //String[][] sColumns =   {{"0",           "span",    "class='fontbold'",   "${0}"},     {"first_line","tree","class='fontbold'","${5}"},{"2","span","","${2}'"}};
+    // column index/name: Can be resultset field index/name or any other name, must be consistent with sHeaders's column index/name, otherwise no effect.
+    // if the column index or name is set null or "", that means all other columns except the columns already set have this same column setting. Hence this kind of column set should be last one.
+    // column type: null or "" takes plain text. Values are : radio, checkbox, button, submit, text, a, url, image, img, select, div, span, tree
+    // The value of 'url' is the same as 'a', only 'tree' is special. Any other value takes plain text.
+    // attributes: be used as column type tag's attributes. Can be null or "". Can take ${x} or %{x} variable values inside. 
+    // innerValues: be used as mid value between column type tags. null value or missing takes resultset field value whose index or name is specified in column index/name.
+    // "" value means nothing is showed up between column type tags. Can take ${x} or %{x} variable values inside.
+    //
+    // variable x in ${x}, %{x} should be resultset field index/name. ${x} takes the original value of x field and %{x} takes the display value of x field.
+     //String[][] sColumns =   {{"0",  "tree",    "key='1' parentKey='5' status='1' icon='0' class='font'",   "${0}"},
+    // 'tree' column attributes: there are several special attributes inside: 'key', 'parentkey', status, 'icon', 'class'.
+    // 'key' and 'parentkey' should be resultset field index/name. They are used to order tree. 'icon' value is 0 (no icon) or 1 (show icon), can be missing. 
+    // 'status' value is 0 (collapse tree), 1 (expand tree). 
+    // One grid only allowed to have one tree column. If more than one, only take the first one, rest will be neglected.
+    
+    this.totalColNumber=this.headers.length;
+    this.captions = new String[this.totalColNumber];
+    this.sortFields = new String[this.totalColNumber];
+    this.fieldsWidth = new String[this.totalColNumber];
+    this.fieldNames = new String[this.totalColNumber];
+    this.columnTypes = new String[this.totalColNumber];
+    this.columnSetup = new boolean[this.totalColNumber];
+    this.columnAttributes = new String[this.totalColNumber];
+    this.columnInnerValues = new String[this.totalColNumber];
+    
+    for(i=0; i<this.totalColNumber;i++)
+    { 
+      this.captions[i] = "";
+      this.sortFields[i] = "";
+      this.fieldsWidth[i] = "";
+      this.fieldNames[i] = String.valueOf(i);
+      this.columnTypes[i] = "";
+      this.columnSetup[i] = false;
+      this.columnAttributes[i] = "";
+      this.columnInnerValues[i] = "%{self}";
+    }
+    
+    //parse the headers string array
+    for(i=0; i<this.totalColNumber;i++)
+    { 
+      if(this.headers[i] != null)
+      {
+        for(int j=0; j<headers[i].length; j++)
+        {
+          if(j==0 && headers[i][j] != null)
+          {
+            this.captions[i] = headers[i][j];
+          }
+          else if(j==1 && headers[i][j] != null)
+          {
+            this.sortFields[i] = headers[i][j];
+          }
+          else if(j==2 && headers[i][j] != null)
+          {
+            this.fieldsWidth[i] = headers[i][j];
+          }
+          else if(j==3 && headers[i][j] != null)
+          {
+            this.fieldNames[i] = headers[i][j];
+          }
+        }
+      }
+    }
+
+    //parse the columns string array
+    if(this.columns != null)
+    {
+      for(i=0; i<this.columns.length; i++)
+      { 
+        if(this.columns[i] != null)
+        {
+          int j = 0, index = -1;
+          String temp = "";
+          if(j==0 && columns[i][j] != null && !columns[i][j].equals(""))
+          {
+            temp = columns[i][j];
+            
+            //find index from fieldNames
+            for(int k=0; k<this.fieldNames.length; k++)
+            {
+              if(this.fieldNames[k].equals(temp))
+              {
+                index = k;
+                this.columnSetup[k] = true;
+                for( j=1; j<columns[i].length; j++)
+                {
+                  
+                  if(j==1 && columns[i][j] != null)
+                  {
+                    this.columnTypes[index] = columns[i][j];
+                  }
+                  else if(j==2 && columns[i][j] != null)
+                  {
+                    this.columnAttributes[index] = columns[i][j];
+                  }
+                  else if(j==3 && columns[i][j] != null)
+                  {
+                    this.columnInnerValues[index] = columns[i][j];
+                  }
+                }
+                
+              }
+            }
+            //for end
+          }
+          else
+          {
+            //set for all other columns, must be last column
+            for(int k=0; k<this.fieldNames.length; k++)
+            {
+              if(!this.columnSetup[k])
+              {
+                
+                for( j=1; j<columns[i].length; j++)
+                {
+                  
+                  if(j==1 && columns[i][j] != null)
+                  {
+                    this.columnTypes[k] = columns[i][j];
+                  }
+                  else if(j==2 && columns[i][j] != null)
+                  {
+                    this.columnAttributes[k] = columns[i][j];
+                  }
+                  else if(j==3 && columns[i][j] != null)
+                  {
+                    this.columnInnerValues[k] = columns[i][j];
+                  }
+                }
+                
+              }
+            }
+          }
+ 
+        }
+      }
+    }
+    
+    //check tree column and get its attributes
+    for(i=0; i<this.columnTypes.length; i++)
+    { 
+      if(this.columnTypes[i].equalsIgnoreCase("tree"))
+      {
+        this.treeGrid = true;
+        String attribute = this.columnAttributes[i];
+        String tempAttribute = attribute.toLowerCase();
+        String sTemp = getAttributeValue(tempAttribute, "key");
+        if(!sTemp.equals(""))
+        {
+          try{
+            int iIndex = Integer.parseInt(sTemp);
+            this.keyIndex = iIndex;
+          }
+          catch(NumberFormatException ne)
+          {
+            //not number, should be field name, conver to index
+            this.keyFieldName = sTemp;
+          }
+        }
+        sTemp = getAttributeValue(tempAttribute, "parentkey");
+        if(!sTemp.equals(""))
+        {
+          try{
+            int iIndex = Integer.parseInt(sTemp);
+            this.parentKeyIndex = iIndex;
+          }
+          catch(NumberFormatException ne)
+          {
+            //not number, should be field name, conver to index
+            this.parentKeyFieldName = sTemp;
+          }
+        }
+        
+        sTemp = getAttributeValue(tempAttribute, "icon");
+        if(!sTemp.equals("")) 
+        {
+          try{
+            int iIndex = Integer.parseInt(sTemp);
+            if(iIndex != 0)
+              this.treeIcon = true;
+            else
+              this.treeIcon = false;
+          }
+          catch(NumberFormatException ne)
+          {
+            //not number, set as default value
+            this.treeIcon = true;
+          }
+        }
+        
+        sTemp = getAttributeValue(tempAttribute, "status");
+        if(!sTemp.equals("")) 
+        {
+          try{
+            int iIndex = Integer.parseInt(sTemp);
+            if(iIndex != 0)
+              this.treeStatus = 1;
+            else
+              this.treeStatus = 0;
+          }
+          catch(NumberFormatException ne)
+          {
+            //not number, set as default value
+            this.treeStatus = 0;
+          }
+        }
+        break;
+      }
+    }
+    
+    
+  }
+  
+  private static String getAttributeValue(String attributes, String attributename)
+  {
+    if(attributes == null || attributename == null) return "";
+    String strTemp, strTemp1, strTemp2, strRest, strResult = "";
+    strTemp = attributes.toLowerCase();
+    attributename = attributename.toLowerCase();
+    int index = strTemp.indexOf(attributename);
+    int index1, index2=-1;
+    boolean bSpace = false;
+    if(index>-1) //find
+    {
+      index1 = index;
+      index = strTemp.indexOf("=", index1+attributename.length());
+      if(index>-1)
+      {
+        //check between attributename and =
+        strTemp1 = strTemp.substring(index1+attributename.length(), index);
+        strTemp1 = strTemp1.trim();
+        if(strTemp1.length()==0)
+        {
+          //try to find second =
+          index1 = index; // first = index
+          index = strTemp.indexOf("=", index+1);
+          //strTemp1 is string between =
+          if(index>-1)
+          {
+            strTemp1 = strTemp.substring(index1+1, index);
+            strRest = strTemp.substring(index);
+          }
+          else
+          { //no second =, go to all end
+            strTemp1 = strTemp.substring(index1+1);
+            strRest = "";
+          }
+          boolean bSQuote = true;
+          index = strTemp1.indexOf("'");
+          if(index == -1) 
+          {
+            index = strTemp1.indexOf("\"");
+            bSQuote = false;
+          }
+          if(index>-1) 
+          { //found ' or "
+            //check space
+            strTemp2 = strTemp1.substring(0, index);
+            if(strTemp2.trim().length()==0)
+            {
+              if(bSQuote)
+                index2 = strTemp1.indexOf("'", index+1);
+              else
+                index2 = strTemp1.indexOf("\"", index+1);
+              if(index2 > -1)
+              {//found close ' or "
+                strResult = strTemp1.substring(index+1, index2);
+                strResult = strResult.trim();
+                
+              }
+              else
+              {
+                bSpace = true;
+                
+              }
+            }
+            else
+            {
+              //cannot count as ' or "
+              bSpace = true;
+            }
+          }
+          else
+          {//no ' or "
+            bSpace = true;
+            
+            
+          }
+          
+          if(bSpace)
+          {
+            strTemp2 = strTemp1 + "A";
+            strTemp2 = strTemp2.trim(); //remove left side spaces
+            index2 = strTemp2.indexOf(" ");
+            if(index2 > -1)
+            {//found space
+              strResult = strTemp2.substring(0, index2);
+              strResult = strResult.trim();
+              
+              index2 = strTemp1.length() + 1 - strTemp2.length() + index2;
+            }
+            else
+            {//no space found
+              strResult = strTemp1;
+            }
+          }
+          
+        }
+       
+      }
+      
+    }
+    
+    return strResult;
+  }
+  
+  
+  private String getParseValueNew(String statement, SingleRecord R, int colnum)
+  {
+    String strTemp, strField, strResult = "";
+    int iIndex, iField;
+    strTemp = statement;
+    if(strTemp == null) return "";
+    
+    while(true)
+    {
+      iIndex = strTemp.indexOf("${");
+      if(iIndex>-1)
+      {
+        strResult = strResult + strTemp.substring(0, iIndex); 
+        strTemp = strTemp.substring(iIndex); 
+
+        iIndex = strTemp.indexOf("}");
+        if(iIndex>-1)
+        {
+          strField = strTemp.substring(2, iIndex); 
+          strTemp = strTemp.substring(iIndex); 
+          if(strTemp.length()>0) strTemp = strTemp.substring(1);
+          //strResult = strResult + strField; 
+          
+          if(strField.equals("self"))
+          {
+            strField = this.fieldNames[colnum];
+          }
+         
+          try{
+            iField = Integer.parseInt(strField);
+            if(iField < R.getTotalColumnNumber())
+            {
+              strResult = strResult + R.getFieldOrigialValue(iField);
+            }
+          }
+          catch(NumberFormatException ne)
+          {//not number, should be field name
+            strResult = strResult + R.getFieldOrigialValue(strField);
+          }
+          
+          
+        }
+      }
+      else
+      {
+        strResult = strResult + strTemp; 
+        break;
+      }
+        
+    }
+    
+    //for display values
+    strTemp = strResult;
+    strResult = "";
+    while(true)
+    {
+      iIndex = strTemp.indexOf("%{");
+      if(iIndex>-1)
+      {
+        strResult = strResult + strTemp.substring(0, iIndex); 
+        strTemp = strTemp.substring(iIndex); 
+
+        iIndex = strTemp.indexOf("}");
+        if(iIndex>-1)
+        {
+          strField = strTemp.substring(2, iIndex); 
+          strTemp = strTemp.substring(iIndex); 
+          if(strTemp.length()>0) strTemp = strTemp.substring(1);
+          //strResult = strResult + strField; 
+          
+          if(strField.equals("self"))
+          {
+            strField = this.fieldNames[colnum];
+          }
+         
+          try{
+            iField = Integer.parseInt(strField);
+            if(iField < R.getTotalColumnNumber())
+            {
+              strResult = strResult + R.getFieldValue(iField);
+            }
+          }
+          catch(NumberFormatException ne)
+          {//not number, should be field name
+            strResult = strResult + R.getFieldValue(strField);
+          }
+          
+          
+        }
+      }
+      else
+      {
+        strResult = strResult + strTemp; 
+        break;
+      }
+        
+    }
+    
+    //System.out.println("strResult "+strResult);
+    return strResult;
+  }
+  
+  private int getRealDataArrayIndex(SingleRecord R, int id)
+  {
+    int iIndex = id;
+    if(id < this.totalColNumber)
+    {
+      String strField = this.fieldNames[id];
+      
+      try{
+        iIndex = Integer.parseInt(strField);
+      }
+      catch(NumberFormatException ne)
+      {
+        //not number, should be field name, conver to index
+        iIndex = R.getFieldIndex(strField);
+      }
+    }
+    
+    return iIndex;
+  }
+  
+  
+  public ArrayList treeResultSetArray(List rsa)
+  {
+    ArrayList newarray = new ArrayList();
+    if(rsa == null || rsa.size() == 0) return newarray;
+    
+    String[] keyArray = new String[10];
+    int level = 0, nlevel = 0;
+    String Key = "", parentKey="";
+    
+    String[] nameId = new String[10];
+    
+    SingleRecord sr = (SingleRecord)rsa.get(0);
+    SingleRecord lastSR = null;
+   try{ 
+    //copy resultset array
+    for(int i=0; i<rsa.size(); i++)
+    {
+      sr = (SingleRecord)rsa.get(i);
+      
+      if(this.keyIndex != -1)
+        Key = sr.getFieldOrigialValue(this.keyIndex);
+      else
+        Key = sr.getFieldOrigialValue(this.keyFieldName);
+      if(this.parentKeyIndex != -1)
+        parentKey = sr.getFieldOrigialValue(this.parentKeyIndex);
+      else
+        parentKey = sr.getFieldOrigialValue(this.parentKeyFieldName);
+        
+      if(Key == null) Key = "";
+      if(parentKey == null) parentKey = "";
+      
+      if(parentKey.equals("") || i==0)
+      {
+        level = 0; 
+        nameId[level] = String.valueOf(i);
+        keyArray[level++] = Key;
+        
+      }
+      else
+      {
+        if(parentKey.equals(keyArray[level-1]))
+        {
+          nameId[level] = String.valueOf(i);
+          keyArray[level++] = Key;
+          lastSR.hasChild = true;
+        }
+        else
+        {
+          int j = -1;
+          nlevel = level-1;
+          for(j=nlevel; j>-1; j--)
+          {
+            if(parentKey.equals(keyArray[j]))
+            {
+              break;
+            }
+            level--;
+          }
+          
+          //no found
+          if(j == -1)
+            level = 0;
+          nameId[level] = String.valueOf(i);
+          keyArray[level++] = Key;
+        }
+      }
+        
+        
+      sr.level = level; 
+      
+      sr.rowID = name+"_tree";
+      for(int k=0; k<level; k++) 
+      {
+        if(k==0)
+          sr.rowID = sr.rowID + nameId[k];
+        else
+          sr.rowID = sr.rowID + "_" + nameId[k];
+        
+      }
+      
+      if(rsa.size() == 1)
+      {
+        newarray.add(sr); 
+      }
+      else
+      {
+        if(i>0 && i<=rsa.size()-1)
+          newarray.add(lastSR); 
+        //if it is last one
+        if( i==rsa.size()-1)
+          newarray.add(sr);
+      }
+      lastSR = sr;
+    }
+    
+   }
+   catch(Exception e)
+   {
+     e.printStackTrace();
+   }
+    return newarray;
+    
+  }
+  
+  
+  //new add end
+  
+
+  public void setPageContext(PageContext p) {
+    pageContext = p;
+  }
+
+  public void release() {
+  }
+
+  
+
+ private void SetUpArrayList(){   
+    try{
+      String navigation = (String)pageContext.getRequest().getParameter(name + "_CurrentPage");
+      String orderBy = (String)pageContext.getRequest().getParameter(name + "_ORDERBY");
+      
+      if (resultSetArray == null)
+      { 
+              
+        if(navigation == null && orderBy == null)
+        {
+          //String datasource = "jdbc/COVERTrain2_connDS";
+          if ((!queryString.equals("")) && !dataSource.equals(""))
+          {
+            Connection myConnection = null;
+            PreparedStatement pStmt = null;
+            try 
+            {
+              //look up the data source and get the connection to the database
+              InitialContext myInitialContext = new InitialContext();
+              //for different database connection (in data-sources.xml file) we can change here.  
+              DataSource myDataSource = (DataSource) (myInitialContext.lookup(dataSource));
+              myConnection = myDataSource.getConnection();
+              pStmt = myConnection.prepareStatement(queryString);
+              SingleRecordCreation src = new SingleRecordCreation();
+            
+              resultSetArray = src.getResultsetArrayList(pStmt);
+              
+              //new added fro tree 11/07/2006
+              if(this.treeGrid)
+                resultSetArray = treeResultSetArray(resultSetArray);
+              //new added end
+          
+//              pageContext.getSession().setAttribute(name + "_ResultArray", resultSetArray);
+            }
+            catch(Exception e) 
+            {
+              //e.printStackTrace();
+              throw new SQLException("couldn't create JDBC connection");
+              
+            }
+            finally
+            {
+              try {
+      
+                if (pStmt != null)    pStmt.close();
+                if (myConnection != null) myConnection.close();                    
+              
+              } catch (SQLException sqle) {}
+            }
+            
+          }
+            
+           // System.out.println("close Connection");
+        
+        }
+        else
+        {
+//          resultSetArray=(ArrayList)pageContext.getSession().getAttribute(name + "_ResultArray");
+        }
+    
+      }
+      
+      if (resultSetArray != null)
+      {
+          //new added fro tree 11/07/2006
+          if(this.treeGrid)
+            resultSetArray = treeResultSetArray(resultSetArray);
+          //new added end
+          
+        if (orderBy != null)  //for sorting
+        { 
+          int ascdesc = 1;
+          String AscDesc = (String)pageContext.getSession().getAttribute(name + "_ORDERBY_"+orderBy);
+          if (AscDesc != null)
+          {
+            ascdesc = -1 * Integer.parseInt(AscDesc);
+          }
+          //jimt added 11/02/2006
+          SingleRecord SR = (SingleRecord)resultSetArray.get(0);
+          int realIndex = getRealDataArrayIndex(SR, Integer.parseInt(orderBy));
+          Collections.sort(resultSetArray, new SingleRecordComparator(realIndex, ascdesc)); 
+          //Collections.sort(resultSetArray, new SingleRecordComparator(Integer.parseInt(orderBy), ascdesc)); //original one
+          //added end
+          
+          pageContext.getSession().setAttribute(name + "_ORDERBY_"+orderBy, Integer.toString(ascdesc));
+                    
+        }
+        else if(navigation != null) //for navaigation
+        {
+          
+//          resultSetArray=(ArrayList)pageContext.getSession().getAttribute(name + "_ResultArray");
+        }
+        else if(navigation == null && orderBy == null)
+        {
+                    
+//          pageContext.getSession().setAttribute(name + "_ResultArray", resultSetArray);
+          HttpServletRequest request = (HttpServletRequest)pageContext.getRequest();
+          
+          String URLqueryString = request.getQueryString();
+          if(URLqueryString != null) 
+          {
+            pageContext.getSession().setAttribute(name + "_URLQueryString", URLqueryString);
+          }
+       
+        }
+      }
+    }
+    catch(Exception e) {
+      e.printStackTrace();
+    }
+  }
+  
+  /**
+   * Method called at start of tag.
+   * @return SKIP_BODY
+   */
+  public int doStartTag() throws JspException
+  {
+    try
+    {       
+      
+      this.setUpIniNew();
+      
+      
+      this.SetUpArrayList(); 
+      
+      this.SetNavigation();
+    }
+    catch(Exception e)
+    {
+      e.printStackTrace();
+    }
+
+    return SKIP_BODY;
+  }
+
+
+  /**
+   * Method is invoked after every body evaluation to control whether the body will be reevaluated or not.
+   * @return SKIP_BODY
+   */
+  public int doAfterBody() throws JspException
+  {
+    return SKIP_BODY;
+  }
+
+
+
+  private void SetNavigation()
+  {  
+    HttpServletRequest request = (HttpServletRequest)pageContext.getRequest();
+    String pathname = request.getServletPath(); //request.getRequestURI();
+    //String path = pageContext.getServletContext().getRealPath(request.getServletPath());
+//    StringBuffer realpathname = request.getRequestURL();
+    int pos = pathname.lastIndexOf("/");
+    if (pos > -1)
+    {
+      pageName = pathname.substring(pos+1, pathname.length());
+    }
+    else
+    {
+      pageName = pathname;
+    }
+    
+    /*if(pathname.startsWith("/"))
+    {
+      pageName = pathname.substring(1, pathname.length());
+    }
+    else
+      pageName = pathname; */
+    
+//System.out.println("pathname "+pathname +" pageName "+pageName +" realpathname "+realpathname);
+//System.out.println("request.getServletPath() "+request.getServletPath());
+    String URLqueryString = (String)pageContext.getSession().getAttribute(name + "_URLQueryString");
+    if(URLqueryString != null) 
+      pageName = pageName + "?" + URLqueryString + "&";
+    else
+      pageName = pageName + "?";
+    
+    
+    String strNewRowNum = pageContext.getRequest().getParameter(name + "_NewRowNum");
+    if (strNewRowNum != null) {
+        if(strNewRowNum.equals(""))
+            gridRows = 0;
+        else {
+            gridRows = Integer.parseInt(strNewRowNum);
+        }
+        pageContext.getSession().setAttribute(name + "_gridRows", String.valueOf(gridRows));
+    } else {
+        strNewRowNum = (String)pageContext.getSession().getAttribute(name + "_gridRows");
+        if (strNewRowNum != null) {
+            if(strNewRowNum.equals(""))
+                gridRows = 0;
+            else {
+                gridRows = Integer.parseInt(strNewRowNum);
+            }
+        }
+    }
+    
+    strNewRowNum = name + "_NewRowNum=";
+    int index = pageName.indexOf(strNewRowNum);
+    if(index > -1) {
+        String temp1 = pageName.substring(0, index);
+        String temp2 = pageName.substring(index + strNewRowNum.length());
+        index = temp2.indexOf("&");
+        if(index> -1)
+            temp2 = temp2.substring(index+1);
+        else {
+            index = temp2.indexOf("?");
+            if(index> -1) temp2 = temp2.substring(index);
+        }
+        
+        pageName = temp1 + temp2;
+    } 
+    strNewRowNum = String.valueOf(gridRows);
+        
+    String strCurrentPage = pageContext.getRequest().getParameter(name + "_CurrentPage");
+    if (strCurrentPage==null) strCurrentPage="1";
+    String strPageDirection = pageContext.getRequest().getParameter(name + "_PageDirection");
+    if(strPageDirection==null) strPageDirection="1";
+    if (strCurrentPage == null) 
+      currPageNum = 1;
+    else
+      currPageNum = Integer.parseInt(strCurrentPage);
+
+    totalPageNum = 0;
+    if (resultSetArray != null)
+    {
+      int totalRecord = resultSetArray.size();
+      //new adding for having totalSize
+      if(totalSize > -1){
+          totalRecord = totalSize;
+      }
+      //
+      if (gridRows < 0) bPrintNavigation = false;
+      if (gridRows <= 0) gridRows = totalRecord;
+
+      if (totalRecord >0 )
+      {
+        totalPageNum = (int)(totalRecord / gridRows);
+        if ((totalPageNum * gridRows) < totalRecord)
+        {
+          totalPageNum = totalPageNum + 1;
+        }
+      }
+      else
+        totalPageNum = 1;
+        
+    }
+  
+    PageNumber= " "+PageText+" " + this.currPageNum + " / " +  this.totalPageNum  + "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
+    //for page type: word
+    // No previous, No First
+    wordPageNav1= "<A href='" + pageName + name + "_CurrentPage=1'></A><span style='color: gray' class='"+pageClass+"'>[&nbsp;"+PageFirstText+"&nbsp;]</span>&nbsp;&nbsp;"
+    + " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(currPageNum-1) + "'></A><span style='color: gray' class='"+pageClass+"'>[&nbsp;"+PagePrevText+"&nbsp;]</span>&nbsp;&nbsp;"
+    + " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(currPageNum+1) + "'><U class='"+pageClass+"'>[&nbsp;"+PageNextText+"&nbsp;]</U></A>&nbsp;&nbsp;"
+    + " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(totalPageNum) + "'><U class='"+pageClass+"'>[&nbsp;"+PageLastText+"&nbsp;]</U></A>" ;
+
+    // No Next, No Last
+    wordPageNav2= "<A href='" + pageName + name + "_CurrentPage=1'><U class='"+pageClass+"'>[&nbsp;"+PageFirstText+"&nbsp;]</U></A>&nbsp;&nbsp;"
+    + " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(currPageNum-1) + "'><U class='"+pageClass+"'>[&nbsp;"+PagePrevText+"&nbsp;]</U></A>&nbsp;&nbsp;"
+    + " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(currPageNum+1) + "'></A><span style='color: gray' class='"+pageClass+"'>[&nbsp;"+PageNextText+"&nbsp;]</span>&nbsp;&nbsp;"
+    + " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(totalPageNum) + "'></A><span style='color: gray' class='"+pageClass+"'>[&nbsp;"+PageLastText+"&nbsp;]</span>" ;
+    //All Have 
+    wordPageNav3= "<A href='" + pageName + name + "_CurrentPage=1'><U class='"+pageClass+"'>[&nbsp;"+PageFirstText+"&nbsp;]</U></A>&nbsp;&nbsp;"
+    + " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(currPageNum-1) + "'><U class='"+pageClass+"'>[&nbsp;"+PagePrevText+"&nbsp;]</U></A>&nbsp;&nbsp;"
+    + " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(currPageNum+1) + "'><U class='"+pageClass+"'>[&nbsp;"+PageNextText+"&nbsp;]</U></A>&nbsp;&nbsp;"
+    + " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(totalPageNum) + "'><U class='"+pageClass+"'>[&nbsp;"+PageLastText+"&nbsp;]</U></A>" ;
+
+
+    //for page type: number
+    
+    // First
+    numPageNav1= "[<A href='" + pageName + name + "_CurrentPage=1'><U>"+PageFirstText+"</U></A>&nbsp;";
+    //+ " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(currPageNum-1) + "'></A><span style='color: gray'>[&nbsp;"+PagePrevText+"&nbsp;]</span>&nbsp;&nbsp;"
+    for(int i=1; i<=totalPageNum; i++)
+    {
+      if(i==1)
+        numPageNav1=numPageNav1+ " "+ String.valueOf(i) + "&nbsp;";
+      else if(i<6 && i>1)
+        numPageNav1=numPageNav1+ " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(i) + "'&"+name + "_PageDirection=1><U>"+String.valueOf(i)+"</U></A>&nbsp;";
+      else if(i==6)
+        numPageNav1=numPageNav1+ " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(i) + "&"+name + "_PageDirection=Prev'><U>"+"..."+"</U></A>&nbsp;";
+    }
+    numPageNav1=numPageNav1+ " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(totalPageNum) + "'><U>"+PageLastText+"</U></A>]" ;
+
+    // Last
+    numPageNav2= "[<A href='" + pageName + name + "_CurrentPage=1'><U>"+PageFirstText+"</U></A>&nbsp;";
+    //+ " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(currPageNum-1) + "'>[&nbsp;"+PagePrevText+"&nbsp;]</A>&nbsp;&nbsp;"
+    for(int i=totalPageNum-6; i<=totalPageNum; i++)
+    {
+      if(i==totalPageNum-6 && i>1)
+        numPageNav2=numPageNav2+ " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(i) + "&"+name + "_PageDirection=Next'><U>"+"..."+"</U></A>&nbsp;";
+      else if(i<totalPageNum && i>0)
+        numPageNav2=numPageNav2+ " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(i) + "&"+name + "_PageDirection="+String.valueOf(totalPageNum-6)+"'><U>"+String.valueOf(i)+"</U></A>&nbsp;";
+      else if(i==totalPageNum && i>0)
+        numPageNav2=numPageNav2+ " "+String.valueOf(i)+"&nbsp;";
+    }
+    numPageNav2=numPageNav2+ " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(totalPageNum) + "'><U>"+PageLastText+"</U></A>]" ;
+
+    // middle 
+    int iBegan = 1;
+    numPageNav3= "[<A href='" + pageName + name + "_CurrentPage=1'><U>"+PageFirstText+"</U></A>&nbsp;";
+    //+ " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(currPageNum-1) + "'>[&nbsp;"+PagePrevText+"&nbsp;]</A>&nbsp;&nbsp;"
+    if(strPageDirection.equals("Prev"))
+      iBegan= currPageNum-6;
+    else if(strPageDirection.equals("Next")) 
+      iBegan= currPageNum-1;
+    else
+      iBegan= Integer.parseInt(strPageDirection);    
+    for(int i=iBegan; i<=iBegan+7; i++)
+    {
+      if(i==currPageNum)
+        numPageNav3=numPageNav3+ " "+String.valueOf(i)+"&nbsp;";
+      else
+      {
+        if(i==iBegan && i>1 && i<=totalPageNum)
+          numPageNav3=numPageNav3+ " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(i) + "&"+name + "_PageDirection=Next'><U>"+"..."+"</U></A>&nbsp;";
+        else if(i<iBegan+7 && i>0 && i<=totalPageNum)
+          numPageNav3=numPageNav3+ " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(i) + "&"+name + "_PageDirection="+String.valueOf(iBegan)+"'><U>"+String.valueOf(i)+"</U></A>&nbsp;";
+        else if(i==iBegan+7 && i>0 && i<=totalPageNum)
+          numPageNav3=numPageNav3+ " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(i) + "&"+name + "_PageDirection=Prev'><U>"+"..."+"</U></A>&nbsp;";
+      }
+    }    
+    numPageNav3=numPageNav3+ " <A href='" + pageName + name + "_CurrentPage="+ String.valueOf(totalPageNum) + "'><U>"+PageLastText+"</U></A>]" ;
+
+    //change grid rows number per page
+//    changeRowsNum = "Rows Number: <input type='text' id='" + name + "_rowNum' value='" + strNewRowNum + "' onkeyup='" + name + "_limitNumber(this);' disabled='true' size='3'>&nbsp;<input type='button' id='" + name + "_btnChange' value='Change' onclick='" + name + "_changRowNum(this)'>";
+    if(changeRows) {
+        changeRowsNum = "行数: <input type='text' id='" + name + "_rowNum' value='" + strNewRowNum + "' onkeyup='" + name + "_limitNumber(this);' size='3'>&nbsp;<input type='button' id='" + name + "_btnChange' value='提交' onclick='" + name + "_changRowNum(this)'>";
+    } else {
+        changeRowsNum = "";
+    }
+  }
+
+
+  //Print grid headings
+  private void PrintLable(JspWriter out, String[] datTypes)throws JspException{
+    try{
+      
+      //out.println("<TABLE cellSpacing=1 cellPadding=1 bgcolor='white' border=1 style='WIDTH: 98%; HEIGHT: 100px'>");
+      tableSetting = "<TABLE id='tbl_"+name+"' cellSpacing='"+cellSpacing+"' cellPadding='"+cellPadding+"' bgcolor='"+bgcolor+"' border='"+border+"' style='"+style+"'>";
+      out.println(tableSetting );
+      if(showCaption)
+      {
+        out.println("<THEAD>");
+        out.println("<TR id='"+name+"_row_head'>");
+        //begin column
+       
+        //middle columns
+        String orderBy = (String)pageContext.getRequest().getParameter(name + "_ORDERBY");
+        if(orderBy == null) orderBy = "";
+        String AscDesc = (String)pageContext.getSession().getAttribute(name + "_ORDERBY_"+orderBy);
+        if (AscDesc != null)
+        {
+          if(AscDesc.equals("1"))
+            AscDesc = "&nbsp;&uarr;";
+          else
+            AscDesc = "&nbsp;&darr;";
+        }
+        else
+          AscDesc = "";
+        String strCaption = "";
+        for (int i=0; i < this.captions.length; i++){
+          if(!columnTypes[i].equalsIgnoreCase("hidden"))
+          {
+            strCaption = this.captions[i];
+            if (strCaption.trim().equals("")) {  strCaption = "&nbsp;"; }
+            
+            
+              if (this.sortFields[i].equals("") || this.sortFields[i].equals("0")){
+                //no sorting
+                out.println("<th valign='top' class ='"+ headClass +"' width =\""+ this.fieldsWidth[i] + "\" ><span id='"+name+"_header_col"+String.valueOf(i)+"' class =''>" + strCaption + "</span></th>");
+              }
+              else{
+                //sorting
+                if(sortMethod.equalsIgnoreCase("server"))
+                {
+                  if(orderBy.equals(String.valueOf(i)))
+                    out.println(" <th valign='top' class ='"+ headClass +"' width =\""+ this.fieldsWidth[i] + "\" ><A href='" +  pageName + name + "_ORDERBY=" + String.valueOf(i) + "'><span id='"+name+"_header_col"+String.valueOf(i)+"' class =''>" + strCaption  + "</span></A>"+AscDesc+"</TH>");
+                  else
+                    out.println(" <th valign='top' class ='"+ headClass +"' width =\""+ this.fieldsWidth[i] + "\" ><A href='" +  pageName + name + "_ORDERBY=" + String.valueOf(i) + "'><span id='"+name+"_header_col"+String.valueOf(i)+"' class =''>" + strCaption  + "</span></A></TH>");
+                }
+                else
+                {
+                  out.println(" <th valign='top' class ='"+ headClass +"' width =\""+ this.fieldsWidth[i] + "\"><a href='#' onclick=\""+name+"_sort_table('"+name+"',"+String.valueOf(i)+","+this.totalColNumber+","+this.pageRowNumber+");return false;\"><span id='"+name+"_header_col"+String.valueOf(i)+"' class =''>" + strCaption  + "</span></A><span id='"+name+"_sort_col"+String.valueOf(i)+"'>&nbsp;&nbsp;</span></TH>");
+                }
+              }
+            } 
+            
+            
+          //end column
+        
+        }
+        out.println("</TR>");
+	out.println("</THEAD>");
+      }
+      out.println("<TBODY>");
+    }
+    catch(Exception e) {
+      System.out.println("Error "+  e.getMessage()  );
+      e.printStackTrace() ;
+    }     
+  }
+
+  //Print grid rows
+   private void PrintGridRows(JspWriter out, int alternate, SingleRecord R, int RowNumber)throws JspException{
+    
+    String sFieldNumber="";
+    String sTempName="";
+        
+    String strSelection = "";
+    String sTemp;
+    
+    
+    //jimt new update
+    try {
+      //middle columns    
+      if (alternate==0){
+        if(R.rowID != "")
+          if(this.treeStatus == 0 && R.level>1)
+            out.println(" <TR id='"+R.rowID+"' status='"+this.treeStatus+"' style='display:none;' onclick='"+name+"_JGridRowClick(this)' >");
+          else
+            out.println(" <TR id='"+R.rowID+"' status='"+this.treeStatus+"' onclick='"+name+"_JGridRowClick(this)'>");
+        else
+          out.println(" <TR id='"+name+"_row"+RowNumber+"' onclick='"+name+"_JGridRowClick(this)'>");
+      }
+      else {
+        if(R.rowID != "")
+          if(this.treeStatus == 0 && R.level>1)
+            out.println("<TR id='"+R.rowID+"' status='"+this.treeStatus+"' style='display:none; "+altRowStyle+"' onclick='"+name+"_JGridRowClick(this)'>");
+          else
+            out.println("<TR id='"+R.rowID+"' status='"+this.treeStatus+"' style='"+altRowStyle+"' onclick='"+name+"_JGridRowClick(this)'>");
+        else
+          out.println("<TR id='"+name+"_row"+RowNumber+"' style='"+altRowStyle+"' onclick='"+name+"_JGridRowClick(this)'>");
+      }			
+      out.println(strSelection);
+      String strAtrribute = "";
+      String sColumnName = "";
+      String sInnerValue = "";
+      String sFieldName = "";
+      for (int i=0; i < (this.captions.length); i++){
+        
+        sColumnName = name + "_" + "col" + i;
+        sFieldName = name + "_row" + RowNumber+ "_" + "col" + i;
+        
+        strAtrribute = getParseValueNew(this.columnAttributes[i], R, i);
+        sInnerValue = getParseValueNew(this.columnInnerValues[i], R, i);
+        
+        
+          
+          if(columnTypes[i].equalsIgnoreCase("radio"))
+          {
+            //out.println(" <TD class='"+ rowClass +"'><input type='"+columnTypes[i]+"' id ='" + sFieldName +"' name ='" + sColumnName + "' " + strAtrribute + " > " + sInnerValue +" </input></TD>");
+            out.println(" <TD class='"+ rowClass +"'><input type='"+columnTypes[i]+"' id ='" + sFieldName +"' name ='" + sColumnName + "' " + strAtrribute + " /></TD>");
+          }
+          else if(columnTypes[i].equalsIgnoreCase("checkbox") || columnTypes[i].equalsIgnoreCase("button") || columnTypes[i].equalsIgnoreCase("submit") || columnTypes[i].equalsIgnoreCase("text") )
+          {
+          //  out.println(" <TD class='"+ rowClass +"'><input type='"+columnTypes[i]+"' id ='" + sFieldName +"' name ='" + sFieldName + "' " + strAtrribute + " > " + sInnerValue +" </input></TD>");
+            out.println(" <TD class='"+ rowClass +"'><input type='"+columnTypes[i]+"' id ='" + sFieldName +"' name ='" + sFieldName + "' " + strAtrribute + " /></TD>");
+          }
+          else if(columnTypes[i].equalsIgnoreCase("a") || columnTypes[i].equalsIgnoreCase("url") )
+          {
+            out.println(" <TD class='"+ rowClass +"'><a id ='" + sFieldName +"' name ='" + sFieldName + "' " + strAtrribute + " > " + sInnerValue +" </a></TD>");
+          }
+          else if(columnTypes[i].equalsIgnoreCase("image") || columnTypes[i].equalsIgnoreCase("img") )
+          {
+            //out.println(" <TD class='"+ rowClass +"'><image id ='" + sFieldName +"' name ='" + sFieldName + "' " + strAtrribute + " > " + sInnerValue +" </image></TD>");
+            out.println(" <TD class='"+ rowClass +"'><image id ='" + sFieldName +"' name ='" + sFieldName + "' " + strAtrribute + " /></TD>");
+          }
+          else if(columnTypes[i].equalsIgnoreCase("select"))
+          {
+            out.println(" <TD class='"+ rowClass +"'><select id ='" + sFieldName +"' name ='" + sFieldName + "' " + strAtrribute + " > " + sInnerValue +" </select></TD>");
+          }
+          else if(columnTypes[i].equalsIgnoreCase("div"))
+          {
+            out.println(" <TD class='"+ rowClass +"'><div id ='" + sFieldName +"' name ='" + sFieldName + "' " + strAtrribute + " > " + sInnerValue +" </div></TD>");
+          }
+          else if(columnTypes[i].equalsIgnoreCase("span"))
+          {
+            out.println(" <TD class='"+ rowClass +"'><span id ='" + sFieldName +"' name ='" + sFieldName + "' " + strAtrribute + " > " + sInnerValue +" </span></TD>");
+          }
+          else if(columnTypes[i].equalsIgnoreCase("tree"))
+          {
+            String sTable = "<table cellspacing='0' cellpadding='0' border='0'><tr> ";
+            
+            for(int j=0; j<R.level-1; j++)
+            {
+              sTable += "<td><image src='imgs/blank.gif' border='0'></td>";
+            }
+            if(R.hasChild)
+            {
+              if(this.treeStatus == 1)
+                sTable += "<td><a href='javascript:clickTreeGridNode(\"tbl_"+name+"\", \""+R.rowID+"\")'><image id='"+R.rowID+"img' src='imgs/minus.gif' border='0'></a></td>";
+              else
+                sTable += "<td><a href='javascript:clickTreeGridNode(\"tbl_"+name+"\", \""+R.rowID+"\")'><image id='"+R.rowID+"img' src='imgs/plus.gif' border='0'></a></td>";
+                
+              if(treeIcon)
+                sTable += "<td><a href='javascript:clickTreeGridNode(\"tbl_"+name+"\", \""+R.rowID+"\")'><image id='"+R.rowID+"icon' src='imgs/folder.gif' border='0'></a></td>";
+            }
+            else
+            {
+	      sTable += "<td><image src='imgs/blank.gif' border='0'></td>";
+              if(treeIcon)
+                sTable += "<td><image src='imgs/leaf.gif' border='0'></td>";
+            }
+            
+            sTable += "<td ><span id ='" + sFieldName +"' name ='" + sFieldName + "' " + strAtrribute + " > " + sInnerValue +" </span></td>";
+            sTable += " </tr></table>";
+            out.println(" <TD class='"+ rowClass +"' style='text-align: left' >" + sTable +"</TD>");
+          }
+
+          else if(columnTypes[i].equalsIgnoreCase("hidden"))
+          {
+            out.println(" <input type='"+columnTypes[i]+"' id ='" + sFieldName +"' name ='" + sFieldName + "' " + strAtrribute + " />");
+          }
+          else
+          {
+            out.println(" <TD class='"+ rowClass +"'> " + sInnerValue +" </TD>");
+          }
+          
+      }    
+      
+
+      //end column
+      
+
+      out.println("</TR>");
+    }
+    catch(Exception e) {
+      System.out.println("Error "+  e.getMessage()  );
+      e.printStackTrace() ;
+    }
+  } 
+  
+  // Print table bottom
+  private void hideTotalRowColNumber(JspWriter out)throws JspException{
+    String strTotalRow="";
+    String strTotalCol="";
+    
+    strTotalRow="<input type='hidden' id='"+ name +"_TotalRowNumber' name='"+ name +"_TotalRowNumber' value='" + this.pageRowNumber +"'>";
+    strTotalCol="<input type='hidden' id='"+ name +"_TotalColNumber' name='"+ name +"_TotalColNumber' value='" + this.totalColNumber +"'>";
+   
+    try{
+      out.println(strTotalRow);
+      out.println(strTotalCol);
+    }
+    catch(Exception e)
+    {
+      System.out.println("Error "+  e.getMessage()  );
+      e.printStackTrace() ;
+    }
+  }
+  
+  private void PrintBottom(JspWriter out)throws JspException{
+    try {    
+      out.println("</TBODY>");
+                  
+      //new code begin
+      //out.println ("<br>");
+      if(bPrintNavigation) {
+      
+	String sAlign = "";
+	if(pageClass == null || pageClass.trim().equals("")) sAlign = "center";
+	out.println("<TFOOT>"); 
+	out.println("<TR id='" + name + "_gridBottom'>");    
+        out.println ("<TD colspan='"+(this.captions.length)+ "' class='"+ pageClass +"' align='"+sAlign+"'>");
+        out.println (  PageNumber );
+        
+        String sNavigation = "";
+        if (currPageNum == 1)
+        {
+          if(pageType.equalsIgnoreCase("word"))
+            sNavigation = wordPageNav1;
+          if(pageType.equalsIgnoreCase("number"))
+            sNavigation = numPageNav1;
+        }
+        else if (currPageNum == totalPageNum){
+          if(pageType.equalsIgnoreCase("word"))
+            sNavigation = wordPageNav2;
+          if(pageType.equalsIgnoreCase("number"))
+            sNavigation = numPageNav2;
+        }
+        else if ((currPageNum > 1)&&(currPageNum < totalPageNum)){
+          if(pageType.equalsIgnoreCase("word"))
+            sNavigation = wordPageNav3;
+          if(pageType.equalsIgnoreCase("number"))
+            sNavigation = numPageNav3;
+        }
+        if(totalRowNumber > gridRows) {
+            sNavigation = sNavigation + "&nbsp;&nbsp;" + changeRowsNum;
+        } else {
+            sNavigation = changeRowsNum;
+        }
+        out.println (sNavigation);
+        out.println ("</TD>");
+	out.println("</TR>");    
+	out.println("</TFOOT>");    
+    }
+      //new code end
+      out.println("</TABLE>");    
+    }
+    catch(Exception e) {
+    }
+  }
+
+
+  private void PrintJavaScripts(JspWriter out, ArrayList sortArray)throws JspException{
+    SingleRecord R;
+    SingleRecord SR = (SingleRecord)sortArray.get(0);
+    try {    
+      out.println("<script type='text/javascript'>");    
+     
+      for (int i=0; i < this.totalColNumber; i++)
+      {
+          if (!this.sortFields[i].equals("")) 
+          {
+            //sort up
+            String indexUpData = "";
+            //jimt modified 2/11/2006
+            int realIndex = getRealDataArrayIndex(SR, i);
+            Collections.sort(sortArray, new SingleRecordComparator(realIndex, 1)); 
+            //Collections.sort(sortArray, new SingleRecordComparator(i, 1));  //original one
+            //modified end
+            for (int j=0; j<sortArray.size(); j++)
+            {
+              //added for tree column sorting   
+              if(columnTypes[i].equalsIgnoreCase("tree"))
+              {
+                if(indexUpData.equals(""))
+                  indexUpData = indexUpData + "'"+String.valueOf(j)+"'";
+                else
+                  indexUpData = indexUpData + ",'"+String.valueOf(j)+"'";
+              }
+              else
+              {
+                R = (SingleRecord)sortArray.get(j);
+                if(indexUpData.equals(""))
+                  indexUpData = indexUpData + "'"+String.valueOf(R.index)+"'";
+                else
+                  indexUpData = indexUpData + ",'"+String.valueOf(R.index)+"'";
+              }
+              
+            }
+            //sort down
+            String indexDownData = "";
+            //modified by jimt 11/02/2006
+            //Collections.sort(sortArray, new SingleRecordComparator(i, -1)); //original one
+            Collections.sort(sortArray, new SingleRecordComparator(realIndex, -1)); 
+            //modified end
+            for (int j=0; j<sortArray.size(); j++)
+            {
+              //added for tree column sorting   
+              if(columnTypes[i].equalsIgnoreCase("tree"))
+              {
+                if(indexDownData.equals(""))
+                  indexDownData = indexDownData + "'"+String.valueOf(j)+"'";
+                else
+                  indexDownData = indexDownData + ",'"+String.valueOf(j)+"'";
+              }
+              else
+              {
+                R = (SingleRecord)sortArray.get(j);
+                if(indexDownData.equals(""))
+                  indexDownData = indexDownData + "'"+String.valueOf(R.index)+"'";
+                else
+                  indexDownData = indexDownData + ",'"+String.valueOf(R.index)+"'";
+              }  
+              
+            }
+            
+            out.println ("  var "+name+"_sort_index"+String.valueOf(i)+"=[["+indexDownData+"], ["+indexUpData+"]]");
+          }
+      }
+      
+     
+      out.println ("  var "+name+"_rows = new Array(); ");
+      out.println ("  var "+name+"_style = '"+altRowStyle+"'; ");
+      
+      out.println ("  ");
+      out.println ("  function "+name+"_initial_table() {");
+       
+            
+      out.println ("  var tbody = document.getElementById('tbl_"+name+"').getElementsByTagName('TBODY')[0];");
+      out.println ("  for (j=0;j<tbody.rows.length;j++) { "+name+"_rows[j] = tbody.rows[j]; }");
+    
+      out.println ("  }");
+      
+      out.println ("  ");
+      out.println ("function "+name+"_sort_table(gridname, column, columnnum, rownum) {");
+      out.println ("  var index;");
+      out.println ("  var tbody = document.getElementById('tbl_'+gridname).getElementsByTagName(\"TBODY\")[0];");
+      out.println ("  var span, ARROW; ");
+      out.println ("  span = document.getElementById(gridname+'_sort_col'+column);");
+      out.println ("  if (span.getAttribute(\"sortdir\") == 'down') {");
+      out.println ("      ARROW = '&nbsp;&uarr;';");
+      out.println ("      span.setAttribute('sortdir','up');");
+      out.println ("      //alert('down');");
+      out.println ("      for (i=0; i<rownum; i++) ");
+      out.println ("      { ");
+      out.println ("        index = eval(gridname + \"_sort_index\"+column+\"[0][\"+i+\"]\"); ");
+      out.println ("        eval(\"tbody.appendChild(\"+ gridname+\"_rows[\"+index+\"])\");");
+      out.println ("      }");
+      out.println ("  } else { //alert('up');");
+      out.println ("      ARROW = '&nbsp;&darr;';");
+      out.println ("      span.setAttribute('sortdir','down');");
+      out.println ("      ");
+      out.println ("      for (i=0; i<rownum; i++) ");
+      out.println ("      { ");
+      out.println ("        index = eval(gridname + \"_sort_index\"+column+\"[1][\"+i+\"]\"); ");
+      out.println ("        eval(\"tbody.appendChild(\"+ gridname+\"_rows[\"+index+\"])\");");
+      out.println ("      }");
+      out.println ("  }");
+      out.println (" ");
+      out.println ("  for (j=0; j<columnnum; j++) ");
+      out.println ("  { ");
+      out.println ("    try{");
+      out.println ("      document.getElementById(gridname+'_sort_col'+j).innerHTML='&nbsp;&nbsp;';");
+      out.println ("    }catch(error){ }");
+      out.println ("  }");
+      out.println ("  span.innerHTML = ARROW;");
+      out.println ("  ");
+      out.println ("  for (i=0; i<tbody.rows.length; i++)");
+      out.println ("  { ");
+      out.println ("    if(i%2 == 0)");
+      out.println ("    { ");
+      out.println ("      eval(\"tbody.rows[i].style.background = \"+ gridname+\"_style;\");");  
+      out.println ("    }");
+      out.println ("    else");
+      out.println ("    {");
+      out.println ("      eval(\"tbody.rows[i].style.background = ' ';\"); "); 
+      out.println ("    }");
+      out.println ("  }");
+      out.println ("}");
+    
+      out.println ("  setTimeout('"+name+"_initial_table()', 200); ");
+      
+            
+      out.println ("</script>");
+    }
+    catch(Exception e) {
+    }
+  }
+  
+  private void PrintOtherJavaScripts(JspWriter out)throws JspException{
+    
+    try {    
+      out.println("<script type='text/javascript'>");  
+      if(this.treeGrid)
+      {
+        out.println ("function clickTreeGridNode(tableid, rowid)");
+        out.println ("  {");
+        out.println ("    //note: status=1 means open, status=0 means close ");
+        out.println ("    var bTrue = true;");
+        out.println ("    //get row attribute");
+        out.println ("    var row = document.getElementById(rowid);");
+        out.println ("    var rowStatus = row.getAttribute('status');");
+        out.println ("    if (rowStatus == null) //already open");
+        out.println ("      bTrue = false;");
+        out.println ("    else");
+        out.println ("    {");
+        out.println ("      if (rowStatus == '0') //already close");
+        out.println ("        bTrue = true;");
+        out.println ("      else  //already open");
+        out.println ("        bTrue = false; ");
+        out.println ("    }");
+        out.println ("    ");
+        out.println ("    if(bTrue)");
+        out.println ("    {");
+        out.println ("      try{");
+        out.println ("      document.getElementById(rowid+'img').src = 'imgs/minus.gif';");
+        out.println ("      document.getElementById(rowid+'icon').src = 'imgs/folder.gif';");
+        out.println ("      }catch(e){}");
+        out.println ("    }");
+        out.println ("    else");
+        out.println ("    {");
+        out.println ("      try{");
+        out.println ("      document.getElementById(rowid+'img').src = 'imgs/plus.gif';");
+        out.println ("      document.getElementById(rowid+'icon').src = 'imgs/folder.gif';");
+        out.println ("      }catch(e){}");
+        out.println ("    }");
+        out.println ("    ");
+        out.println ("    showTreeGridChildNode(tableid, rowid, bTrue);");
+        out.println ("    ");
+        out.println ("    if(bTrue)");
+        out.println ("      row.setAttribute('status','1');");
+        out.println ("    else");
+        out.println ("      row.setAttribute('status','0');");
+        out.println ("  }");
+        out.println ("  ");
+        out.println ("  function showTreeGridChildNode(tableid, rowid, bTrue)");
+        out.println ("  {");
+        out.println ("    var tempId, elem = rowid + '_';");
+        out.println ("    //var elems = document.getElementsByTagName('*'); // yes, wildcards do exist");
+        out.println ("    var rows = eval(tableid+\".getElementsByTagName('TR')\")");
+        out.println ("    for (var i=0; i<rows.length; i++) {");
+        out.println ("      tempId = rows[i].id;");
+        out.println ("      if(tempId!=null && tempId.length>=elem.length && tempId.substring(0,elem.length)==elem)");
+        out.println ("      {");
+        out.println ("        var temp = tempId.substring(elem.length, tempId.length); //alert(temp.indexOf('_'));");
+        out.println ("        if(temp.indexOf('_')== -1)");
+        out.println ("        {");
+        out.println ("          var imgElem = document.getElementById(tempId + 'img');");
+        out.println ("          if(bTrue)  //open");
+        out.println ("          {");
+        out.println ("            rows[i].style.display=(navigator.appName.indexOf(\"Microsoft\") > -1)?'inline':'table-row';");
+        out.println ("            if(imgElem != null)");
+        out.println ("            {");
+        out.println ("              if (imgElem.src.indexOf('minus.gif') > -1)");
+        out.println ("              {");
+        out.println ("                showTreeGridChildNode(tableid, tempId, true);");
+        out.println ("              }");
+        out.println ("            }");
+        out.println ("          }");
+        out.println ("          else  //close");
+        out.println ("          {");
+        out.println ("            rows[i].style.display='none';");
+        out.println ("            if(imgElem != null)");
+        out.println ("            {");
+        out.println ("              if (imgElem.src.indexOf('minus.gif') > -1) //if it is folder and already open, close his children");
+        out.println ("              {");
+        out.println ("                showTreeGridChildNode(tableid, tempId, false);");
+        out.println ("              }");
+        out.println ("            }");
+        out.println ("          }");
+        out.println ("        }");
+        out.println ("      }");
+        out.println ("    }");
+        out.println ("    ");
+        out.println ("  }");
+      }
+      
+      out.println ("  var "+name+"_lastJGridRowClick = null;");
+      out.println ("  var "+name+"_lastJGridRowClick_bgcolor = '';");
+      out.println ("  function "+name+"_JGridRowClick(the){");
+      out.println ("    if("+name+"_lastJGridRowClick) {");
+      out.println ("      "+name+"_lastJGridRowClick.style.backgroundColor = "+name+"_lastJGridRowClick_bgcolor; ");
+      out.println ("    }");
+      out.println ("    "+name+"_lastJGridRowClick = the;");
+      out.println ("    "+name+"_lastJGridRowClick_bgcolor = the.style.backgroundColor;");
+      out.println ("    if(typeof(HighLiteRowColor)!='undefined') {");
+      out.println ("      the.style.backgroundColor = HighLiteRowColor; ");
+      out.println ("    } else {");
+      out.println ("      the.style.backgroundColor = '#D8D8D8';");
+      out.println ("    }");
+      out.println ("  }");
+      out.println ("  ");
+      
+      out.println ("  function "+name+"_changRowNum(the){");
+//      out.println ("    if(the.value=='改变') {");
+//      out.println ("      the.value='提交'; ");
+//      out.println ("      document.getElementById('"+name+"_rowNum').removeAttribute('disabled'); ");
+//      out.println ("    } else {");
+      out.println ("      var value = document.getElementById('"+name+"_rowNum').value; ");
+      out.println ("      window.location.href='" + pageName + name +"_NewRowNum='+value;");
+//      out.println ("    }");
+      out.println ("  }");
+      out.println ("  ");
+      
+      out.println ("  function "+name+"_limitNumber(entry) {");
+      out.println ("    var re = /^[0-9]*$/;");
+      out.println ("    if (!re.test(entry.value)) {");
+      out.println ("        entry.value = entry.value.replace(/[^0-9]/g, '');");
+      out.println ("    }");
+      out.println ("  }");
+      
+      out.println ("</script>");
+    }
+    catch(Exception e) {
+    }
+  
+  }
+  
+  /**
+   * Method called at end of tag.
+   * @return EVAL_PAGE
+   */
+  public int doEndTag()
+  {
+    SingleRecord R;
+    ArrayList sortArray = new ArrayList();
+
+    if (resultSetArray == null) return EVAL_PAGE;
+  
+    int totalRecord = resultSetArray.size();
+    //new adding for having totalSize
+      if(totalSize > -1){
+          totalRecord = totalSize;
+      }
+      //
+    this.totalRowNumber = totalRecord;
+    this.pageRowNumber = totalRecord;
+        
+    if (totalRecord > 0){
+      String strNewRowNum = (String)pageContext.getSession().getAttribute(name + "_gridRows");
+      if (strNewRowNum != null) {
+        if(strNewRowNum.equals(""))
+            gridRows = 0;
+        else {
+            gridRows = Integer.parseInt(strNewRowNum);
+        }
+     }
+      if (gridRows < 0) bPrintNavigation = false;
+      if (gridRows <= 0) gridRows = totalRecord;
+      
+      if(this.totalRowNumber < currPageNum * gridRows)
+        this.pageRowNumber = totalRecord - (currPageNum - 1) * gridRows;
+      else
+        this.pageRowNumber =  gridRows;
+          
+      try {
+        JspWriter out = pageContext.getOut();
+
+        //get data type
+        R = (SingleRecord)resultSetArray.get(0);
+        String[] dataTypes = new String[this.totalColNumber];
+        for(int col=0; col<this.totalColNumber; col++)
+        {
+          dataTypes[col] = R.getFieldDataType(col);
+        }
+        //print headings
+        this.PrintLable(out, dataTypes);
+        
+        //new code begin
+        int alternate = 0;
+        int iIndex;
+        for(iIndex=0; iIndex<resultSetArray.size(); iIndex++)
+        {
+          R = (SingleRecord)resultSetArray.get(iIndex);
+          
+          //Print out grid body
+          //new adding for having totalSize
+            if(totalSize > -1){
+                PrintGridRows(out, alternate, R, iIndex);
+
+                if (alternate==0){
+                    alternate=1;
+                }
+                else if(alternate==1){
+                    alternate=0;
+                }
+
+                //for client side sorting
+                R.index = iIndex;
+                sortArray.add(R);
+                //      
+            } else {
+            //
+                if ((iIndex >= (currPageNum - 1) * gridRows) && (iIndex < currPageNum * gridRows))
+                {                
+                    PrintGridRows(out, alternate, R, iIndex - (currPageNum - 1) * gridRows);
+
+                    if (alternate==0){
+                    alternate=1;
+                    }
+                    else if(alternate==1){
+                    alternate=0;
+                    }
+
+                    //for client side sorting
+                    R.index = iIndex - (currPageNum - 1) * gridRows;
+                    sortArray.add(R);
+                    //      
+                }   
+            }
+            //
+        }
+
+        this.hideTotalRowColNumber(out);
+        
+        //print bottom navigation buttons
+        this.PrintBottom(out);  
+        
+        boolean bsort = false;
+        for (int i=0; i < this.captions.length; i++)
+        {
+            if (!this.sortFields[i].equals("")) 
+            {
+              bsort = true;
+              break;
+            }
+        }
+        
+        if(bsort && !sortMethod.equalsIgnoreCase("server"))
+        {
+          this.PrintJavaScripts(out, sortArray);
+        }
+        
+       // if(this.treeGrid)
+        {
+          this.PrintOtherJavaScripts(out);
+        }
+        
+      }
+      catch(Exception e) {
+        System.out.println("Error "+  e.getMessage()  );
+        e.printStackTrace();
+      }
+    }
+    else{
+      try {
+        JspWriter out = pageContext.getOut();
+        this.hideTotalRowColNumber(out);
+        out.println("<center><span class='"+pageClass+"'>"+emptyText+"</span></center>");
+      }
+      catch(Exception e)
+      {
+        System.out.println("Error "+  e.getMessage()  );
+        e.printStackTrace();
+      }
+    }
+    return EVAL_PAGE;
+  }
+
+
+  public void setQueryString(String value)
+  {
+    queryString = value;
+  }
+
+
+  public String getQueryString()
+  {
+    return queryString;
+  }
+
+
+  public void setDataSource(String value)
+  {
+    dataSource = value;
+  }
+
+  public String getDataSource()
+  {
+    return dataSource;
+  }
+
+
+  public void setResultSetArray(ArrayList value)
+  {
+    resultSetArray = value;
+  }
+  
+  public void setResultSetArray(List value)
+  {
+    resultSetArray = value;
+  }
+
+
+
+  public List getResultSetArray()
+  {
+    return resultSetArray;
+  }
+
+
+  public void setGridRows(int value)
+  {
+    gridRows = value;
+  }
+
+
+  public int getGridRows()
+  {
+    return gridRows;
+  }
+
+  public void setChangeRows(boolean value)
+  {
+    changeRows = value;
+  }
+
+
+  public boolean getChangeRows()
+  {
+    return changeRows;
+  }
+  
+  public void setTotalSize(int value)
+  {
+    totalSize = value;
+  }
+
+
+  public int getTotalSize()
+  {
+    return totalSize;
+  }
+  
+
+  public void setShowCaption(boolean value)
+  {
+    showCaption = value;
+  }
+
+
+  public boolean getShowCaption()
+  {
+    return showCaption;
+  }
+
+
+  public void setCellSpacing(String value)
+  {
+    cellSpacing = value;
+  }
+  public String getCellSpacing()
+  {
+    return cellSpacing;
+  }
+  
+  public void setCellPadding(String value)
+  {
+    cellPadding = value;
+  }
+  public String getCellPadding()
+  {
+    return cellPadding;
+  }
+  
+  public void setBgcolor(String value)
+  {
+    bgcolor = value;
+  }
+  public String getBgcolor()
+  {
+    return bgcolor;
+  }
+  
+  public void setBorder(String value)
+  {
+    border = value;
+  }
+  public String getBorder()
+  {
+    return border;
+  }
+  
+  public void setStyle(String value)
+  {
+    style = value;
+  }
+  public String getStyle()
+  {
+    return style;
+  }
+
+  public void setHeadClass(String value)
+  {
+    headClass = value;
+  }
+
+
+  public String getHeadClass()
+  {
+    return headClass;
+  }
+
+
+  public void setRowClass(String value)
+  {
+    rowClass = value;
+  }
+
+
+  public String getRowClass()
+  {
+    return rowClass;
+  }
+
+  public void setPageClass(String value)
+  {
+    pageClass = value;
+  }
+
+  public String getPageClass()
+  {
+    return pageClass;
+  }
+
+  public void setAltRowStyle(String value)
+  {
+    altRowStyle = value;
+  }
+
+  public String getAltRowStyle()
+  {
+    return altRowStyle;
+  }
+
+ 
+
+  public void setName(String value)
+  {
+    name = value;
+  }
+
+
+  public String getName()
+  {
+    return name;
+  }
+  
+  public String getEmptyText(){
+    return this.emptyText;
+  }
+  public void setEmptyText(String newEmptyText){
+    this.emptyText = newEmptyText;
+  }
+  
+  public String getPageType(){
+    return this.pageType;
+  }
+  public void setPageType(String newPageType){
+    this.pageType = newPageType;
+  }
+
+  public String getSortMethod(){
+    return this.sortMethod;
+  }
+  public void setSortMethod(String newSortMethod){
+    this.sortMethod = newSortMethod;
+  }
+  
+  
+}

+ 59 - 0
src/com/tang/taglib/grid/Paging.java

@@ -0,0 +1,59 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tang.taglib.grid;
+
+/**
+ *
+ * @author txijian
+ */
+public class Paging {
+    private int page_size = 0;
+    private int page_number = -1;
+    private int total_size = -1;
+    private String start_point;
+    private String other;
+
+    public int getPage_number() {
+        return page_number;
+    }
+
+    public void setPage_number(int page_number) {
+        this.page_number = page_number;
+    }
+
+    public int getPage_size() {
+        return page_size;
+    }
+
+    public void setPage_size(int page_size) {
+        this.page_size = page_size;
+    }
+
+    public int getTotal_size() {
+        return total_size;
+    }
+
+    public void setTotal_size(int total_size) {
+        this.total_size = total_size;
+    }
+
+    public String getOther() {
+        return other;
+    }
+
+    public void setOther(String other) {
+        this.other = other;
+    }
+
+    public String getStart_point() {
+        return start_point;
+    }
+
+    public void setStart_point(String start_point) {
+        this.start_point = start_point;
+    }
+    
+    
+}

+ 275 - 0
src/com/tang/taglib/grid/SingleRecord.java

@@ -0,0 +1,275 @@
+/*
+Copyright 2009 Xijian (Jim) Tang
+This version of Software is free for using in non-commercial applications. For commercial use please contact txijian@yahoo.com to obtain license
+*/
+
+package com.tang.taglib.grid;
+
+import java.util.*;
+import java.lang.System;
+import java.lang.String;
+import java.sql.*;
+
+public class SingleRecord implements java.io.Serializable {
+  private String[] fieldValues = null; 
+  private String[] fieldNames = null; 
+  private String[] fieldDataTypes = null;
+  private int totalFields=0;
+  
+  //for display values
+  private String[] newFieldValues = null; 
+  
+  //for sorting
+  int index = 0;  
+  
+  //new added for tree grid
+  int level = 0;
+  boolean hasChild = false;
+  String rowID = "";
+  //new added end
+  
+  public SingleRecord(String[] recordfieldvalues)
+  {
+    totalFields = recordfieldvalues.length;
+        
+    fieldValues = new String[totalFields]; newFieldValues = new String[totalFields];
+    fieldNames = new String[totalFields];
+    fieldDataTypes = new String[totalFields];
+    int i;
+    for (i=0;i<totalFields; i++ ) {
+      fieldValues[i] = recordfieldvalues[i];
+      fieldNames[i] = "COL_" + String.valueOf(i);
+      fieldDataTypes[i] = "STRING";
+    }
+    
+  }
+  
+  public SingleRecord(String[] recordfieldvalues, String[] recordfieldnames)
+  {
+    totalFields = recordfieldvalues.length;
+    if(recordfieldnames != null)
+    {
+      if (totalFields > recordfieldnames.length) totalFields = recordfieldnames.length;
+    }
+    fieldValues = new String[totalFields];  newFieldValues = new String[totalFields];
+    fieldNames = new String[totalFields];
+    fieldDataTypes = new String[totalFields];
+    int i;
+    for (i=0;i<totalFields; i++ ) {
+      fieldValues[i] = recordfieldvalues[i];
+      if(recordfieldnames != null)
+        fieldNames[i] = recordfieldnames[i];
+      else
+        fieldNames[i] = "COL_" + String.valueOf(i);
+      fieldDataTypes[i] = "STRING";
+    }
+    
+  }
+
+  public SingleRecord(String[] recordfieldvalues, String[] recordfieldnames, String[] recordfielddatatypes)
+  {
+    totalFields = recordfieldvalues.length;
+    if(recordfieldnames != null)
+    {
+      if (totalFields > recordfieldnames.length) totalFields = recordfieldnames.length;
+    }
+    if(recordfielddatatypes != null)
+    {
+      if (totalFields > recordfielddatatypes.length) totalFields = recordfielddatatypes.length;
+    }
+    
+    fieldValues = new String[totalFields];  newFieldValues = new String[totalFields];
+    fieldNames = new String[totalFields];
+    fieldDataTypes = new String[totalFields];
+    int i;
+    for (i=0;i<totalFields; i++ ) {
+      fieldValues[i] = recordfieldvalues[i];
+      if(recordfieldnames != null)
+        fieldNames[i] = recordfieldnames[i];
+      else
+        fieldNames[i] = "COL_" + String.valueOf(i);
+      
+      if(recordfielddatatypes != null)
+        fieldDataTypes[i] = recordfielddatatypes[i];
+      else
+        fieldDataTypes[i] = "STRING";
+    }
+    
+  }
+  
+  public SingleRecord(String[] recordfieldvalues, String[] recordfieldnames, String[] recordfielddatatypes, String[] newrecordfieldvalues)
+  {
+    totalFields = recordfieldvalues.length;
+    if(recordfieldnames != null)
+    {
+      if (totalFields > recordfieldnames.length) totalFields = recordfieldnames.length;
+    }
+    if(recordfielddatatypes != null)
+    {
+      if (totalFields > recordfielddatatypes.length) totalFields = recordfielddatatypes.length;
+    }
+    
+    fieldValues = new String[totalFields];  newFieldValues = new String[totalFields];
+    fieldNames = new String[totalFields];
+    fieldDataTypes = new String[totalFields];
+    int i;
+    for (i=0;i<totalFields; i++ ) {
+      fieldValues[i] = recordfieldvalues[i]; newFieldValues[i] = newrecordfieldvalues[i]; 
+      if(recordfieldnames != null)
+        fieldNames[i] = recordfieldnames[i];
+      else
+        fieldNames[i] = "COL_" + String.valueOf(i);
+      
+      if(recordfielddatatypes != null)
+        fieldDataTypes[i] = recordfielddatatypes[i];
+      else
+        fieldDataTypes[i] = "STRING";
+    }
+    
+  }
+  
+  //
+  public String getFieldValue(int i)
+  {
+    if (i >= totalFields) return "&nbsp;";
+    
+    String value = "";
+    if (this.newFieldValues[i]==null)
+      value = this.fieldValues[i];
+    else
+      value = this.newFieldValues[i];
+    
+    if (value==null)
+    {
+      return "&nbsp;";
+    }
+    else
+    {
+      if (value.trim().equals(""))
+        return "&nbsp;";
+      else
+        return (value.trim());  
+    }
+  }
+
+  public String getFieldValue(String fieldname)
+  {
+    for (int i=0;i<totalFields; i++ ) {
+      if (fieldNames[i].equalsIgnoreCase(fieldname))
+      {
+        return getFieldValue(i);
+      }
+    }
+    return "&nbsp;";
+  }
+
+  public String getFieldOrigialValue(int i)
+  {
+    if (i >= totalFields) return null;
+    return this.fieldValues[i];  
+  }
+
+  public String getFieldOrigialValue(String fieldname)
+  {
+    for (int i=0;i<totalFields; i++ ) {
+      if (fieldNames[i].equalsIgnoreCase(fieldname))
+      {
+        return getFieldOrigialValue(i);
+      }
+    }
+    return null;
+  }
+  
+   //new added by jimt 11/02/2006
+  public int getFieldIndex(String fieldname)
+  {
+    for (int i=0;i<totalFields; i++ ) {
+      if (fieldNames[i].equalsIgnoreCase(fieldname))
+      {
+        return i;
+      }
+    }
+    return -1;
+  }
+  
+  //add end
+  
+
+  public void setFieldOrigialValue(int i, String value)
+  {
+    if (i >= totalFields) return;
+    this.fieldValues[i] = value;  
+  }
+
+  public void setFieldOrigialValue(String fieldname, String value)
+  {
+    for (int i=0;i<totalFields; i++ ) {
+      if (fieldNames[i].equalsIgnoreCase(fieldname))
+      {
+        setFieldOrigialValue(i, value);
+        break;
+      }
+    }
+  }
+  
+  public void setFieldValue(int i, String value)
+  {
+    if (i >= totalFields) return;
+    this.newFieldValues[i] = value;  
+  }
+
+  public void setFieldValue(String fieldname, String value)
+  {
+    for (int i=0;i<totalFields; i++ ) {
+      if (fieldNames[i].equalsIgnoreCase(fieldname))
+      {
+        setFieldValue(i, value);
+        break;
+      }
+    }
+  }
+  
+  //
+  public String getFieldName(int i)
+  {
+    if (i >= totalFields) return "";
+    return (this.fieldNames[i]);
+  }
+  
+  public void setFieldName(int i, String newname)
+  {
+    if (i >= totalFields) return;
+    this.fieldNames[i] = newname;
+  }
+  //
+  public String getFieldDataType(int i)
+  {
+    if (i >= totalFields) return "";
+    return (this.fieldDataTypes[i]);
+  }
+  
+  public void setFieldDataType(int i, String newtype)
+  {
+    if (i >= totalFields) return;
+    if (newtype == null) return;
+    this.fieldDataTypes[i] = newtype.toUpperCase();
+  }
+  
+  public String getFieldDataType(String fieldname)
+  {
+    for (int i=0;i<totalFields; i++ ) {
+      if (fieldNames[i].equalsIgnoreCase(fieldname))
+      {
+        return getFieldDataType(i);
+      }
+    }
+    return "";
+  }
+  //
+  public int getTotalColumnNumber()
+  {
+    return  this.totalFields;
+  }
+
+}
+  

+ 106 - 0
src/com/tang/taglib/grid/SingleRecordComparator.java

@@ -0,0 +1,106 @@
+/*
+Copyright 2009 Xijian (Jim) Tang
+This version of Software is free for using in non-commercial applications. For commercial use please contact txijian@yahoo.com to obtain license
+*/
+
+package com.tang.taglib.grid;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.lang.Object; 
+import java.lang.reflect.*; 
+import java.util.Comparator; 
+import java.text.ParseException;
+
+public class SingleRecordComparator extends Object implements Comparator { 
+  private int column = 0; 
+  private int descAscIndicator = 1; 
+  private static final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss"; 
+  private static final String DATEFORMAT = "yyyy-MM-dd";
+  public static final int ASCENDING = 1; 
+  public static final int DESCENDING = -1; 
+    	 
+  public SingleRecordComparator(int column, int descAscIndicator) { 
+    this.descAscIndicator = descAscIndicator; 
+    this.column = column;
+  } 
+
+               	 
+  public int compare(Object o1, Object o2) { 
+    SingleRecord sr1 = (SingleRecord) o1;
+    SingleRecord sr2 = (SingleRecord) o2;
+
+    if (column >= sr1.getTotalColumnNumber()) return 0;
+    //new added by jimt 11/02/2006
+    if (column <= -1) return 0;
+    //add end
+
+    String dataType = sr1.getFieldDataType(column);
+
+    String strTemp1 = sr1.getFieldOrigialValue(column);
+    String strTemp2 = sr2.getFieldOrigialValue(column);
+    if( (strTemp1 == null || strTemp1.equals("")) && (strTemp2 != null && !strTemp2.equals("")))
+    {
+      return -1* descAscIndicator;
+    }
+    if( (strTemp1 != null && !strTemp1.equals("")) && (strTemp2 == null || strTemp2.equals("")))
+    {
+      return 1* descAscIndicator;
+    }
+    if( (strTemp1 == null || strTemp1.equals("")) && (strTemp2 == null || strTemp2.equals("")))
+    {
+      return 0;
+    }
+    try
+    {  
+      if( dataType.startsWith("DATE"))
+      {
+        String sFormat ="";
+        int begPos = dataType.indexOf("(");
+        int endPos = dataType.indexOf(")");
+
+        if ((begPos != -1) && (endPos != -1))
+        {
+          sFormat = dataType.substring(begPos+1, endPos);                    
+        }
+        
+        SimpleDateFormat formatter = null;
+        if(!sFormat.equals(""))
+          formatter = new SimpleDateFormat(sFormat);
+        else {
+	  if(dataType.equals("DATETIME"))
+	    formatter = new SimpleDateFormat(DATETIMEFORMAT);
+	  else
+	    formatter = new SimpleDateFormat(DATEFORMAT);
+	}
+	
+        Date Date1 = formatter.parse(sr1.getFieldOrigialValue(column));
+        Date Date2 = formatter.parse(sr2.getFieldOrigialValue(column));
+        return Date1.compareTo(Date2)* descAscIndicator;
+      }
+    
+      if( dataType.equalsIgnoreCase("NUMBER") || dataType.equalsIgnoreCase("INTEGER"))
+      { 
+      
+        Double Double1 = Double.valueOf(sr1.getFieldOrigialValue(column));
+        Double Double2 = Double.valueOf(sr2.getFieldOrigialValue(column));
+    
+        return Double1.compareTo(Double2)* descAscIndicator;
+      }
+    
+      String String1 = sr1.getFieldOrigialValue(column);
+      String String2 = sr2.getFieldOrigialValue(column);
+      return String1.compareTo(String2)* descAscIndicator;
+    }
+    catch (Exception e) 
+    {
+      System.out.println("Error message = " + e.getMessage());
+      //e.printStackTrace();
+      return 0;
+    } 
+  } 
+                            	 
+  public boolean equals(Object obj) { 
+    return this.equals(obj); 
+  } 
+}

+ 218 - 0
src/com/tang/taglib/grid/SingleRecordCreation.java

@@ -0,0 +1,218 @@
+/*
+Copyright 2009 Xijian (Jim) Tang
+This version of Software is free for using in non-commercial applications. For commercial use please contact txijian@yahoo.com to obtain license
+*/
+
+package com.tang.taglib.grid;
+
+import java.sql.*;
+import javax.sql.*;
+import java.rmi.RemoteException;
+import javax.naming.*;
+import java.util.Vector;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.text.SimpleDateFormat;
+import java.io.File;
+import oracle.sql.*;
+import oracle.jdbc.*;
+
+public class SingleRecordCreation implements java.io.Serializable
+{
+
+  private String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss";
+  private String DATEFORMAT = "yyyy-MM-dd";
+  
+  public SingleRecordCreation()
+  {
+  }
+  
+  public ArrayList getResultsetArrayList(PreparedStatement notamStmt) throws Exception
+  {
+    int totalCoulum=0;
+    ResultSet rs = null;
+    SimpleDateFormat formatter;
+    
+    rs = notamStmt.executeQuery();
+    
+    if (rs == null) return null;
+    try{
+      ArrayList mList = new ArrayList();
+      int i = 0;
+      ResultSetMetaData rsmd =rs.getMetaData();
+      
+      int columnCount = rsmd.getColumnCount();
+      String[] fieldValues = new String[columnCount];
+      String[] fieldNames=new String[columnCount];  
+      String[] fieldNameTypes=new String[columnCount];  
+      int row = 0;
+      while (rs.next())
+      {
+        fieldValues = new String[columnCount];
+        for(i=0;i<columnCount;i++)
+        {
+          fieldValues[i]=rs.getString(i+1);
+          fieldNames[i] = rsmd.getColumnName(i+1).toUpperCase();
+          fieldNameTypes[i]= checkDataType(rsmd.getColumnTypeName(i+1));
+          if (rsmd.getColumnTypeName(i+1).equalsIgnoreCase("CLOB")== true)
+          {
+            CLOB myClob = ((OracleResultSet)rs).getCLOB(rsmd.getColumnName(i+1));
+            fieldValues[i]=getCLOBContent(myClob);
+          }
+
+          if (fieldNameTypes[i].startsWith("DATE"))
+          {
+            java.util.Date dDate = rs.getTimestamp(i+1);
+            if (dDate != null) 
+            {
+	      if (fieldNameTypes[i].equals("DATETIME"))
+		formatter = new SimpleDateFormat(DATETIMEFORMAT);
+              else
+		formatter = new SimpleDateFormat(DATEFORMAT);
+
+	      fieldValues[i] = formatter.format(dDate);
+                
+            }
+            else
+              fieldValues[i] = "";
+          }
+        } 
+        
+        mList.add(new SingleRecord(fieldValues, fieldNames, fieldNameTypes));
+        row++;
+      }
+      return mList;
+      
+    }
+    catch(Exception e)
+    {
+      e.printStackTrace();
+      return null;         
+    }
+    finally
+    {
+      if(notamStmt != null) notamStmt.close();
+    }
+  }
+
+  
+  public ArrayList getResultsetArrayList(Connection myConnection, String SQLState) throws Exception
+  {
+    
+    PreparedStatement notamStmt = null;
+    int totalCoulum=0;
+    ResultSet rs = null;
+    
+    notamStmt = myConnection.prepareStatement(SQLState) ;
+    rs = notamStmt.executeQuery(SQLState);
+    
+    if (rs == null) return null;
+    try{
+      ArrayList mList = new ArrayList();
+      int i = 0;
+      ResultSetMetaData rsmd =rs.getMetaData();
+      
+      int columnCount = rsmd.getColumnCount();
+      String[] fieldValues = new String[columnCount];
+      String[] fieldNames=new String[columnCount];  
+      String[] fieldNameTypes=new String[columnCount];  
+      int row = 0;
+      while (rs.next())
+      {
+        fieldValues = new String[columnCount];
+        for(i=0;i<columnCount;i++)
+        {
+          fieldValues[i]=rs.getString(i+1);
+          fieldNames[i] = rsmd.getColumnName(i+1).toUpperCase();
+          fieldNameTypes[i]= checkDataType(rsmd.getColumnTypeName(i+1));
+          if (rsmd.getColumnTypeName(i+1).equalsIgnoreCase("CLOB")== true)
+          {
+            CLOB myClob = ((OracleResultSet)rs).getCLOB(rsmd.getColumnName(i+1));
+            fieldValues[i]=getCLOBContent(myClob);
+          }
+
+          if (fieldNameTypes[i].equals("DATE"))
+          {
+            java.util.Date dDate = rs.getTimestamp(i+1);
+            if (dDate != null) 
+            {
+              SimpleDateFormat formatter = new SimpleDateFormat(DATETIMEFORMAT);
+              fieldValues[i] = formatter.format(dDate);
+                
+            }
+            else
+              fieldValues[i] = "";
+          }
+        } 
+        
+        mList.add(new SingleRecord(fieldValues, fieldNames, fieldNameTypes));
+        row++;
+      }
+      return mList;
+      
+    }
+    catch(Exception e)
+    {
+      e.printStackTrace();
+      return null;         
+    }
+  }
+
+  public String checkDataType(String sType)
+  {
+    if (sType == null) return "STRING";
+
+    String sTemp = sType.toLowerCase();
+    if (sTemp.equals("int")||sTemp.equals("short")||sTemp.equals("long")||sTemp.equals("byte")||sTemp.equals("integer")||sTemp.equals("autonumber")||sTemp.equals("smallint")||sTemp.equals("mediumint")||sTemp.equals("year"))
+      return "INTEGER";
+    if (sTemp.equals("boolean") || sTemp.equals("bool") ||sTemp.equals("bit")||sTemp.equals("yes/no"))
+      return "INTEGER";
+      
+    if (sTemp.equals("float")||sTemp.equals("double")||sTemp.equals("decimal")||sTemp.equals("number")||sTemp.equals("currency"))
+      return "NUMBER";
+    if (sTemp.equals("raw")||sTemp.equals("long raw")||sTemp.equals("fixed")||sTemp.equals("real"))
+      return "NUMBER";
+    if (sTemp.equals("tinyint")||sTemp.equals("bigint")||sTemp.equals("dec")||sTemp.equals("double precision")||sTemp.equals("numeric"))
+      return "NUMBER";
+    
+    if (sTemp.equals("java.util.date")|| sTemp.equals("java.sql.timestamp")||sTemp.equals("java.sql.date"))
+      return "DATETIME"; 
+    if (sTemp.equals("datetime")|| sTemp.equals("date/time")||sTemp.equals("timestamp")||sTemp.equals("time"))
+      return "DATETIME"; 
+    if (sTemp.equals("java.sql.date")||sTemp.equals("date"))
+      return "DATE"; 
+    if (sTemp.startsWith("date"))
+    {
+      if(sTemp.length()>4)
+        return "DATE"+sType.substring(4); 
+      else
+        return "DATE";
+    }
+    
+    return "STRING";
+  }
+  
+  public String getCLOBContent(CLOB myClob) throws SQLException
+  {
+    try{
+      int chunkSize = myClob.getChunkSize();
+      char [] textBuffer = new char[chunkSize];
+      long clobLength = myClob.length();
+      String strClob = "";
+      String strTemp;
+      for( long position = 1; position <= clobLength; position += chunkSize)
+      {
+        int charsRead = myClob.getChars(position, chunkSize, textBuffer);
+        strTemp = new String(textBuffer);
+        strClob = strClob + strTemp;
+      }
+      return strClob;
+    }
+    catch(Exception e)
+    {
+      e.printStackTrace();
+      return null;         
+    }
+  }
+
+}

+ 127 - 0
taglib_JGrid.tld

@@ -0,0 +1,127 @@
+<?xml version = '1.0' encoding = 'windows-1252'?>
+<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+<taglib>
+   <tlib-version>1.0</tlib-version>
+   <jsp-version>1.2</jsp-version>
+   <short-name>taglib</short-name>
+   <uri>/WEB-INF/</uri>
+   <description>A short description...</description>
+   <tag>
+      <name>JGrid</name>
+      <tag-class>com.tang.taglib.grid.JGrid</tag-class>
+      <body-content>Empty</body-content>
+      <display-name>JGrid</display-name>
+      <description>A short description...</description>
+      <attribute>
+         <name>queryString</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>dataSource</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>resultSetArray</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>headers</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>columns</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>treeGrid</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      
+      <attribute>
+         <name>gridRows</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      
+      <attribute>
+         <name>showCaption</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>headClass</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>rowClass</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>altRowStyle</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>pageClass</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      
+      <attribute>
+         <name>name</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>emptyText</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>pageType</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>border</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>bgcolor</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>cellspacing</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>cellpadding</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>style</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      <attribute>
+         <name>sortMethod</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+      </attribute>
+      
+      <example>Brief snippet showing how to use this tag.</example>
+   </tag>
+   
+</taglib>