Changeset 536

Show
Ignore:
Timestamp:
07-06-10 09:20:00 (4 years ago)
Author:
roberth
Message:

Samples are now shown in the study overview page. Also some tests are added and the bootstrap is updated to show some sample fields with a template

Location:
trunk
Files:
2 added
9 modified

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/conf/BootStrap.groovy

    r531 r536  
    960960                                                name: currentSubject.name + '_B', 
    961961                                                material: bloodTerm, 
     962                                                template: humanBloodSampleTemplate, 
    962963                                                parentSubject: currentSubject, 
    963964                                                parentEvent: bloodSamplingEvent 
    964965                                        ); 
     966                                        currentSample.setFieldValue( "Text on vial", "T" + (Math.random() * 100L) ) 
    965967 
    966968                                        humanStudy.addToSubjects(currentSubject).addToSamples(currentSample).with { if (!validate()) { errors.each { println it} } else save()} 
  • trunk/grails-app/controllers/dbnp/studycapturing/StudyController.groovy

    r497 r536  
    3131    } 
    3232 
    33     /*def create = { 
    34         def studyInstance = new Study() 
    35         studyInstance.properties = params 
    36         return [studyInstance: studyInstance] 
    37     } 
    38  
    39     def save = { 
    40         def studyInstance = new Study(params) 
    41         if (studyInstance.save(flush: true)) { 
    42             flash.message = "${message(code: 'default.created.message', args: [message(code: 'study.label', default: 'Study'), studyInstance.id])}" 
    43             redirect(action: "show", id: studyInstance.id) 
    44         } 
    45         else { 
    46             render(view: "create", model: [studyInstance: studyInstance]) 
    47         } 
    48     }*/ 
    49  
    5033    /** 
    5134     * Shows one or more studies 
     
    7255     */ 
    7356    def events = { 
    74         def eventGroup = EventGroup.get(params.id) 
     57        def eventGroupId = Integer.parseInt( params.id ); 
     58        def studyId      = Integer.parseInt( params.study ); 
     59        def eventGroup; 
     60 
     61        // eventGroupId == -1 means that the orphaned events should be given 
     62        if( eventGroupId == -1 ) { 
     63            def studyInstance = Study.get( studyId ) 
     64             
     65            if (studyInstance == null) { 
     66                flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'study.label', default: 'Study'), studyId])}" 
     67                redirect(action: "list"); 
     68                return; 
     69            } 
     70 
     71            events = studyInstance.getOrphanEvents(); 
     72        } else { 
     73            eventGroup = EventGroup.get(params.id) 
     74 
     75            if (eventGroup == null) { 
     76                flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'eventgroup.label', default: 'Eventgroup'), params.id])}" 
     77                redirect(action: "list"); 
     78                return; 
     79            } 
     80            events = eventGroup?.events; 
     81        } 
    7582 
    7683        // This parameter should give the startdate of the study in milliseconds 
    7784        // since 1-1-1970 
    7885        long startDate  = Long.parseLong( params.startDate ) 
    79          
    80         if (!eventGroup) { 
    81             flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'eventgroup.label', default: 'Eventgroup'), params.id])}" 
    82             redirect(action: "list") 
     86 
     87        // Create JSON object 
     88        def json = [ 'dateTimeFormat': 'iso8601', events: [] ]; 
     89 
     90        // Add all other events 
     91        for( event in events ) { 
     92            def parameters = [] 
     93            for( templateField in event.giveTemplateFields() ) { 
     94                def value = event.getFieldValue( templateField.name ); 
     95                if( value ) { 
     96                    parameters << templateField.name + " = " + value; 
     97                } 
     98            } 
     99 
     100             json.events << [ 
     101                'start':    new Date( startDate + event.startTime * 1000 ), 
     102                'end':      new Date( startDate + event.endTime * 1000 ), 
     103                'durationEvent': !event.isSamplingEvent(), 
     104                'title': event.template.name + " (" + parameters.join( ', ' ) + ")", 
     105                'description': parameters 
     106            ] 
    83107        } 
    84         else { 
    85  
    86             // Create JSON object 
    87             def json = [ 'dateTimeFormat': 'iso8601', events: [] ]; 
    88  
    89             // Add the start of the study as event 
    90             /* 
    91             json.events << [ 
    92                 'start':    startDate, 
    93                 'durationEvent': false, 
    94                 'title': "Start date study", 
    95                 'color': 'red' 
    96             ] 
    97             */ 
    98             
    99             // Add all other events 
    100             for( event in eventGroup.events ) { 
    101                 def parameters = [] 
    102                 for( templateField in event.giveTemplateFields() ) { 
    103                     def value = event.getFieldValue( templateField.name ); 
    104                     if( value ) { 
    105                         parameters << templateField.name + " = " + value; 
    106                     } 
    107                 } 
    108  
    109                  json.events << [ 
    110                     'start':    new Date( startDate + event.startTime * 1000 ), 
    111                     'end':      new Date( startDate + event.endTime * 1000 ), 
    112                     'durationEvent': !event.isSamplingEvent(), 
    113                     'title': event.template.name + " (" + parameters.join( ', ' ) + ")", 
    114                     'description': parameters 
    115                 ] 
    116             } 
    117             render json as JSON 
    118         } 
     108        render json as JSON 
    119109    } 
    120110 
  • trunk/grails-app/domain/dbnp/studycapturing/Event.groovy

    r506 r536  
    8484        } 
    8585 
     86        def belongsToGroup( Set<EventGroup> groups ){ 
     87            def eventFound = false; 
     88            def that = this; 
     89            groups.each{ eventgroup -> 
     90                if( !eventFound ) { 
     91                    eventFound = ( that.id in eventgroup.events.id ); 
     92                } 
     93            } 
     94 
     95            return eventFound; 
     96        } 
     97 
    8698        def String toString() { 
    8799                return fieldExists('Description') ? getFieldValue('Description') : "" 
  • trunk/grails-app/domain/dbnp/studycapturing/Study.groovy

    r511 r536  
    6666        } 
    6767 
     68        /** 
     69         * returns all events and sampling events that do not belong to a group 
     70         */ 
     71        def Set<Event> getOrphanEvents() { 
     72            def orphans = 
     73                events.findAll{ event -> !event.belongsToGroup( eventGroups ) } + 
     74                samplingEvents.findAll { event -> !event.belongsToGroup( eventGroups ) }; 
     75 
     76            return orphans; 
     77        } 
     78 
    6879        /** 
    6980         * Return the unique Subject templates that are used in this study 
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateEntity.groovy

    r507 r536  
    585585        /** 
    586586         * Convenience method. Returns all unique templates used within a collection of TemplateEntities. 
     587         * 
     588         * If the collection is empty, an empty set is returned. If none of the entities contains 
     589         * a template, also an empty set is returned. 
    587590         */ 
    588591        static Set<Template> giveTemplates(Set<TemplateEntity> entityCollection) { 
    589                 return entityCollection*.template.unique(); 
     592            def set = entityCollection*.template.unique(); 
     593 
     594            // If one or more entities does not have a template, the resulting 
     595            // set contains null. That is not what is meant. 
     596            return set.findAll { it != null }; 
    590597        } 
    591598 
  • trunk/grails-app/views/study/show.gsp

    r522 r536  
    11 
    22<%@ page import="dbnp.studycapturing.Study" %> 
     3<%@ page import="dbnp.studycapturing.EventGroup" %> 
    34<%@ page import="dbnp.studycapturing.RelTime" %> 
    45<html> 
     
    2021                show: function(event, ui) { 
    2122                  // If the events tab is shown, the timeline should be redrawn 
    22                   if( ui.tab.hash == '#events' && !timelineloaded ) { 
     23                  if( ui.tab.hash == '#events-timeline' && !timelineloaded ) { 
    2324                    loadTimeline( 'eventstimeline', 'eventtitles', 0 ); 
    2425                    timelineloaded = true; 
     
    8687 
    8788              <g:set var="bandNr" value="${bandNr+1}" /> 
    88  
    89               <g:each in="${study.eventGroups}" var="eventGroup" status="i"> 
     89              <%  
     90                def sortedEventGroups = study.eventGroups.sort( { a, b -> 
     91                    return a.name <=> b.name; 
     92                }  as Comparator ); 
     93 
     94                def orphans = study.getOrphanEvents(); 
     95                if( orphans.size() > 0 ) { 
     96                  sortedEventGroups.add( new EventGroup( 
     97                    id: -1, 
     98                    name: 'No group', 
     99                    events: orphans, 
     100                    subjects: [] 
     101                  )); 
     102                } 
     103 
     104              %> 
     105              <g:each in="${sortedEventGroups}" var="eventGroup" status="i"> 
    90106 
    91107                //------------- Eventgroup ${bandNr} --------------- 
     
    95111 
    96112                // Load events for this eventsource (using jquery) 
    97                 var event_url = '${createLink(controller:'study', action:'events', id:eventGroup.id, params: [startDate: study.startDate.getTime() ])}'; 
     113                var event_url = '${createLink(controller:'study', action:'events', id:( eventGroup.id ? eventGroup.id : -1 ), params: [ startDate: study.startDate.getTime(), study: study.id ])}'; 
    98114                $.getJSON(event_url, $.callback( _loadJSONEvents, [0, ${bandNr}, eventSources[${bandNr}], overviewEventSource, event_url] ) ); 
    99115 
     
    156172                bandTitleInfo[ timelineNr ][ ${bandNr} ] = { 
    157173                  title: "${eventGroup.name}", 
     174                  className: "<g:if test="${ eventGroup.id == -1 || !eventGroup.id  }">no_group</g:if>", 
    158175                  subjects: "${showSubjects}" 
    159176                }; 
     
    163180 
    164181              // Synchronize all bands 
    165               <g:each in="${study.eventGroups}" var="eventGroup" status="i"> 
     182              <g:each in="${sortedEventGroups}" var="eventGroup" status="i"> 
    166183                bandInfos[${i + datesBandNr +1}].syncWith = ${datesBandNr}; 
    167184              </g:each> 
     
    185202          <li><a href="#study">Study Information</a></li> 
    186203          <li><a href="#subjects">Subjects</a></li> 
    187           <li><a href="#events">Events</a></li> 
    188           <li><a href="#event-group">Event Groups</a></li> 
     204          <li><a href="#events-timeline">Events timeline</a></li> 
     205          <li><a href="#events-table">Events table</a></li> 
    189206          <li><a href="#assays">Assays</a></li> 
     207          <li><a href="#samples">Samples</a></li> 
    190208          <li><a href="#persons">Persons</a></li> 
    191209          <li><a href="#publications">Publications</a></li> 
     
    313331                    // so the list is filtered for unique values 
    314332                    subjectTemplates = studyList*.giveSubjectTemplates().flatten().unique() 
    315                     subjectFields = subjectTemplates*.fields.flatten().unique() 
    316  
    317                     showSubjectFields = subjectFields 
    318  
    319                     /*  
     333                    if( !subjectTemplates ) { 
     334                      subjectTemplates = []; 
     335                      subjectFields = []; 
     336                    } else { 
     337                      subjectFields = subjectTemplates*.fields.flatten().unique() 
     338                      if( !subjectFields ) { 
     339                        subjectFields = []; 
     340                      } 
     341                    } 
     342 
     343                    /* 
    320344                     * These lines are rewritten because 
    321345                     * performance sucked 
     
    393417        </div> 
    394418 
    395         <div id="events"> 
     419        <div id="events-timeline"> 
    396420          <g:if test="${studyList*.events.flatten().size()==0 && studyInstance*.samplingEvents.flatten().size()==0 }"> 
    397421            No events in these studies 
     
    472496        </div> 
    473497 
    474         <div id="event-group"> 
     498        <div id="events-table"> 
    475499          <g:if test="${studyList*.eventGroups.flatten().size()==0}"> 
    476500            No event groups in this study 
     
    510534 
    511535              <g:each in="${studyList}" var="studyInstance"> 
    512  
    513                 <g:each in="${studyInstance.eventGroups}" var="eventGroup" status="j"> 
     536                <% 
     537                  def sortedEventGroups = studyInstance.eventGroups.sort( { a, b -> 
     538                      return a.name <=> b.name; 
     539                  }  as Comparator ); 
     540 
     541                  def orphans = studyInstance.getOrphanEvents(); 
     542                  if( orphans.size() > 0 ) { 
     543                    sortedEventGroups.add( new EventGroup( 
     544                      id: -1, 
     545                      name: 'No group', 
     546                      events: orphans, 
     547                      subjects: [] 
     548                    )); 
     549                  } 
     550 
     551                %> 
     552                <g:each in="${sortedEventGroups}" var="eventGroup" status="j"> 
    514553                  <tr class="${(i % 2) == 0 ? 'odd' : 'even'}"> 
    515554                    <g:if test="${multipleStudies && j==0}"> 
    516                       <td class="studytitle" rowspan="${studyInstance.eventGroups.size()}"> 
     555                      <td class="studytitle" rowspan="${sortedEventGroups.size()}"> 
    517556                        ${studyInstance.title} 
    518557                      </td> 
     
    595634                </g:each> 
    596635              </g:each> 
     636            </table> 
     637          </g:else> 
     638        </div> 
     639 
     640        <div id="samples"> 
     641 
     642          <g:if test="${studyList*.samples.flatten().size()==0}"> 
     643            No samples in the selected studies 
     644          </g:if> 
     645          <g:else> 
     646            <table> 
     647              <thead> 
     648                <tr> 
     649                  <g:if test="${multipleStudies}"> 
     650                    <th></th> 
     651                  </g:if> 
     652                  <g:each in="${new dbnp.studycapturing.Sample().giveDomainFields()}" var="field"> 
     653                    <th>${field}</th> 
     654                  </g:each> 
     655 
     656                  <% 
     657                    // Determine a union of the fields for all different 
     658                    // samples in all studies. In order to show a proper list. 
     659                    // We want every field to appear just once, 
     660                    // so the list is filtered for unique values 
     661                    sampleTemplates = studyList*.giveSampleTemplates().flatten().unique() 
     662 
     663                    if( !sampleTemplates ) { 
     664                      sampleTemplates = []; 
     665                      sampleFields = []; 
     666                      showSampleFields = []; 
     667                    } else { 
     668                      sampleFields = sampleTemplates*.fields.flatten().unique() 
     669                      if( !sampleFields ) { 
     670                        sampleFields = []; 
     671                        showSampleFields = []; 
     672                      } else { 
     673                        // Filter out all fields that are left blank for all samples 
     674                        allSamples = studyList*.samples.flatten() 
     675 
     676                        showSampleFields = []; 
     677                        sampleFields.each { sampleField -> 
     678                          for( sample in allSamples ) 
     679                          { 
     680                            // If the field is filled for this subject, we have to 
     681                            // show the field and should not check any other 
     682                            // samples (hence the break) 
     683                            if( sample.fieldExists( sampleField.name ) && sample.getFieldValue( sampleField.name ) ) { 
     684                              showSampleFields << sampleField; 
     685                              break; 
     686                            } 
     687                          } 
     688                        } 
     689                      } 
     690                    } 
     691                  %> 
     692 
     693                  <g:each in="${showSampleFields}" var="field"> 
     694                    <th>${field}</th> 
     695                  </g:each> 
     696 
     697                </tr> 
     698              </thead> 
     699 
     700              <g:set var="i" value="${1}" /> 
     701 
     702              <g:each in="${studyList}" var="studyInstance"> 
     703                <% 
     704                  // Sort samples by name 
     705                  samples = studyInstance.samples; 
     706                  sortedSamples = samples.sort( { a, b -> a.name <=> b.name } as Comparator ) 
     707                %> 
     708 
     709                <g:each in="${sortedSamples}" var="sample" status="j"> 
     710                  <tr class="${(i % 2) == 0 ? 'odd' : 'even'}"> 
     711                    <g:if test="${multipleStudies && j==0}"> 
     712                      <td class="studytitle" rowspan="${sortedSamples.size()}"> 
     713                        ${studyInstance.title} 
     714                      </td> 
     715                    </g:if> 
     716                    <g:each in="${sample.giveDomainFields()}" var="field"> 
     717                      <td>${sample.getFieldValue(field.name)}</td> 
     718                    </g:each> 
     719 
     720                    <g:each in="${showSampleFields}" var="field"> 
     721                      <td> 
     722                        <g:if test="${sample.fieldExists(field.name)}"> 
     723                          ${sample.getFieldValue(field.name)} 
     724                        </g:if> 
     725                        <g:else> 
     726                          N/A 
     727                        </g:else> 
     728                      </td> 
     729                    </g:each> 
     730 
     731                  </tr> 
     732                  <g:set var="i" value="${i + 1}" /> 
     733                </g:each> 
     734              </g:each> 
     735 
    597736            </table> 
    598737          </g:else> 
  • trunk/test/unit/dbnp/studycapturing/EventTests.groovy

    r496 r536  
    1212    } 
    1313 
    14     void testSomething() { 
     14    void testBelongsToGroup() { 
     15        def events = []; 
     16        10.times { 
     17            events[ it ] = new Event( 
     18                id: it, 
     19                startTime: 3600, 
     20                endTime: 3800 
     21            ) 
     22            println( 'Created event ' + it ); 
     23        } 
     24        def evGroup1 = new EventGroup( 
     25            name: 'group1', 
     26            events: events[0..4] 
     27        ) 
     28        def evGroup2 = new EventGroup( 
     29            name: 'group2', 
     30            events: events[3..6] 
     31        ) 
     32 
     33        Set<EventGroup> set1 = new HashSet<EventGroup>(); 
     34        Set<EventGroup> set2 = new HashSet<EventGroup>(); 
     35        Set<EventGroup> setBoth = new HashSet<EventGroup>(); 
     36        Set<EventGroup> setEmpty = new HashSet<EventGroup>(); 
     37        set1.add( evGroup1 ); 
     38        set2.add( evGroup2 ); 
     39        setBoth.add( evGroup1 ); 
     40        setBoth.add( evGroup2 ); 
     41 
     42        assert events[0].belongsToGroup( set1 ); 
     43        assert events[3].belongsToGroup( set1 ); 
     44        assert !events[6].belongsToGroup( set1 ); 
     45 
     46        assert events[3].belongsToGroup( set2 ); 
     47        assert events[6].belongsToGroup( set2 ); 
     48 
     49        assert !events[0].belongsToGroup( setEmpty ); 
     50        assert !events[8].belongsToGroup( setEmpty ); 
     51 
     52        assert events[0].belongsToGroup( setBoth ); 
     53        assert events[3].belongsToGroup( setBoth ); 
     54        assert events[6].belongsToGroup( setBoth ); 
     55 
     56        assert !events[7].belongsToGroup( setBoth ); 
    1557 
    1658    } 
  • trunk/test/unit/dbnp/studycapturing/StudyTests.groovy

    r496 r536  
    22 
    33import grails.test.* 
    4  
     4import groovy.util.GroovyTestCase 
    55class StudyTests extends GrailsUnitTestCase { 
    66    protected void setUp() { 
     
    1212    } 
    1313 
    14     void testSomething() { 
     14    protected void assertCollectionEquals( Collection set1, Collection set2 ) { 
     15        set1.each { 
     16            assert it in set2; 
     17        } 
     18        set2.each { 
     19            assert it in set1; 
     20        } 
    1521 
    1622    } 
     23 
     24    void testGetOrphanEvents() { 
     25        def events = []; 
     26        10.times { 
     27            events[ it ] = new Event( 
     28                id: it, 
     29                startTime: 3600, 
     30                endTime: 3800 
     31            ) 
     32            println( 'Created event ' + it ); 
     33        } 
     34        def evGroup1 = new EventGroup( 
     35            name: 'group1', 
     36            events: events[0..4] 
     37        ) 
     38        def evGroup2 = new EventGroup( 
     39            name: 'group2', 
     40            events: events[3..6] 
     41        ) 
     42 
     43        // No events should give no orphan events 
     44        def study1 = new Study( title: 'Studytitle 1', events: [], eventGroups: [] ); 
     45        assert study1.getOrphanEvents().size() == 0; 
     46 
     47        // Not even with a group 
     48        study1.eventGroups = [ evGroup1 ]; 
     49        assert study1.getOrphanEvents().size() == 0; 
     50 
     51        // Events 0..4 are part of evGroup1 
     52        study1.events = events[0..8]; 
     53        println(  study1.getOrphanEvents().id ) 
     54        println(  events[ 5..8].id ) 
     55         
     56        assertCollectionEquals( study1.getOrphanEvents(), events[ 5..8 ] ); 
     57 
     58        // Remove the evGroup 
     59        study1.eventGroups = []; 
     60        assertCollectionEquals( study1.getOrphanEvents(), events[ 0..8 ] ); 
     61 
     62        // Add multiple groups 
     63        study1.eventGroups = [ evGroup1, evGroup2 ]; 
     64        assertCollectionEquals( study1.getOrphanEvents(), events[ 7..8 ] ); 
     65 
     66        // Remove events again 
     67        study1.events = []; 
     68        assert study1.getOrphanEvents().size() == 0; 
     69    } 
    1770} 
  • trunk/web-app/css/studies.css

    r522 r536  
    8484 
    8585.eventtitles .studytitle { font-weight: bold; background-color: transparent; } 
     86.eventtitles .no_group { color: #990000; } 
    8687