Changeset 1175

Show
Ignore:
Timestamp:
19-11-10 11:51:09 (3 years ago)
Author:
robert@…
Message:

The templateeditor is now capable of adding new items to a stringlist (that is in use), or adding new ontologies to a ontologyterm field that is in use. See ticket #74

Location:
trunk/grails-app
Files:
9 modified

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/dbnp/studycapturing/TemplateEditorController.groovy

    r1159 r1175  
    401401                        def listEntries = []; 
    402402                        params.listEntries.eachLine { 
    403                                 // Search whether a listitem with this name already exists. 
    404                                 // if it does, use that one to prevent pollution of the database 
     403                                // We don't search for a listitem that might already exist, 
     404                                // because if we use that list item, it will be removed from the 
     405                                // other string list.  
    405406                                def name = it.trim(); 
    406                                 def listitem = TemplateFieldListItem.findByName( name );7 
    407                                 if( !listitem ) { 
    408                                         listitem = new TemplateFieldListItem( name: name ) 
    409                                 } 
     407 
     408                                def listitem = new TemplateFieldListItem( name: name ) 
    410409                                listEntries.add( listitem ); 
    411410                        } 
     
    466465 
    467466                // If this field is type stringlist or ontology, we have to prepare the parameters 
    468                 if( params.type.toString() == 'STRINGLIST' ) { 
     467                // 
     468                // For stringlist and ontologyterm fields, the list items can be changed, even when the field is in use 
     469                // In that case, only never-used items can be removed or changed and items can be added. If that is the case 
     470                // params.is_disabled is true and we should combine listEntries and extraListEntries with the items already in use. 
     471                if( params.type.toString() == 'STRINGLIST' || ( templateField.type == TemplateFieldType.STRINGLIST && params.is_disabled) ) { 
     472                        def listEntryLines = ""; 
    469473                        def listEntries = []; 
    470                         params.listEntries.eachLine { 
    471                                 // Search whether a listitem with this name already exists. 
    472                                 // if it does, use that one to prevent pollution of the database 
    473                                 def name = it.trim(); 
    474                                 def listitem = TemplateFieldListItem.findByName( name );7 
    475                                 if( !listitem ) { 
    476                                         listitem = new TemplateFieldListItem( name: name ) 
     474 
     475                        if( params.is_disabled ) { 
     476                                listEntries = templateField.getUsedListEntries(); 
     477                        } 
     478 
     479                        if( params.listEntries ) { 
     480                                listEntryLines = params.listEntries; 
     481                                 
     482                                listEntryLines.eachLine { 
     483                                        // We don't search for a listitem that might already exist, 
     484                                        // because if we use that list item, it will be removed from the 
     485                                        // other string list. We only search for an item that already 
     486                                        // belongs to this list. 
     487                                        def name = it.trim(); 
     488 
     489                                        def c = TemplateFieldListItem.createCriteria() 
     490                                        def listitem = c.get { 
     491                                                eq( "name", name ) 
     492                                                eq( "parent", templateField) 
     493                                        } 
     494                                        if( !listitem ) { 
     495                                                listitem = new TemplateFieldListItem( name: name ) 
     496                                        } 
     497 
     498                                        // Prevent using the same list entry twice 
     499                                        if( !listEntries.contains( listitem ) ) 
     500                                                listEntries.add( listitem ); 
    477501                                } 
    478                                 listEntries.add( listitem ); 
    479502                        } 
    480503 
     504                        // Add listEntries to the templateField 
    481505                        params.listEntries = listEntries; 
    482506                } else { 
     
    485509 
    486510                // If this field is a ontologyterm, we add ontology objects 
    487                 if( params.type.toString() == 'ONTOLOGYTERM' && params.ontologies ) { 
    488                         params.ontologies = Ontology.getAll( params.ontologies.collect { Integer.parseInt( it ) } ); 
     511                // For stringlist and ontologyterm fields, the list items can be changed, even when the field is in use 
     512                // In that case, only never-used items can be removed or changed and items can be added. If that is the case 
     513                // params.is_disabled is true and we should combine ontologies with the ontologies already in use. 
     514                if( ( params.type.toString() == 'ONTOLOGYTERM' || ( templateField.type == TemplateFieldType.ONTOLOGYTERM && params.is_disabled ) ) && params.ontologies ) { 
     515                        def usedOntologies = []; 
     516 
     517                        if( params.is_disabled ) { 
     518                                usedOntologies = templateField.getUsedOntologies(); 
     519                        } 
     520 
     521                        if( params.ontologies ) { 
     522                                def ontologies = params.ontologies; 
     523         
     524                                params.ontologies = usedOntologies + Ontology.getAll( ontologies.collect { Integer.parseInt( it ) } ); 
     525                        } 
     526 
    489527                } else { 
    490528                        params.remove( 'ontologies' ); 
    491529                } 
    492530 
     531                // A field that is already used in one or more templates, but is not filled everywhere, 
     532                // can not be set to required 
     533                if( params.required ) { 
     534                        if( !templateField.isFilledInAllObjects() ) { 
     535                                response.status = 500; 
     536                                render "A field can only be marked as required if all objects using this field have a value for the field." 
     537                                return 
     538                        } 
     539                } 
     540 
    493541                // Set all parameters 
    494542                templateField.properties = params 
     543 
     544                templateField.validate(); 
     545                 
     546 
    495547        if (!templateField.hasErrors() && templateField.save(flush: true)) { 
     548 
     549                        // Remove all orphaned list items, because grails doesn't handle it for us 
     550                        TemplateFieldListItem.findAllByParent( templateField ).each { 
     551                                if( !params.listEntries.contains( it ) ) { 
     552                                        templateField.removeFromListEntries( it ); 
     553                                        it.delete(); 
     554                                } 
     555                        } 
    496556 
    497557                        // Select the template to use for the HTML output 
     
    511571        } else { 
    512572            response.status = 500; 
    513             render 'TemplateField was not updated because errors occurred.'; 
     573            render 'TemplateField was not updated because errors occurred. Please contact the system administrator'; 
    514574            return 
    515575        } 
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateEntity.groovy

    r1167 r1175  
    600600                        // iterate through ontologies and find term 
    601601                        field.ontologies.each() { ontology -> 
    602                                 def term = ontology.giveTermByName(value) 
    603  
    604                                 // found a term? 
    605                                 if (term) { 
    606                                         value = term 
    607                                 } 
     602                                // If we've found a term already, value.class == Term. In that case, 
     603                                // we shouldn't look further. Unfortunately, groovy doesn't support breaking out of 
     604                                // each(), so we check it on every iteration. 
     605                                if( value.class == String ) { 
     606                                        def term = ontology.giveTermByName(value) 
     607 
     608                                        // found a term? 
     609                                        if (term) { 
     610                                                value = term 
     611                                        } 
     612                                } 
     613                        } 
     614 
     615                        // If the term is not found in any ontology 
     616                        if( value.class == String ) { 
    608617                                // TODO: search ontology for the term online (it may still exist) and insert it into the Term cache 
    609618                                // if not found, throw exception 
    610                                 else { 
    611                                         throw new IllegalArgumentException("Ontology term not recognized (not in the GSCF ontology cache): ${value} when setting field ${fieldName}") 
    612                                 } 
     619                                throw new IllegalArgumentException("Ontology term not recognized (not in the GSCF ontology cache): ${value} when setting field ${fieldName}") 
    613620                        } 
    614621                } 
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateField.groovy

    r1160 r1175  
    7676                entity column:"templatefieldentity" 
    7777                unit column:"templatefieldunit" 
    78                 comment column:"templatefieldcomment"                 
     78                comment column:"templatefieldcomment" 
    7979        } 
    8080 
     
    109109 
    110110        /** 
     111         * Retrieves all list items of a stringlist template field that have been used in an object 
     112         *  
     113         * @return      ArrayList containing all list items of this template field that have been used in an object. 
     114         */ 
     115        def getUsedListEntries() { 
     116                if( this.type != TemplateFieldType.STRINGLIST ) 
     117                        return [] 
     118 
     119                return this.listEntries.findAll { this.entryUsed( it ) } 
     120        } 
     121 
     122        /** 
     123         * Retrieves all list items of a stringlist template field that have never been used in an object 
     124         * 
     125         * @return      ArrayList containing all list items of this template field that have nevert been used in an object. 
     126         */ 
     127        def getNonUsedListEntries() { 
     128                if( this.type != TemplateFieldType.STRINGLIST ) 
     129                        return [] 
     130                 
     131                return this.listEntries.findAll { !this.entryUsed( it ) } 
     132        } 
     133 
     134        /** 
     135         * Retrieves all ontologies of an ontologyterm template field that have been used in an object 
     136         * 
     137         * @return      ArrayList containing all ontologies of this template field that have been used in an object 
     138         *                      (i.e. all ontologies from which a term has been selected in this template field). 
     139         */ 
     140        def getUsedOntologies() { 
     141                if( this.type != TemplateFieldType.ONTOLOGYTERM ) 
     142                        return [] 
     143 
     144                return this.ontologies.findAll { this.entryUsed( it ) } 
     145        } 
     146 
     147        /** 
     148         * Retrieves all list items of an ontologyterm template field that have never been used in an object 
     149         * 
     150         * @return      ArrayList containing all ontologies of this template field that have never been used in an object. 
     151         *                      (i.e. all ontologies from which no term has been selected in this template field). 
     152         */ 
     153        def getNonUsedOntologies() { 
     154                if( this.type != TemplateFieldType.ONTOLOGYTERM ) 
     155                        return [] 
     156 
     157                return this.ontologies.findAll { !this.entryUsed( it ) } 
     158        } 
     159 
     160        /** 
    111161         * Checks whether this template field is used in a template 
    112162         * 
     
    151201         */ 
    152202        def isFilled() { 
    153                 // Find all entities that use this template 
     203                // Find all templates that use this template field 
    154204                def templates = getUses(); 
    155205 
     
    157207                        return false; 
    158208 
     209                // Find all entities that use these templates 
    159210                def c = this.entity.createCriteria() 
    160211                def entities = c { 
     
    186237 
    187238                return filledEntities.size() > 0; 
     239        } 
     240 
     241        /** 
     242         * Checks whether this template field is filled in all objects using a template with this template field 
     243         * If the template field is never used, the method returns true. If the template field is used in a template, 
     244         * but no objects with this template exist, the method also returns true 
     245         * 
     246         * @returns             false iff objects exist using this template field, but without a value for this field. true otherwise 
     247         */ 
     248        def isFilledInAllObjects() { 
     249                // Find all templates that use this entity 
     250                def templates = getUses(); 
     251 
     252                if( templates.size() == 0 ) 
     253                        return true; 
     254 
     255                // Find all entities that use these templates 
     256                def c = this.entity.createCriteria() 
     257                def entities = c { 
     258                        'in'("template",templates) 
     259                } 
     260 
     261                if( entities.size() == 0 ) 
     262                        return true; 
     263 
     264                def emptyEntities = entities.findAll { entity -> !entity.getFieldValue( this.name ) } 
     265 
     266                return ( emptyEntities.size() == 0 ); 
    188267        } 
    189268 
     
    211290         */ 
    212291        def entryUsed(TemplateFieldListItem item) { 
    213                 //return numUses() > 0; 
     292                if( this.type != TemplateFieldType.STRINGLIST ) 
     293                        return false; 
     294 
     295                // Find all templates that use this template field 
     296                def templates = getUses(); 
     297 
     298                if( templates.size() == 0 ) 
     299                        return false; 
     300 
     301                // Find all entities that use these templates 
     302                def c = this.entity.createCriteria() 
     303                def entities = c { 
     304                        'in'("template",templates) 
     305                } 
     306 
     307                if( entities.size() == 0 )  
     308                        return false 
     309                         
     310                def entitiesWithListItem = entities.findAll { entity -> entity.getFieldValue( this.name ).equals( item ) } 
     311 
     312                return entitiesWithListItem.size() > 0; 
    214313        } 
    215314 
     
    220319         * @returns                     true iff the ontology is part of this template field and a term from the given 
    221320         *                                      ontology is selected in an entity where this template field is used. false otherwise 
    222          *                                      Returns false if the type of this template field is other than ONTOLOGY 
     321         *                                      Returns false if the type of this template field is other than ONTOLOGYTERM 
    223322         */ 
    224323        def entryUsed(Ontology item) { 
    225                 //return numUses() > 0; 
     324                if( this.type != TemplateFieldType.ONTOLOGYTERM ) 
     325                        return false; 
     326 
     327                // Find all templates that use this template field 
     328                def templates = getUses(); 
     329 
     330                // If the template field is never used in a template, it will also never 
     331                // be filled, and this Ontology will never be used 
     332                if( templates.size() == 0 ) 
     333                        return false; 
     334 
     335                // Find all entities that use these templates 
     336                def c = this.entity.createCriteria() 
     337                def entities = c { 
     338                        'in'("template",templates) 
     339                } 
     340 
     341                if( entities.size() == 0 ) 
     342                        return false 
     343 
     344                def entitiesWithOntology = entities.findAll { entity ->  
     345                        def value = entity.getFieldValue( this.name ); 
     346                        if( value )  
     347                                return value.ontology.equals( item ) 
     348                        else 
     349                                return false; 
     350                } 
     351 
     352                return entitiesWithOntology.size() > 0; 
    226353        } 
    227354 
  • trunk/grails-app/views/templateEditor/elements/_disabledFieldForm.gsp

    r959 r1175  
     1        <g:hiddenField name="id" value="${templateField?.id}" /> 
     2        <g:hiddenField name="version" value="${templateField?.version}" /> 
     3        <g:hiddenField name="is_disabled" value="1" /> 
     4        <g:if test="${is_selected}"><g:hiddenField name="renderTemplate" value="selected" /></g:if> 
     5        <g:if test="${template}"><g:hiddenField name="templateId" value="${template.id}" /></g:if> 
     6 
    17        <label for="name">Name:</label> <g:textField disabled="disabled" name="name" value="${templateField?.name}" /><br /> 
    28        <label for="type">Type:</label> <g:textField disabled="disabled" name="type" value="${templateField?.type}" /><br /> 
    39 
    410        <div class="extra stringlist_options" <g:if test="${templateField?.type.toString() == 'STRINGLIST'}">style='display: block;'</g:if>> 
    5           <label for="type">Items:</label> 
    6                 <g:textArea name="listEntries" disabled="disabled" value="${templateField?.listEntries?.name?.join( '\n' )}" /> 
     11          <label for="type">Used items:</label> 
     12                <g:textArea name="usedListEntries" disabled="disabled" value="${templateField?.getUsedListEntries().name?.join( '\n' )}" /> 
     13          <label for="type">Extra Items (every item on a new line):</label> 
     14                <g:textArea name="listEntries" value="${templateField?.getNonUsedListEntries().name?.join( '\n' )}" /> 
    715        </div> 
    816        <div class="extra ontologyterm_options" <g:if test="${templateField?.type.toString() == 'ONTOLOGYTERM'}">style='display: block;'</g:if>> 
    9           <label for="type">Ontology:</label> <g:textArea name="ontology" disabled="disabled" value="${templateField?.ontologies?.name?.join( '\n' )}" /><br /> 
     17          <label for="type">Used ontologies:</label> <g:textArea name="ontology" disabled="disabled" value="${templateField?.getUsedOntologies().name?.join( '\n' )}" /><br /> 
     18 
     19          <label for="type">Extra ontologies:<br /><br /><a href="#" style="text-decoration: underline;" onClick="openOntologyDialog();">Add new</a></label> 
     20                <g:select multiple="yes" size="5" from="${ontologies - templateField?.getUsedOntologies()}" class="ontologySelect" optionValue="name" optionKey="id" name="ontologies" id="ontologies_${templateField?.id}" value="${templateField?.getNonUsedOntologies()}" /><br /> 
     21 
    1022        </div> 
    1123         
     
    1325        <label for="comment">Comment:</label> <g:textArea disabled="disabled" name="comment" value="${templateField?.comment}" /><br /> 
    1426        <label for="required">Required:</label> <input type="checkbox" disabled <g:if test="${templateField?.required}">checked</g:if><br /> 
     27 
     28        <div class="templateFieldButtons"> 
     29          <g:if test="${ templateField?.type.toString() == 'STRINGLIST' || templateField?.type.toString() == 'ONTOLOGYTERM' }"> 
     30                <input type="button" value="Save" onClick="updateTemplateField( ${templateField?.id} );"> 
     31                <input type="button" value="Close" onClick="hideTemplateFieldForm( ${templateField?.id} );"> 
     32          </g:if> 
     33          <g:else> 
     34                <input type="button" value="Close" onClick="hideTemplateFieldForm( ${templateField?.id} );"> 
     35          </g:else> 
     36        </div> 
  • trunk/grails-app/views/templateEditor/elements/_fieldForm.gsp

    r1056 r1175  
    1         <label for="name">Name:</label> <g:textField name="name" value="${templateField?.name}" /><br /> 
     1  <g:hiddenField name="id" value="${templateField?.id}" /> 
     2  <g:hiddenField name="version" value="${templateField?.version}" /> 
     3  <g:if test="${is_new}"><g:hiddenField name="entity" value="${encryptedEntity}" /></g:if> 
     4  <g:if test="${is_selected}"><g:hiddenField name="renderTemplate" value="selected" /></g:if> 
     5  <g:if test="${template}"><g:hiddenField name="templateId" value="${template.id}" /></g:if> 
     6<label for="name">Name:</label> <g:textField name="name" value="${templateField?.name}" /><br /> 
    27        <label for="type">Type:</label> 
    38          <% 
     
    3742        <label for="comment">Comment:</label> <g:textArea name="comment" value="${templateField?.comment}" /><br /> 
    3843        <label for="required">Required:</label> <g:checkBox name="required" value="${templateField?.required}" /><br /> 
     44 
     45        <div class="templateFieldButtons"> 
     46          <g:if test="${is_new}"> 
     47                <input type="button" value="Save" onClick="createTemplateField( 'new' );"> 
     48                <input type="button" value="Cancel" onClick="hideTemplateFieldForm( 'new' );"> 
     49          </g:if> 
     50          <g:else> 
     51                <input type="button" value="Save" onClick="updateTemplateField( ${templateField?.id} );"> 
     52                <input type="button" value="Close" onClick="hideTemplateFieldForm( ${templateField?.id} );"> 
     53          </g:else> 
     54        </div> 
  • trunk/grails-app/views/templateEditor/elements/_liFieldInUse.gsp

    r1159 r1175  
    1010     
    1111<form class="templateField_form" id="templateField_${templateField.id}_form" action="updateField"> 
    12         <g:hiddenField name="id" value="${templateField.id}" /> 
    13         <g:hiddenField name="version" value="${templateField.version}" /> 
    14         <p class="noEditsPossible">Editing not possible. Field is used in ${numUses} template(s).</p> 
    15         <g:render template="elements/disabledFieldForm" model="['templateField': templateField, 'ontologies': ontologies, 'fieldTypes': fieldTypes]"/> 
    16         <div class="templateFieldButtons"> 
    17                 <input type="button" value="Close" onClick="hideTemplateFieldForm( ${templateField.id} );"> 
    18         </div> 
     12  <g:if test="${ templateField?.type.toString() == 'STRINGLIST' }"> 
     13    <p class="noEditsPossible">You can only add or remove list items that are not used. Field is used in ${numUses} template(s).</p> 
     14  </g:if> 
     15  <g:else> 
     16    <g:if test="${templateField?.type.toString() == 'ONTOLOGYTERM' }"> 
     17    <p class="noEditsPossible">You can only add or remove ontologies that are not used. Field is used in ${numUses} template(s).</p> 
     18        </g:if> 
     19        <g:else> 
     20          <p class="noEditsPossible">Editing not possible. Field is used in ${numUses} template(s).</p> 
     21        </g:else> 
     22  </g:else> 
     23  <g:render template="elements/disabledFieldForm" model="['templateField': templateField, 'ontologies': ontologies, 'fieldTypes': fieldTypes]"/> 
    1924</form> 
    2025 
  • trunk/grails-app/views/templateEditor/elements/_liFieldNotInUse.gsp

    r1159 r1175  
    99 
    1010<form class="templateField_form" id="templateField_${templateField.id}_form" action="updateField"> 
    11         <g:hiddenField name="id" value="${templateField.id}" /> 
    12         <g:hiddenField name="version" value="${templateField.version}" /> 
    1311        <g:render template="elements/fieldForm" model="['templateField': templateField, 'ontologies': ontologies, 'fieldTypes': fieldTypes]"/> 
    14         <div class="templateFieldButtons"> 
    15                 <input type="button" value="Save" onClick="updateTemplateField( ${templateField.id} );"> 
    16                 <input type="button" value="Close" onClick="hideTemplateFieldForm( ${templateField.id} );"> 
    17         </div> 
    1812</form> 
  • trunk/grails-app/views/templateEditor/elements/_liFieldSelected.gsp

    r1159 r1175  
    1515  <form class="templateField_form" id="templateField_${templateField.id}_form" action="updateField"> 
    1616          <g:if test="${templateField.isEditable()}"> 
    17                 <g:hiddenField name="id" value="${templateField.id}" /> 
    18                 <g:hiddenField name="version" value="${templateField.version}" /> 
    19                 <g:hiddenField name="renderTemplate" value="selected" /> 
    20                 <g:hiddenField name="templateId" value="${template.id}" /> 
    21                 <g:render template="elements/fieldForm" model="['templateField': templateField, 'ontologies': ontologies, 'fieldTypes': fieldTypes]"/> 
    22                 <div class="templateFieldButtons"> 
    23                         <input type="button" value="Save" onClick="updateTemplateField( ${templateField.id} );"> 
    24                         <input type="button" value="Close" onClick="hideTemplateFieldForm( ${templateField.id} );"> 
    25                 </div> 
     17                <g:render template="elements/fieldForm" model="['templateField': templateField, 'template': template, 'is_selected': true, 'ontologies': ontologies, 'fieldTypes': fieldTypes]" /> 
    2618          </g:if> 
    2719        <g:else> 
    28                 <g:render template="elements/disabledFieldForm" model="['templateField': templateField, 'ontologies': ontologies, 'fieldTypes': fieldTypes]"/> 
    29                 <div class="templateFieldButtons"> 
    30                         <input type="button" value="Close" onClick="hideTemplateFieldForm( ${templateField.id} );"> 
    31                 </div> 
     20                <g:render template="elements/disabledFieldForm" model="['templateField': templateField, 'template': template, 'is_selected': true, 'ontologies': ontologies, 'fieldTypes': fieldTypes]"/> 
    3221        </g:else> 
    3322  </form> 
  • trunk/grails-app/views/templateEditor/template.gsp

    r1153 r1175  
    112112 
    113113                                        <form class="templateField_form" id="templateField_new_form" action="createField"> 
    114                                                 <g:hiddenField name="entity" value="${encryptedEntity}" /> 
    115                                                 <g:render template="elements/fieldForm" model="['templateField': null, 'fieldTypes': fieldTypes]"/> 
    116                                                 <div class="templateFieldButtons"> 
    117                                                         <input type="button" value="Save" onClick="createTemplateField( 'new' );"> 
    118                                                         <input type="button" value="Cancel" onClick="hideTemplateFieldForm( 'new' );"> 
    119                                                 </div> 
     114                                                <g:render template="elements/fieldForm" model="['templateField': null, 'fieldTypes': fieldTypes, 'encryptedEntity': encryptedEntity, 'is_new': true]"/> 
    120115                                        </form> 
    121116                                </div>