source: branches/2.1/www/biomaterials/samples/edit_sample.jsp @ 2969

Last change on this file since 2969 was 2969, checked in by Nicklas Nordborg, 17 years ago

Fixes #448: Setting 'Used quantity' for pooled sources of sample, extracts and labeled extract doesn't work

Also, fixed incorrect links on view pages and added 'used quantity' as a column in listings of
children.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Id
File size: 17.5 KB
Line 
1<%-- $Id: edit_sample.jsp 2969 2006-11-28 12:40:05Z nicklas $
2  ------------------------------------------------------------------
3  Copyright (C) Authors contributing to this file.
4
5  This file is part of BASE - BioArray Software Environment.
6  Available at http://base.thep.lu.se/
7
8  BASE is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License
10  as published by the Free Software Foundation; either version 2
11  of the License, or (at your option) any later version.
12
13  BASE is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place - Suite 330,
21  Boston, MA  02111-1307, USA.
22  ------------------------------------------------------------------
23
24
25  @author Nicklas
26  @version 2.0
27--%>
28<%@ page
29  import="net.sf.basedb.core.SessionControl"
30  import="net.sf.basedb.core.DbControl"
31  import="net.sf.basedb.core.Item"
32  import="net.sf.basedb.core.ItemContext"
33  import="net.sf.basedb.core.SystemItems"
34  import="net.sf.basedb.core.Permission"
35  import="net.sf.basedb.core.Sample"
36  import="net.sf.basedb.core.BioSource"
37  import="net.sf.basedb.core.BioMaterialEvent"
38  import="net.sf.basedb.core.Protocol"
39  import="net.sf.basedb.core.ProtocolType"
40  import="net.sf.basedb.core.PermissionDeniedException"
41  import="net.sf.basedb.core.BaseException"
42  import="net.sf.basedb.core.ItemQuery"
43  import="net.sf.basedb.core.ItemResultList"
44  import="net.sf.basedb.core.Include"
45  import="net.sf.basedb.core.query.Orders"
46  import="net.sf.basedb.core.query.Hql"
47  import="net.sf.basedb.clients.web.Base"
48  import="net.sf.basedb.clients.web.util.HTML"
49  import="net.sf.basedb.util.Values"
50  import="java.util.List"
51  import="java.util.Set"
52  import="java.util.HashSet"
53  import="java.util.Date"
54%>
55<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
56<%@ taglib prefix="t" uri="/WEB-INF/tab.tld" %>
57<%
58final Item itemType = Item.SAMPLE;
59final SessionControl sc = Base.getExistingSessionControl(pageContext, true);
60final ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, null, null);
61final int itemId = cc.getId();
62final String ID = sc.getId();
63final float scale = Base.getScale(sc);
64final DbControl dc = sc.newDbControl();
65try
66{
67  String title = null;
68  Sample sample = null;
69  BioMaterialEvent creationEvent = null;
70  boolean isPooled = false;
71  String name = null;
72
73  boolean readCurrentProtocol = true;
74  Protocol currentProtocol = null;
75  boolean readCurrentBioSource = true;
76  BioSource currentBioSource = null;
77  ItemQuery<Sample> samplesQuery = null;
78 
79  // Load recently used items
80  List<Protocol> recentProtocols = (List<Protocol>)cc.getRecent(dc, Item.PROTOCOL);
81  List<BioSource> recentBioSources = (List<BioSource>)cc.getRecent(dc, Item.BIOSOURCE);
82
83  if (itemId == 0)
84  {
85    title = "Create sample";
86    cc.removeObject("item");
87    if (cc.getPropertyFilter("creationEvent.protocol.name") != null)
88    {
89      currentProtocol = Base.getFirstMatching(dc, Protocol.getQuery(), "name", cc.getPropertyFilter("creationEvent.protocol.name"));
90    }
91    int bioSourceId = Values.getInt(request.getParameter("biosource_id"));
92    if (bioSourceId != 0)
93    {
94      currentBioSource = BioSource.getById(dc, bioSourceId);
95      isPooled = false;
96      name = currentBioSource.getName() + ".s" + (currentBioSource.countSamples() + 1);
97    }
98    else if (Values.getBoolean(request.getParameter("pooled")))
99    {   
100      isPooled = true;
101      name = Values.getString(cc.getPropertyValue("name"),"New pooled sample");
102    }
103    else
104    {
105      isPooled = Values.getBoolean(cc.getPropertyValue("pooled"));
106      name = Values.getString(cc.getPropertyValue("name"), "New sample");
107    }
108  }
109  else
110  {
111    sample = Sample.getById(dc, itemId);
112    cc.setObject("item", sample);
113    title = "Edit sample -- " + HTML.encodeTags(sample.getName());
114 
115    creationEvent = sample.getCreationEvent();
116    isPooled = sample.isPooled();
117    name = sample.getName();
118   
119    try
120    {
121      currentProtocol = creationEvent.getProtocol();
122    }
123    catch (PermissionDeniedException ex)
124    {
125      readCurrentProtocol = false;
126    }
127 
128    try
129    {
130      currentBioSource = sample.getBioSource();
131    }
132    catch (PermissionDeniedException ex)
133    {
134      readCurrentBioSource = false;
135    }
136 
137    // Query to retrieve pooled samples
138    samplesQuery = (ItemQuery<Sample>)creationEvent.getSources();
139    samplesQuery.include(Include.MINE, Include.SHARED, Include.IN_PROJECT, Include.OTHERS);
140    samplesQuery.order(Orders.asc(Hql.property("name")));
141 
142  }
143  if (sample != null && !sample.hasPermission(Permission.WRITE))
144  {
145    throw new PermissionDeniedException(Permission.WRITE, itemType.toString());
146  }
147  final String clazz = "class=\"text\"";
148  final String requiredClazz = "class=\"text required\"";
149  %>
150
151  <base:page type="popup" title="<%=title%>">
152  <base:head scripts="tabcontrol.js,annotations.js,linkitems.js" styles="tabcontrol.css">
153    <script language="JavaScript">
154    // Validate the "Sample" tab
155    function validateSample()
156    {
157      var frm = document.forms['sample'];
158      if (Main.trimString(frm.name.value) == '')
159      {
160        alert("You must enter a name");
161        frm.name.focus();
162        return false;
163      }
164      return true;
165    }
166
167    // Submit the form
168    function saveSettings()
169    {
170      var frm = document.forms['sample'];
171      if (TabControl.validateActiveTab('settings'))
172      {
173        if (annotationsLoaded)
174        {
175          Annotations.addModifiedAnnotationsToForm(frames.annotations, frm);
176        }
177        if (inheritedAnnotationsLoaded)
178        {
179          Annotations.addInheritedAnnotationsToForm(frames.inheritedAnnotations, frm);
180        }
181        frm.modifiedSamples.value = Link.exportModified(frm, 'S', true).join(',');
182        frm.removedSamples.value = Link.getActionIds(-1, 'S').join(',');
183        frm.submit();
184      }
185    }
186   
187    var annotationsLoaded = false;
188    var inheritedAnnotationsLoaded = false;
189    var parentsChanged = false;
190    function switchTab(tabControlId, tabId)
191    {
192      if (TabControl.setActiveTab(tabControlId, tabId))
193      {
194        if (tabId == 'annotations' && !annotationsLoaded)
195        {
196          Annotations.loadAnnotateFrame(frames.annotations, '<%=ID%>', '<%=itemType.name()%>', <%=itemId%>);
197          annotationsLoaded = true;
198        }
199        else if (tabId == 'inheritedAnnotations' && 
200          (parentsChanged || !inheritedAnnotationsLoaded))
201        {
202          Annotations.loadInheritFrame(frames.inheritedAnnotations, '<%=ID%>', '<%=itemType.name()%>', <%=itemId%>, getParents());
203          inheritedAnnotationsLoaded = true;
204          parentsChanged = false;
205        }
206      }
207    }
208   
209    function getParents()
210    {
211      var frm = document.forms['sample'];
212      var parents = new Array();
213      if (frm.pooled[0].checked)
214      {
215        var bioSourceId = Math.abs(parseInt(frm.biosource_id[frm.biosource_id.selectedIndex].value));
216        if (bioSourceId > 0) parents[parents.length] = 'BIOSOURCE:'+bioSourceId;
217      }
218      else
219      {
220        var ids = Link.getListIds(frm.samples, 'S');
221        if (ids.length > 0)
222        {
223          parents[parents.length] = 'SAMPLE:'+ids.join(':');
224        }
225      }
226      return parents;
227    }
228   
229    function selectProtocolOnClick()
230    {
231      var frm = document.forms['sample'];
232      var url = '../../admin/protocols/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectone&callback=setProtocolCallback';
233      if (frm.protocol_id.length > 1)
234      {
235        var id = Math.abs(parseInt(frm.protocol_id[1].value));       
236        url += '&item_id='+id;
237      }
238      url += '&filter:INT:protocolType=<%=SystemItems.getId(ProtocolType.SAMPLING)%>';
239      Main.openPopup(url, 'SelectProtocol', 1000, 700);
240    }
241    function setProtocolCallback(id, name)
242    {
243      var frm = document.forms['sample'];
244      var list = frm.protocol_id;
245      if (list.length < 2 || list[1].value == '0') // >
246      {
247        Forms.addListOption(list, 1, new Option());
248      }
249      list[1].value = id;
250      list[1].text = name;
251      list.selectedIndex = 1;
252    }
253   
254    function pooledOnClick()
255    {
256      var frm = document.forms['sample'];
257      var isPooled = frm.pooled[1].checked
258      frm.biosource_id.disabled = isPooled;
259      frm.samples.disabled = !isPooled;
260      frm.used_quantity.disabled = !isPooled;
261      parentsChanged = true;
262    }
263    function bioSourceOnChange()
264    {
265      parentsChanged = true;
266    }
267    function selectBioSourceOnClick()
268    {
269      var frm = document.forms['sample'];
270      if (frm.pooled[1].checked)
271      {
272        alert('This is a pooled sample, which cannot have a biosource as it\'s parent');
273        return;
274      }
275      var url = '../biosources/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectone&callback=setBioSourceCallback';
276      if (frm.biosource_id.length > 1)
277      {
278        var id = Math.abs(parseInt(frm.biosource_id[1].value));       
279        url += '&item_id='+id;
280      }
281      Main.openPopup(url, 'SelectBioSource', 1000, 700);
282    }
283    function setBioSourceCallback(id, name)
284    {
285      var frm = document.forms['sample'];
286      var list = frm.biosource_id;
287      if (list.length < 2 || list[1].value == '0') // >
288      {
289        Forms.addListOption(list, 1, new Option());
290      }
291      list[1].value = id;
292      list[1].text = name;
293      list.selectedIndex = 1;
294      parentsChanged = true;
295    }
296   
297    function addSamplesOnClick()
298    {
299      var frm = document.forms['sample'];
300      if (!frm.pooled[1].checked)
301      {
302        alert('This is not a pooled sample');
303        return;
304      }
305      Main.openPopup('index.jsp?ID=<%=ID%>&mode=selectmultiple&callback=addSampleCallback', 'AddSamples', 1000, 700);
306    }
307    function addSampleCallback(sampleId, name)
308    {
309      var item = Link.getItem('S', sampleId);
310      if (!item) item = new Item('S', sampleId, name+' [-]', '', '');
311      Link.addItem(document.forms['sample'].samples, item);
312      parentsChanged = true;
313    }
314    function samplesOnChange()
315    {
316      var frm = document.forms['sample'];
317      var item = frm.samples[frm.samples.selectedIndex].item;
318      if (item && item.id)
319      {
320        frm.used_quantity.value = item.value;
321        frm.used_quantity.focus();
322      }
323      else
324      {
325        frm.used_quantity.value = '';
326      }
327    }
328    function usedQuantityOnBlur()
329    {
330      var frm = document.forms['sample'];
331      var usedQuantity = frm.used_quantity.value;
332      var displayQuantity = usedQuantity == '' ? '-' : usedQuantity+' µg';
333      for (var i = 0; i < frm.samples.length; i++)  // >
334      {
335        var option = frm.samples[i];
336        if (option.selected && option.item.id)
337        {
338          option.item.value = usedQuantity;
339          var text = option.text.replace(/\[.*\]/, '['+displayQuantity+']');
340          option.text = text;
341        }
342      }
343    }
344
345    function removeOnClick()
346    {
347      Link.removeSelected(document.forms['sample'].samples);
348      parentsChanged = true;
349    }
350
351    function init()
352    {
353      <%
354      if (sample == null)
355      {
356        %>
357        var frm = document.forms['sample'];
358        frm.name.focus();
359        frm.name.select();
360        <%
361      }
362      %>
363      initSamples();
364      pooledOnClick();
365    }
366    function initSamples()
367    {
368      var samples = document.forms['sample'].samples;
369      <%
370      if (sample != null && sample.isPooled())
371      {
372        ItemResultList<Sample> samples = samplesQuery.list(dc);
373        for (Sample s : samples)
374        {
375          String usedQuantity = Values.formatNumber(creationEvent.getUsedQuantity(s), -1);
376          %>
377          Link.addNewItem(samples, new Item('S', <%=s.getId()%>, '<%=HTML.javaScriptEncode(s.getName())%> [<%=usedQuantity%> µg]', '<%=usedQuantity%>'));
378          <%
379        }
380      }
381      else if (sample == null && Values.getBoolean(request.getParameter("pooled")))
382      {
383        for (int sid : cc.getSelected())
384        {
385          Sample sampleToPool = Sample.getById(dc, sid);
386          %>
387          Link.addItem(samples, new Item('S', <%=sampleToPool.getId()%>, '<%=HTML.javaScriptEncode(sampleToPool.getName())%> [-]', '', ''));
388          <%
389        }
390      }
391      %>
392    }
393    </script>
394  </base:head>
395  <base:body onload="init()">
396    <p>
397    <form action="index.jsp?ID=<%=ID%>" method="post" name="sample" onsubmit="return false;">
398    <input type="hidden" name="cmd" value="UpdateItem">
399
400    <h3 class="docked"><%=title%> <base:help tabcontrol="settings" /></h3>
401    <t:tabcontrol id="settings" contentstyle="<%="height: "+(int)(scale*370)+"px;"%>" 
402      position="bottom"  remember="<%=sample != null%>" switch="switchTab">
403    <t:tab id="info" title="Sample" validate="validateSample()" helpid="sample.edit">
404      <table class="form" cellspacing=0>
405      <tr>
406        <td class="prompt">Name</td>
407        <td><input <%=requiredClazz%> type="text" name="name" 
408          value="<%=HTML.encodeTags(name)%>" 
409          size="40" maxlength="<%=Sample.MAX_NAME_LENGTH%>"></td>
410      </tr>
411      <tr>
412        <td class="prompt">External ID</td>
413        <td><input <%=clazz%> type="text" name="external_id" 
414          value="<%=HTML.encodeTags(sample == null ? Values.getString(cc.getPropertyValue("externalId"), "") : sample.getExternalId())%>" 
415          size="40" maxlength="<%=Sample.MAX_EXTERNAL_ID_LENGTH%>"></td>
416      </tr>
417      <tr>
418        <td class="prompt">Original quantity</td>
419        <td><input <%=clazz%> type="text" name="original_quantity" 
420          value="<%=Values.formatNumber(sample == null ? Values.getFloat(cc.getPropertyValue("originalQuantity"), null): sample.getOriginalQuantity(), -1)%>" size="12" 
421          maxlength="10" onkeypress="return Numbers.numberOnly(event)"> (µg)</td>
422      </tr>
423      <tr>
424        <td class="prompt">Remaining quantity</td>
425        <td><%=Values.formatNumber(sample == null ? null : sample.getRemainingQuantity(), 2, " µg")%></td>
426      </tr>
427      <tr>
428        <td class="prompt">Created</td>
429        <td>
430          <table border="0" cellspacing="0" cellpadding="0">
431          <tr>
432          <td>
433            <input <%=clazz%> type="text" name="event_date" 
434              value="<%=Values.formatDate(creationEvent == null ? Values.getDate(cc.getPropertyValue("creationEvent.eventDate"), new Date()): creationEvent.getEventDate())%>" 
435              size="12" maxlength="10" onkeypress="return Dates.dateOnly(event)">
436            (yyyy-mm-dd)&nbsp;
437          </td>
438          <td>
439          <base:button 
440            onclick="Dates.selectDate('Date', 'sample', 'event_date')"
441            image="calendar.png" 
442            title="Calendar&hellip;" 
443            tooltip="Select a date from a calendar" 
444          />
445          </td>
446          </tr>
447          </table>
448        </td>
449      </tr>
450      <tr>
451        <td class="prompt">Registered</td>
452        <td><%=Values.formatDate(creationEvent == null ? new Date() : creationEvent.getEntryDate())%></td>
453      </tr>
454      <tr>
455        <td class="prompt">Protocol</td>
456        <td>
457          <base:select 
458            id="protocol_id"
459            clazz="selectionlist"
460            required="false"
461            current="<%=currentProtocol%>"
462            denied="<%=!readCurrentProtocol%>"
463            recent="<%=recentProtocols%>"
464            newitem="<%=sample == null%>"
465            onselect="selectProtocolOnClick()"
466          />
467        </td>
468      </tr>
469      <tr valign=top>
470        <td class="prompt">Description</td>
471        <td nowrap>
472          <textarea <%=clazz%> rows="4" cols="40" name="description" wrap="virtual"
473            ><%=HTML.encodeTags(sample == null ? cc.getPropertyValue("description") : sample.getDescription())%></textarea>
474          <a href="javascript:Main.zoom('Description', 'sample', 'description')"
475            title="Edit in larger window"><base:icon image="zoom.gif" /></a>
476        </td>
477      </tr>
478      </table>
479      <div align=right>&nbsp;<i><base:icon image="required.gif" /> = required information</i></div>
480    </t:tab>
481   
482    <t:tab id="parents" title="Parents" helpid="sample.parents" >
483      <table class="form" cellspacing=0>
484      <tr>
485        <td class="prompt">Pooled</td>
486        <td>
487          <input type="radio" name="pooled" value="0" onclick="pooledOnClick()"
488            <%=!isPooled ? "checked" : ""%>
489            >no
490          <input type="radio" name="pooled" value="1" onclick="pooledOnClick()"
491            <%=isPooled ? "checked" : ""%>
492            >yes
493        </td>
494      </tr>
495      <tr>
496        <td class="prompt">Biosource</td>
497        <td>
498          <base:select 
499            id="biosource_id"
500            clazz="selectionlist"
501            required="false"
502            current="<%=currentBioSource%>"
503            denied="<%=!readCurrentBioSource%>"
504            recent="<%=recentBioSources%>"
505            selectrecent="false"
506            newitem="<%=sample == null%>"
507            onselect="selectBioSourceOnClick()"
508            onchange="bioSourceOnChange()"
509          />
510        </td>
511      </tr>
512      <tr valign="top">
513        <td class="prompt">Samples</td>
514        <td>
515          <table border="0" cellspacing="0" cellpadding="0">
516          <tr valign="top">
517          <td>
518            <select name="samples" size="5" multiple style="width: 20em;" 
519              onchange="samplesOnChange()">
520            </select>&nbsp;<br>
521            Used
522            <input <%=clazz%> type="text" name="used_quantity" value=""
523              size="12" maxlength="10" onkeypress="return Numbers.numberOnly(event)"
524              onkeyup="usedQuantityOnBlur();"
525            > (µg)
526            <input type="hidden" name="modifiedSamples" value="">
527            <input type="hidden" name="removedSamples" value="">
528          </td>
529          <td>
530            <table border="0">
531            <tr><td width="150"><base:button 
532              onclick="addSamplesOnClick()" 
533              title="Add&nbsp;samples&hellip;" 
534              tooltip="Add samples"
535              /></td></tr>
536            <tr><td width="150"><base:button 
537              onclick="removeOnClick()" 
538              title="Remove" 
539              tooltip="Remove the selected samples"
540            /></td></tr>
541            </table>
542          </td>
543          </tr>
544          </table>
545        </td>
546      </tr>
547      </table>
548    </t:tab>
549
550    <t:tab id="annotations" title="Annotations" helpid="annotations.edit">
551      <iframe name="annotations" id="idAnnotations" src="../../common/annotations/wait.jsp" 
552        width="100%"  height="<%=(int)(scale*370)%>" frameborder=0 vspace=0 hspace=0
553        marginwidth=0 marginheight=0 scrolling="auto" style="overflow: visible"></iframe>
554    </t:tab>
555   
556    <t:tab id="inheritedAnnotations" title="Inherited annotations" helpid="annotations.edit.inherited">
557   
558      <iframe name="inheritedAnnotations" id="idInheritedAnnotations" src="../../common/annotations/wait.jsp" 
559        width="100%"  height="<%=(int)(scale*370)%>" frameborder=0 vspace=0 hspace=0
560        marginwidth=0 marginheight=0 scrolling="auto" style="overflow: visible"></iframe>
561    </t:tab>
562    </t:tabcontrol>
563
564    <table align="center">
565    <tr>
566      <td width="50%"><base:button onclick="saveSettings()" title="Save" /></td>
567      <td width="50%"><base:button onclick="window.close()" title="Cancel" /></td>
568    </tr>
569    </table>
570    </form>
571  </base:body>
572  </base:page>
573  <%
574}
575finally
576{
577  if (dc != null) dc.close();
578}
579%>
Note: See TracBrowser for help on using the repository browser.