Ignore:
Timestamp:
May 27, 2010, 4:03:31 PM (10 years ago)
Author:
roberth
Message:

Added net RELTIME template field type to contain relative times (e.g. 1d 3h). The type has been added as template type, but will probably not be rendered correctly yet.

Location:
trunk/grails-app/domain/dbnp/studycapturing
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateEntity.groovy

    r453 r487  
    2121        Map templateDoubleFields = [:]
    2222        Map templateDateFields = [:]
     23        Map templateRelTimeFields = [:] // Contains relative times in seconds
    2324        Map templateTermFields = [:]
    2425
     
    3233                templateDateFields: Date,
    3334                templateTermFields: Term,
     35                templateRelTimeFields: long,
    3436                systemFields: TemplateField
    3537        ]
     
    200202                        return (!error)
    201203                })
     204                templateRelTimeFields(validator: { fields, obj, errors ->
     205                        def error = false
     206                        fields.each { key, value ->
     207                                if ( value && value.class != long ) {
     208                                        try {
     209                                                fields[key] = (value as long)
     210                                        } catch (Exception e) {
     211                                                error = true
     212                                                errors.rejectValue(
     213                                                        'templateRelTimeFields',
     214                                                        'templateEntity.typeMismatch.reltime',
     215                                                        [key, value.class] as Object[],
     216                                                        'Property {0} must be of type long and is currently of type {1}'
     217                                                )
     218                                        }
     219                                }
     220                        }
     221                        return (!error)
     222                })
    202223                templateTermFields(validator: { fields, obj, errors ->
    203224                        def error = false
     
    228249         * @throws NoSuchFieldException
    229250         */
    230         private Map getStore(TemplateFieldType fieldType) {
     251        public Map getStore(TemplateFieldType fieldType) {
    231252                switch(fieldType) {
    232253                        case TemplateFieldType.STRING:
     
    240261                        case TemplateFieldType.DATE:
    241262                                return templateDateFields
     263                        case TemplateFieldType.RELTIME:
     264                                return templateRelTimeFields
    242265                        case TemplateFieldType.FLOAT:
    243266                                return templateFloatFields
     
    353376                }
    354377
     378                // Magic setter for relative times: handle string values for relTime fields
     379                //
     380                // The relative time may be set as a string, using the following format
     381                //
     382                //    #w #d #h #m #s
     383                //
     384                // Where w = weeks, d = days, h = hours, m = minutes, s = seconds
     385                //
     386                // The spaces between the values are optional. Every timespan
     387                // (w, d, h, m, s) must appear at most once. You can also omit
     388                // timespans if needed or use a different order.
     389                // Other characters are disregarded, allthough results may not
     390                // always be as expected.
     391                // 
     392                // If an incorrect format is used, which can't be parsed
     393                // an IllegalArgumentException is thrown.
     394                //
     395                // An empty span is treated as zero seconds.
     396                //
     397                // Examples:
     398                // ---------
     399                //    5d 3h 20m     // 5 days, 3 hours and 20 minutes
     400                //    6h 2d         // 2 days, 6 hours
     401                //    10m 200s      // 13 minutes, 20 seconds (200s == 3m + 20s)
     402                //    5w4h15m       // 5 weeks, 4 hours, 15 minutes
     403                //
     404                //    16x14w10d     // Incorrect. 16x is disregarded, so the
     405                //                  // result is 15 weeks, 3 days
     406                //    13days        // Incorrect: days should be d, but this is
     407                //                  // parsed as 13d, 0 seconds
     408                //
     409                if (field.type == TemplateFieldType.RELTIME && value.class == String) {
     410                        // A string was given, attempt to transform it into a timespan
     411
     412                        // An empty string should be parsed as 0
     413                        if( value.trim() == "" ) {
     414                            value = 0;
     415                        } else {
     416                            // Find all parts that contain numbers with
     417                            // a character w, d, h, m or s after it
     418                            def periodMatch = value =~ /([0-9]+)([wdhms])/
     419                            if (periodMatch.size() > 0 ) {
     420                                    def seconds = 0L;
     421
     422                                    // Now check if every part contains data for
     423                                    // the time interval
     424                                    periodMatch.each {
     425                                        def partValue
     426
     427                                        println it
     428
     429                                        if( it[1].isLong() ) {
     430                                            partValue = Long.parseLong( it[1] );
     431                                        } else {
     432                                            partValue = 0;
     433                                        }
     434
     435                                        switch( it[ 2 ] ) {
     436                                            case 'w':
     437                                                seconds += 7L * 24 * 60 * 60 * partValue;
     438                                                break;
     439                                            case 'd':
     440                                                seconds += 24L * 60 * 60 * partValue;
     441                                                break;
     442                                            case 'h':
     443                                                seconds += 60L * 60 * partValue;
     444                                                break;
     445                                            case 'm':
     446                                                seconds += 60L * partValue;
     447                                                break;
     448                                            case 's':
     449                                                seconds += partValue;
     450                                                break;
     451                                            default:
     452                                                adf.error.warn( 'Parsing relative time: ' + it[0] + it[1] + ' is not understood and disregarded' );
     453                                                break;
     454                                        }
     455                                    }
     456
     457                                    // Continue with the computed value
     458                                    value = seconds;
     459                            } else {
     460                                throw new IllegalArgumentException( "String " + value + " cannot be parsed as a relative time. Use format #w #d #h #m #s." );
     461                            }
     462                        }
     463                }
     464
    355465                // Magic setter for ontology terms: handle string values
    356466                if (field.type == TemplateFieldType.ONTOLOGYTERM && value && value.class == String) {
     
    384494                        // If that is ever changed, the results are pretty much unpredictable (random Java object pointers?)!
    385495                        def store = getStore(field.type)
    386                         if (!value && store[fieldName]) {
    387                                 println ".unsetting [" + ((super) ? super.class : '??') + "] template field: [" + fieldName + "]"
    388 
    389                                 // remove the item from the Map (if present)
    390                                 store.remove(fieldName)
    391                         } else if (value) {
    392                                 println ".setting [" + ((super) ? super.class : '??') + "] template field: [" + fieldName + "] ([" + value.toString() + "] of type [" + value.class + "])"
    393 
    394                                 // set value
    395                                 store[fieldName] = value
    396                         }
     496
     497                        // If some value is entered (or 0), then save the value
     498                        // otherwise, it should not be present in the store, so
     499                        // it is unset if it is.
     500                        if ( value || value == 0 ) {
     501                            println ".setting [" + ((super) ? super.class : '??') + "] template field: [" + fieldName + "] ([" + value.toString() + "] of type [" + value.class + "])"
     502
     503                            // set value
     504                            store[fieldName] = value
     505                        } else if ( store[fieldName] ) {
     506                            println ".unsetting [" + ((super) ? super.class : '??') + "] template field: [" + fieldName + "]"
     507
     508                            // remove the item from the Map (if present)
     509                            store.remove(fieldName)
     510                        }
    397511                }
    398512
     
    420534        /**
    421535         * Return all fields defined in the underlying template and the built-in
    422      * domain fields of this entity
     536         * domain fields of this entity
    423537         */
    424538        def List<TemplateField> giveFields() {
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateFieldType.groovy

    r482 r487  
    1717        ONTOLOGYTERM('Ontology Reference'),
    1818        DATE('Date'),
    19     RELDATE('Relative date') // relative date, e.g. days since start of study
     19        RELTIME('Relative time') // relative date, e.g. days since start of study
    2020
    2121        String name
     
    2626
    2727        static list() {
    28                 [STRING, TEXT, INTEGER, FLOAT, DOUBLE, STRINGLIST, ONTOLOGYTERM, DATE, RELDATE]
     28                [STRING, TEXT, INTEGER, FLOAT, DOUBLE, STRINGLIST, ONTOLOGYTERM, DATE, RELTIME]
    2929        }
    3030
     
    4545                        case DATE:
    4646                                return null
    47             case RELDATE:
    48                 return null
     47                        case RELTIME:
     48                                return null
    4949                        default:
    5050                                throw new NoSuchFieldException("Field type ${fieldType} not recognized")
Note: See TracChangeset for help on using the changeset viewer.