Index: trunk/src/templates/artifacts/Controller.groovy
===================================================================
--- trunk/src/templates/artifacts/Controller.groovy	(revision 128)
+++ trunk/src/templates/artifacts/Controller.groovy	(revision 128)
@@ -0,0 +1,4 @@
+@artifact.package@class @artifact.name@ {
+
+    def index = { }
+}
Index: trunk/src/templates/artifacts/DomainClass.groovy
===================================================================
--- trunk/src/templates/artifacts/DomainClass.groovy	(revision 128)
+++ trunk/src/templates/artifacts/DomainClass.groovy	(revision 128)
@@ -0,0 +1,5 @@
+@artifact.package@class @artifact.name@ {
+
+    static constraints = {
+    }
+}
Index: trunk/src/templates/artifacts/Filters.groovy
===================================================================
--- trunk/src/templates/artifacts/Filters.groovy	(revision 128)
+++ trunk/src/templates/artifacts/Filters.groovy	(revision 128)
@@ -0,0 +1,17 @@
+@artifact.package@class @artifact.name@ {
+
+    def filters = {
+        all(controller:'*', action:'*') {
+            before = {
+                
+            }
+            after = {
+                
+            }
+            afterView = {
+                
+            }
+        }
+    }
+    
+}
Index: trunk/src/templates/artifacts/Script.groovy
===================================================================
--- trunk/src/templates/artifacts/Script.groovy	(revision 128)
+++ trunk/src/templates/artifacts/Script.groovy	(revision 128)
@@ -0,0 +1,7 @@
+includeTargets << grailsScript("Init")
+
+target(main: "The description of the script goes here!") {
+    // TODO: Implement script here
+}
+
+setDefaultTarget(main)
Index: trunk/src/templates/artifacts/Service.groovy
===================================================================
--- trunk/src/templates/artifacts/Service.groovy	(revision 128)
+++ trunk/src/templates/artifacts/Service.groovy	(revision 128)
@@ -0,0 +1,8 @@
+@artifact.package@class @artifact.name@ {
+
+    boolean transactional = true
+
+    def serviceMethod() {
+
+    }
+}
Index: trunk/src/templates/artifacts/TagLib.groovy
===================================================================
--- trunk/src/templates/artifacts/TagLib.groovy	(revision 128)
+++ trunk/src/templates/artifacts/TagLib.groovy	(revision 128)
@@ -0,0 +1,3 @@
+@artifact.package@class @artifact.name@ {
+
+}
Index: trunk/src/templates/artifacts/Tests.groovy
===================================================================
--- trunk/src/templates/artifacts/Tests.groovy	(revision 128)
+++ trunk/src/templates/artifacts/Tests.groovy	(revision 128)
@@ -0,0 +1,15 @@
+@artifact.package@import grails.test.*
+
+class @artifact.name@ extends @artifact.superclass@ {
+    protected void setUp() {
+        super.setUp()
+    }
+
+    protected void tearDown() {
+        super.tearDown()
+    }
+
+    void testSomething() {
+
+    }
+}
Index: trunk/src/templates/artifacts/WebTest.groovy
===================================================================
--- trunk/src/templates/artifacts/WebTest.groovy	(revision 128)
+++ trunk/src/templates/artifacts/WebTest.groovy	(revision 128)
@@ -0,0 +1,54 @@
+class @webtest.name.caps@Test extends grails.util.WebTest {
+
+    // Unlike unit tests, functional tests are often sequence dependent.
+    // Specify that sequence here.
+    void suite() {
+        test@webtest.name.caps@ListNewDelete()
+        // add tests for more operations here
+    }
+
+    def test@webtest.name.caps@ListNewDelete() {
+        webtest('@webtest.name.caps@ basic operations: view list, create new entry, view, edit, delete, view') {
+            invoke(url:'@webtest.name.lower@')
+            verifyText(text:'Home')
+
+            verifyListPage(0)
+
+            clickLink(label:'New @webtest.name.caps@')
+            verifyText(text:'Create @webtest.name.caps@')
+            clickButton(label:'Create')
+            verifyText(text:'Show @webtest.name.caps@', description:'Detail page')
+            clickLink(label:'List', description:'Back to list view')
+
+            verifyListPage(1)
+
+            group(description:'edit the one element') {
+                clickLink(label:'Show', description:'go to detail view')
+                clickButton(label:'Edit')
+                verifyText(text:'Edit @webtest.name.caps@')
+                clickButton(label:'Update')
+                verifyText(text:'Show @webtest.name.caps@')
+                clickLink(label:'List', description:'Back to list view')
+            }
+
+            verifyListPage(1)
+
+            group(description:'delete the only element') {
+                clickLink(label:'Show', description:'go to detail view')
+                clickButton(label:'Delete')
+                verifyXPath(xpath:"//div[@class='message']", text:/@webtest.name.caps@.*deleted./, regex:true)
+            }
+
+            verifyListPage(0)
+        }
+    }
+
+    String ROW_COUNT_XPATH = "count(//td[@class='actionButtons']/..)"
+
+    def verifyListPage(int count) {
+        ant.group(description:"verify @webtest.name.caps@ list view with $count row(s)") {
+            verifyText(text:'@webtest.name.caps@ List')
+            verifyXPath(xpath:ROW_COUNT_XPATH, text:count, description:"$count row(s) of data expected")
+        }
+    }
+}
Index: trunk/src/templates/scaffolding/Controller.groovy
===================================================================
--- trunk/src/templates/scaffolding/Controller.groovy	(revision 128)
+++ trunk/src/templates/scaffolding/Controller.groovy	(revision 128)
@@ -0,0 +1,99 @@
+
+
+<%=packageName ? "package ${packageName}\n\n" : ''%>class ${className}Controller {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ ${propertyName}List: ${className}.list( params ), ${propertyName}Total: ${className}.count() ]
+    }
+
+    def show = {
+        def ${propertyName} = ${className}.get( params.id )
+
+        if(!${propertyName}) {
+            flash.message = "${className} not found with id \${params.id}"
+            redirect(action:list)
+        }
+        else { return [ ${propertyName} : ${propertyName} ] }
+    }
+
+    def delete = {
+        def ${propertyName} = ${className}.get( params.id )
+        if(${propertyName}) {
+            try {
+                ${propertyName}.delete()
+                flash.message = "${className} \${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "${className} \${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "${className} not found with id \${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def ${propertyName} = ${className}.get( params.id )
+
+        if(!${propertyName}) {
+            flash.message = "${className} not found with id \${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ ${propertyName} : ${propertyName} ]
+        }
+    }
+
+    def update = {
+        def ${propertyName} = ${className}.get( params.id )
+        if(${propertyName}) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(${propertyName}.version > version) {
+                    <%def lowerCaseName = grails.util.GrailsNameUtils.getPropertyName(className)%>
+                    ${propertyName}.errors.rejectValue("version", "${lowerCaseName}.optimistic.locking.failure", "Another user has updated this ${className} while you were editing.")
+                    render(view:'edit',model:[${propertyName}:${propertyName}])
+                    return
+                }
+            }
+            ${propertyName}.properties = params
+            if(!${propertyName}.hasErrors() && ${propertyName}.save()) {
+                flash.message = "${className} \${params.id} updated"
+                redirect(action:show,id:${propertyName}.id)
+            }
+            else {
+                render(view:'edit',model:[${propertyName}:${propertyName}])
+            }
+        }
+        else {
+            flash.message = "${className} not found with id \${params.id}"
+            redirect(action:edit,id:params.id)
+        }
+    }
+
+    def create = {
+        def ${propertyName} = new ${className}()
+        ${propertyName}.properties = params
+        return ['${propertyName}':${propertyName}]
+    }
+
+    def save = {
+        def ${propertyName} = new ${className}(params)
+        if(!${propertyName}.hasErrors() && ${propertyName}.save()) {
+            flash.message = "${className} \${${propertyName}.id} created"
+            redirect(action:show,id:${propertyName}.id)
+        }
+        else {
+            render(view:'create',model:[${propertyName}:${propertyName}])
+        }
+    }
+}
Index: trunk/src/templates/scaffolding/create.gsp
===================================================================
--- trunk/src/templates/scaffolding/create.gsp	(revision 128)
+++ trunk/src/templates/scaffolding/create.gsp	(revision 128)
@@ -0,0 +1,62 @@
+<% import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events %>
+<%=packageName%>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create ${className}</title>         
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><a class="home" href="\${createLinkTo(dir:'')}">Home</a></span>
+            <span class="menuButton"><g:link class="list" action="list">${className} List</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Create ${className}</h1>
+            <g:if test="\${flash.message}">
+            <div class="message">\${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="\${${propertyName}}">
+            <div class="errors">
+                <g:renderErrors bean="\${${propertyName}}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" <%= multiPart ? ' enctype="multipart/form-data"' : '' %>>
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        <%
+
+                            excludedProps = ['version',
+                                             'id',
+                                               Events.ONLOAD_EVENT,
+                                               Events.BEFORE_DELETE_EVENT,
+                                               Events.BEFORE_INSERT_EVENT,
+                                               Events.BEFORE_UPDATE_EVENT]
+                            props = domainClass.properties.findAll { !excludedProps.contains(it.name) }
+
+                            Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
+                            props.each { p ->
+                                if(!Collection.class.isAssignableFrom(p.type)) {
+                                    cp = domainClass.constrainedProperties[p.name]
+                                    display = (cp ? cp.display : true)        
+                                    if(display) { %>
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="${p.name}">${p.naturalName}:</label>
+                                </td>
+                                <td valign="top" class="value \${hasErrors(bean:${propertyName},field:'${p.name}','errors')}">
+                                    ${renderEditor(p)}
+                                </td>
+                            </tr> 
+                        <%  }   }   } %>
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: trunk/src/templates/scaffolding/edit.gsp
===================================================================
--- trunk/src/templates/scaffolding/edit.gsp	(revision 128)
+++ trunk/src/templates/scaffolding/edit.gsp	(revision 128)
@@ -0,0 +1,64 @@
+<% import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events %>
+<%=packageName%>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit ${className}</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><a class="home" href="\${createLinkTo(dir:'')}">Home</a></span>
+            <span class="menuButton"><g:link class="list" action="list">${className} List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New ${className}</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Edit ${className}</h1>
+            <g:if test="\${flash.message}">
+            <div class="message">\${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="\${${propertyName}}">
+            <div class="errors">
+                <g:renderErrors bean="\${${propertyName}}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" <%= multiPart ? ' enctype="multipart/form-data"' : '' %>>
+                <input type="hidden" name="id" value="\${${propertyName}?.id}" />
+                <input type="hidden" name="version" value="\${${propertyName}?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        <%
+                            excludedProps = ['version',
+                                             'id',
+                                               Events.ONLOAD_EVENT,
+                                               Events.BEFORE_DELETE_EVENT,
+                                               Events.BEFORE_INSERT_EVENT,
+                                               Events.BEFORE_UPDATE_EVENT]
+                            props = domainClass.properties.findAll { !excludedProps.contains(it.name) }
+                            
+                            Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
+                            props.each { p ->
+                                cp = domainClass.constrainedProperties[p.name]
+                                display = (cp ? cp.display : true)        
+                                if(display) { %>
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="${p.name}">${p.naturalName}:</label>
+                                </td>
+                                <td valign="top" class="value \${hasErrors(bean:${propertyName},field:'${p.name}','errors')}">
+                                    ${renderEditor(p)}
+                                </td>
+                            </tr> 
+                        <%  }   } %>
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: trunk/src/templates/scaffolding/list.gsp
===================================================================
--- trunk/src/templates/scaffolding/list.gsp	(revision 128)
+++ trunk/src/templates/scaffolding/list.gsp	(revision 128)
@@ -0,0 +1,60 @@
+<% import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events %>
+<%=packageName%>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>${className} List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><a class="home" href="\${createLinkTo(dir:'')}">Home</a></span>
+            <span class="menuButton"><g:link class="create" action="create">New ${className}</g:link></span>
+        </div>
+        <div class="body">
+            <h1>${className} List</h1>
+            <g:if test="\${flash.message}">
+            <div class="message">\${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        <%
+                            excludedProps = ['version',
+                                               Events.ONLOAD_EVENT,
+                                               Events.BEFORE_DELETE_EVENT,
+                                               Events.BEFORE_INSERT_EVENT,
+                                               Events.BEFORE_UPDATE_EVENT]
+                            
+                            props = domainClass.properties.findAll { !excludedProps.contains(it.name) && it.type != Set.class }
+                            Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
+                            props.eachWithIndex { p,i ->
+                   	            if(i < 6) {
+                   	                if(p.isAssociation()) { %>
+                   	        <th>${p.naturalName}</th>
+                   	    <%          } else { %>
+                   	        <g:sortableColumn property="${p.name}" title="${p.naturalName}" />
+                        <%  }   }   } %>
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="\${${propertyName}List}" status="i" var="${propertyName}">
+                        <tr class="\${(i % 2) == 0 ? 'odd' : 'even'}">
+                        <%  props.eachWithIndex { p,i ->
+                                if(i == 0) { %>
+                            <td><g:link action="show" id="\${${propertyName}.id}">\${fieldValue(bean:${propertyName}, field:'${p.name}')}</g:link></td>
+                        <%      } else if(i < 6) { %>
+                            <td>\${fieldValue(bean:${propertyName}, field:'${p.name}')}</td>
+                        <%  }   } %>
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="\${${propertyName}Total}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: trunk/src/templates/scaffolding/renderEditor.template
===================================================================
--- trunk/src/templates/scaffolding/renderEditor.template	(revision 128)
+++ trunk/src/templates/scaffolding/renderEditor.template	(revision 128)
@@ -0,0 +1,189 @@
+<%  if(property.type == Boolean.class || property.type == boolean.class)
+        out << renderBooleanEditor(domainClass,property)	
+    else if(Number.class.isAssignableFrom(property.type) || (property.type.isPrimitive() && property.type != boolean.class))
+        out << renderNumberEditor(domainClass,property)
+    else if(property.type == String.class)
+        out << renderStringEditor(domainClass,property)
+    else if(property.type == Date.class || property.type == java.sql.Date.class || property.type == java.sql.Time.class)
+        out << renderDateEditor(domainClass,property)
+    else if(property.type == Calendar.class)
+        out << renderDateEditor(domainClass,property)  
+    else if(property.type == URL.class) 
+        out << renderStringEditor(domainClass,property)
+    else if(property.isEnum())
+        out << renderEnumEditor(domainClass,property)
+    else if(property.type == TimeZone.class)
+        out << renderSelectTypeEditor("timeZone",domainClass,property)
+    else if(property.type == Locale.class)
+        out << renderSelectTypeEditor("locale",domainClass,property)
+    else if(property.type == Currency.class)
+        out << renderSelectTypeEditor("currency",domainClass,property)
+    else if(property.type==([] as Byte[]).class) //TODO: Bug in groovy means i have to do this :(
+        out << renderByteArrayEditor(domainClass,property)
+    else if(property.type==([] as byte[]).class) //TODO: Bug in groovy means i have to do this :(
+        out << renderByteArrayEditor(domainClass,property)                
+    else if(property.manyToOne || property.oneToOne)
+        out << renderManyToOne(domainClass,property)
+    else if((property.oneToMany && !property.bidirectional) || (property.manyToMany && property.isOwningSide()))
+        out << renderManyToMany(domainClass, property)
+    else if(property.oneToMany)
+        out << renderOneToMany(domainClass,property)
+
+    private renderEnumEditor(domainClass,property) {
+        if(property.isEnum()) {
+            return "<g:select  from=\"\${${property.type.name}?.values()}\" value=\"\${${domainInstance}?.${property.name}}\" name=\"${property.name}\" ${renderNoSelection(property)}></g:select>"
+        }
+    }
+
+    private renderStringEditor(domainClass, property) {
+        if(!cp) {
+            return "<input type=\"text\" name=\"${property.name}\" id=\"${property.name}\" value=\"\${fieldValue(bean:${domainInstance},field:'${property.name}')}\" />"
+        }
+        else {
+            if("textarea" == cp.widget || (cp.maxSize > 250 && !cp.password && !cp.inList)) {
+                return "<textarea rows=\"5\" cols=\"40\" name=\"${property.name}\">\${fieldValue(bean:${domainInstance}, field:'${property.name}')}</textarea>"
+            }
+             else {
+                if(cp.inList) {
+                    def sb = new StringBuffer('<g:select ')
+                    sb << "id=\"${property.name}\" name=\"${property.name}\" from=\"\${${domainInstance}.constraints.${property.name}.inList}\" value=\"\${${domainInstance}.${property?.name}}\" ${renderNoSelection(property)}>"
+                    sb << '</g:select>'
+                    return sb.toString()
+                }
+                else {
+                    def sb = new StringBuffer('<input ')
+                    cp.password ? sb << 'type="password" ' : sb << 'type="text" '
+                    if(!cp.editable) sb << 'readonly="readonly" '
+                    if(cp.maxSize) sb << "maxlength=\"${cp.maxSize}\" "
+                    sb << "id=\"${property.name}\" name=\"${property.name}\" value=\"\${fieldValue(bean:${domainInstance},field:'${property.name}')}\"/>"
+                    return sb.toString()
+                }
+            }
+        }
+    }
+
+    private renderByteArrayEditor(domainClass,property) {
+        return "<input type=\"file\" id=\"${property.name}\" name=\"${property.name}\" />"
+    }
+
+    private renderManyToOne(domainClass,property) {
+        if(property.association) {
+            return "<g:select optionKey=\"id\" from=\"\${${property.type.name}.list()}\" name=\"${property.name}.id\" value=\"\${${domainInstance}?.${property.name}?.id}\" ${renderNoSelection(property)}></g:select>"
+        }
+    }
+
+    private renderManyToMany(domainClass,property) {
+        def sw = new StringWriter()
+        def pw = new PrintWriter(sw)
+
+        pw.println "<g:select name=\"${property.name}\""
+        pw.println "from=\"\${${property.referencedDomainClass.fullName}.list()}\""
+        pw.println "size=\"5\" multiple=\"yes\" optionKey=\"id\""
+        pw.println "value=\"\${${domainInstance}?.${property.name}}\" />"
+
+        return sw.toString()         
+    }
+
+    private renderOneToMany(domainClass,property) {
+        def sw = new StringWriter()
+        def pw = new PrintWriter(sw)
+        pw.println()
+        pw.println "<ul>"
+        pw.println "<g:each var=\"${property.name[0]}\" in=\"\${${domainInstance}?.${property.name}?}\">"
+        pw.println "    <li><g:link controller=\"${property.referencedDomainClass.propertyName}\" action=\"show\" id=\"\${${property.name[0]}.id}\">\${${property.name[0]}?.encodeAsHTML()}</g:link></li>"
+        pw.println "</g:each>"
+        pw.println "</ul>"
+        pw.println "<g:link controller=\"${property.referencedDomainClass.propertyName}\" params=\"['${domainClass.propertyName}.id':${domainInstance}?.id]\" action=\"create\">Add ${property.referencedDomainClass.shortName}</g:link>"
+        return sw.toString()
+    }
+
+    private renderNumberEditor(domainClass,property) {
+        if(!cp) {
+            if(property.type == Byte.class) {
+                return "<g:select from=\"\${-128..127}\" name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></g:select>"
+            }
+            else {
+                return "<input type=\"text\" id=\"${property.name}\" name=\"${property.name}\" value=\"\${fieldValue(bean:${domainInstance},field:'${property.name}')}\" />"
+            }
+        }
+        else {
+            if(cp.range) {
+                return "<g:select from=\"\${${cp.range.from}..${cp.range.to}}\" id=\"${property.name}\" name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)}></g:select>"
+            }
+            else if(cp.inList) {
+                def sb = new StringBuffer('<g:select ')
+                sb << "id=\"${property.name}\" name=\"${property.name}\" from=\"\${${domainClass.propertyName}.constraints.${property.name}.inList}\" value=\"\${${domainClass.propertyName}.${property?.name}}\" ${renderNoSelection(property)}>"
+                sb << '</g:select>'
+                return sb.toString()
+            }            
+            else {
+                return "<input type=\"text\" id=\"${property.name}\" name=\"${property.name}\" value=\"\${fieldValue(bean:${domainInstance},field:'${property.name}')}\" />"
+            }
+        }
+     }
+
+    private renderBooleanEditor(domainClass,property) {
+        if(!cp) {
+            return "<g:checkBox name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></g:checkBox>"
+        }
+        else {
+            def buf = new StringBuffer('<g:checkBox ')
+            if(cp.widget) buf << "widget=\"${cp.widget}\"";
+
+            buf << "name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" "
+            cp.attributes.each { k,v ->
+                buf << "${k}=\"${v}\" "
+            }
+            buf << '></g:checkBox>'
+            return buf.toString()
+        }
+    }
+
+    private renderDateEditor(domainClass,property) {
+        if(!cp) {
+            return "<g:datePicker name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></g:datePicker>"
+        }
+        else {
+            if(!cp.editable) {
+                return "\${${domainInstance}?.${property.name}?.toString()}"
+            }
+            else {
+                def buf = new StringBuffer('<g:datePicker ')
+                if(cp.widget) buf << "widget=\"${cp.widget}\" "
+                if(cp.format) buf << "format=\"${cp.format}\" "
+                cp.attributes.each { k,v ->
+                    buf << "${k}=\"${v}\" "
+                }
+                buf << "name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)}></g:datePicker>"
+                return buf.toString()
+            }
+        }
+    }
+
+    private renderSelectTypeEditor(type,domainClass,property) {
+        if(!cp) {
+            return "<g:${type}Select name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></g:${type}Select>"
+        }
+        else {
+            def buf = new StringBuffer("<g:${type}Select ")
+            if(cp.widget) buf << "widget=\"${cp.widget}\" ";
+            cp.attributes.each { k,v ->
+                buf << "${k}=\"${v}\" "
+            }
+            buf << "name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)}></g:${type}Select>"
+            return buf.toString()
+        }
+    }
+
+    private renderNoSelection(property) {
+        if(property.optional) {
+            if(property.manyToOne || property.oneToOne) {
+                return "noSelection=\"['null':'']\""				
+            }
+            else {
+                return "noSelection=\"['':'']\""
+            }
+        }
+        return ""
+    }
+%>
Index: trunk/src/templates/scaffolding/show.gsp
===================================================================
--- trunk/src/templates/scaffolding/show.gsp	(revision 128)
+++ trunk/src/templates/scaffolding/show.gsp	(revision 128)
@@ -0,0 +1,64 @@
+<% import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events %>
+<%=packageName%>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show ${className}</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><a class="home" href="\${createLinkTo(dir:'')}">Home</a></span>
+            <span class="menuButton"><g:link class="list" action="list">${className} List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New ${className}</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Show ${className}</h1>
+            <g:if test="\${flash.message}">
+            <div class="message">\${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    <%
+                        excludedProps = ['version',
+                                           Events.ONLOAD_EVENT,
+                                           Events.BEFORE_DELETE_EVENT,
+                                           Events.BEFORE_INSERT_EVENT,
+                                           Events.BEFORE_UPDATE_EVENT]
+                        props = domainClass.properties.findAll { !excludedProps.contains(it.name) }
+                        Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
+                        props.each { p -> %>
+                        <tr class="prop">
+                            <td valign="top" class="name">${p.naturalName}:</td>
+                            <% if(p.isEnum()) { %>
+                            <td valign="top" class="value">\${${propertyName}?.${p.name}?.encodeAsHTML()}</td>
+                            <% } else if(p.oneToMany || p.manyToMany) { %>
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="${p.name[0]}" in="\${${propertyName}.${p.name}}">
+                                    <li><g:link controller="${p.referencedDomainClass?.propertyName}" action="show" id="\${${p.name[0]}.id}">\${${p.name[0]}?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            <%  } else if(p.manyToOne || p.oneToOne) { %>
+                            <td valign="top" class="value"><g:link controller="${p.referencedDomainClass?.propertyName}" action="show" id="\${${propertyName}?.${p.name}?.id}">\${${propertyName}?.${p.name}?.encodeAsHTML()}</g:link></td>
+                            <%  } else  { %>
+                            <td valign="top" class="value">\${fieldValue(bean:${propertyName}, field:'${p.name}')}</td>
+                            <%  } %>
+                        </tr>
+                    <%  } %>
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="\${${propertyName}?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: trunk/src/templates/war/web.xml
===================================================================
--- trunk/src/templates/war/web.xml	(revision 128)
+++ trunk/src/templates/war/web.xml	(revision 128)
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+         xmlns="http://java.sun.com/xml/ns/j2ee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+    <display-name>/@grails.project.key@</display-name>
+
+
+    <context-param>
+        <param-name>contextConfigLocation</param-name>
+        <param-value>/WEB-INF/applicationContext.xml</param-value>
+    </context-param>
+
+    <context-param>
+        <param-name>webAppRootKey</param-name>
+        <param-value>@grails.project.key@</param-value>
+    </context-param>
+
+    <filter>
+        <filter-name>sitemesh</filter-name>
+        <filter-class>org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter</filter-class>
+    </filter>
+
+    <filter>
+        <filter-name>charEncodingFilter</filter-name>
+        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
+        <init-param>
+            <param-name>targetBeanName</param-name>
+            <param-value>characterEncodingFilter</param-value>
+        </init-param>
+        <init-param>
+            <param-name>targetFilterLifecycle</param-name>
+            <param-value>true</param-value>
+        </init-param>
+    </filter>
+
+    <filter-mapping>
+        <filter-name>charEncodingFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>sitemesh</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+    <listener>
+        <listener-class>org.codehaus.groovy.grails.web.util.Log4jConfigListener</listener-class>
+    </listener>
+
+    <listener>
+        <listener-class>org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener</listener-class>
+    </listener>
+
+    <!-- Grails dispatcher servlet -->
+    <servlet>
+        <servlet-name>grails</servlet-name>
+        <servlet-class>org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet</servlet-class>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <!-- The Groovy Server Pages servlet -->
+    <servlet>
+        <servlet-name>gsp</servlet-name>
+        <servlet-class>org.codehaus.groovy.grails.web.pages.GroovyPagesServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>gsp</servlet-name>
+        <url-pattern>*.gsp</url-pattern>
+    </servlet-mapping>
+
+    <welcome-file-list>
+        <!--
+        The order of the welcome pages is important.  JBoss deployment will
+        break if index.gsp is first in the list.
+        -->
+        <welcome-file>index.html</welcome-file>
+        <welcome-file>index.jsp</welcome-file>
+        <welcome-file>index.gsp</welcome-file>
+    </welcome-file-list>
+
+    <jsp-config>
+        <taglib>
+            <taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
+            <taglib-location>/WEB-INF/tld/c.tld</taglib-location>
+        </taglib>
+        <taglib>
+            <taglib-uri>http://java.sun.com/jsp/jstl/fmt</taglib-uri>
+            <taglib-location>/WEB-INF/tld/fmt.tld</taglib-location>
+        </taglib>
+        <taglib>
+            <taglib-uri>http://www.springframework.org/tags</taglib-uri>
+            <taglib-location>/WEB-INF/tld/spring.tld</taglib-location>
+        </taglib>
+        <taglib>
+            <taglib-uri>http://grails.codehaus.org/tags</taglib-uri>
+            <taglib-location>/WEB-INF/tld/grails.tld</taglib-location>
+        </taglib>
+    </jsp-config>
+
+</web-app>
