Changeset 536


Ignore:
Timestamp:
Jun 7, 2010, 9:20:00 AM (6 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 edited

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
Note: See TracChangeset for help on using the changeset viewer.