source: trunk/www/biomaterials/wizards/move_biomaterial.jsp @ 5542

Last change on this file since 5542 was 5542, checked in by Nicklas Nordborg, 12 years ago

References #1564: Move biomaterial on plates

Fixes an issue with an incorrect filter when selecting destination plate if used with plates containing extracts or labeled extracts.

File size: 24.5 KB
Line 
1<%-- $Id$
2  ------------------------------------------------------------------
3  Copyright (C) 2010 Nicklas Nordborg
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 3
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 BASE. If not, see <http://www.gnu.org/licenses/>.
20  ------------------------------------------------------------------
21
22  @author Nicklas
23--%>
24<%@ page pageEncoding="UTF-8" session="false"
25  import="net.sf.basedb.core.BioPlate"
26  import="net.sf.basedb.core.BioPlateEvent"
27  import="net.sf.basedb.core.PermissionDeniedException"
28  import="net.sf.basedb.core.BioPlateEventType"
29  import="net.sf.basedb.core.MeasuredBioMaterial"
30  import="net.sf.basedb.core.Hardware"
31  import="net.sf.basedb.core.Protocol"
32  import="net.sf.basedb.core.DbControl"
33  import="net.sf.basedb.core.Item"
34  import="net.sf.basedb.core.ItemContext"
35  import="net.sf.basedb.core.ItemQuery"
36  import="net.sf.basedb.core.SessionControl"
37  import="net.sf.basedb.core.query.Restrictions"
38  import="net.sf.basedb.core.query.Hql"
39  import="net.sf.basedb.util.Values"
40  import="net.sf.basedb.util.formatter.Formatter"
41  import="net.sf.basedb.clients.web.formatter.FormatterFactory"
42  import="net.sf.basedb.clients.web.formatter.FormatterSettings"
43  import="net.sf.basedb.clients.web.Base"
44  import="net.sf.basedb.clients.web.util.HTML"
45  import="java.util.List"
46  import="java.util.Date"
47  import="java.util.Collections"
48%>
49<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
50<%@ taglib prefix="tbl" uri="/WEB-INF/table.tld" %>
51<%
52final SessionControl sc = Base.getExistingSessionControl(pageContext, true);
53final String ID = sc.getId();
54final float scale = Base.getScale(sc);
55final int sourcePlateId = Values.getInt(request.getParameter("sourceplate_id"));
56final ItemContext cc = sc.getCurrentContext(Item.BIOPLATEEVENT, BioPlateEventType.MOVE);
57final DbControl dc = sc.newDbControl();
58try
59{
60  BioPlate sourcePlate = BioPlate.getById(dc, sourcePlateId);
61 
62  // Load recently used items
63  List<Hardware> recentHardware = (List<Hardware>)cc.getRecent(dc, Item.HARDWARE);
64  List<Protocol> recentProtocols = (List<Protocol>)cc.getRecent(dc, Item.PROTOCOL);
65 
66  Item itemType = null;
67  try
68  {
69    itemType = sourcePlate.getBioPlateType().getBioMaterialType();
70  }
71  catch (PermissionDeniedException ex)
72  {}
73 
74  final String clazz = "class=\"text\"";
75  final String requiredClazz = "class=\"text required\"";
76  final Formatter<Date> dateFormatter = FormatterFactory.getDateFormatter(sc);
77  final String dateFormat = FormatterSettings.getDateFormat(sc);
78  final String jsDateFormat = HTML.javaScriptEncode(dateFormat);
79  final String htmlDateFormat = HTML.encodeTags(dateFormat);
80  final boolean showSourceCoordinates = Values.getBoolean(sc.getUserClientSetting("move-biomaterial.show-source-coordinates"), true);
81  %>
82  <base:page type="popup" title="Move biomaterial">
83  <base:head scripts="ajax.js,plate.js,js-draw.js" styles="plate.css,toolbar.css">
84    <script language="javascript">
85 
86    // For drawing
87    var graphics;
88    var pen;
89    var selectedPen;
90   
91    // Source and destination plates
92    var sourcePlate;
93    var destPlate;
94   
95    // We can select one well on each plate
96    var selectedSourceWell;
97    var selectedDestWell;
98
99    function init()
100    {
101      // Initialize graphics
102      graphics = new jsGraphics(document.getElementById('canvas'));
103      pen = new jsPen();
104      selectedPen = new jsPen(new jsColor('445577'), 2);
105      setBioPlateCallback(<%=sourcePlateId%>, '<%=HTML.javaScriptEncode(sourcePlate.getName())%>', true);
106    }
107
108    /**
109      Select the source well that is clicked on. The currently selected well
110      is de-selected. If the clicked well is the same as the currently
111      selected well no new item is selected. If a destination well is already
112      selected a link is made between the source and destination wells.
113    */
114    function sourceWellOnClick(row, column)
115    {
116      var well = sourcePlate.getWell(row, column);
117      if (!well) return;
118
119      // De-select the currently selected source well
120      if (selectedSourceWell)
121      {
122        selectedSourceWell.setSelected(false);
123        if (well == selectedSourceWell)
124        {
125          // Re-draw link with regular pen (eg. same as onmouseover)
126          selectedSourceWell.drawLink(graphics, pen, true);
127          selectedSourceWell = null;
128          return;
129        }
130        else
131        {
132          selectedSourceWell.hideLink(graphics);
133        }
134      }
135     
136      // Select the new source well and draw link to destination well
137      selectedSourceWell = well;
138      selectedSourceWell.setSelected(true);
139      selectedSourceWell.drawLink(graphics, selectedPen, true);
140
141      // Map the source and destination wells
142      if (selectedSourceWell && selectedDestWell)
143      {
144        mapSelectedWells();
145      }
146    }
147   
148    /**
149      Draw a link between the mapped source and destination wells.
150    */
151    function sourceWellOnMouseOver(row, column)
152    {
153      var well = sourcePlate.getWell(row, column);
154      if (!well) return;
155      well.drawLink(graphics, pen, false);
156    }
157   
158    /**
159      Hide the link between the mapped source and destination
160      wells, unless one of them is selected.
161    */
162    function sourceWellOnMouseOut(row, column)
163    {
164      var well = sourcePlate.getWell(row, column);
165      if (!well) return;
166      if (!well.selected && !(well.mappedWell && well.mappedWell.selected))
167      {
168        well.hideLink(graphics);
169      }
170    }
171   
172    function destWellOnClick(row, column)
173    {
174      var well = destPlate.getWell(row, column);
175
176      // De-select the currently selected well
177      if (selectedDestWell)
178      {
179        selectedDestWell.setSelected(false);
180        if (well == selectedDestWell)
181        {
182          // Re-draw link with regular pen (eg. same as onmouseover)
183          selectedDestWell.drawLink(graphics, pen, true);
184          selectedDestWell = null;
185          return;
186        }
187        else
188        {
189          selectedDestWell.hideLink(graphics);
190        }
191      }
192     
193      selectedDestWell = well;
194      selectedDestWell.setSelected(true);
195      selectedDestWell.drawLink(graphics, selectedPen, true);
196
197      if (selectedSourceWell && selectedDestWell)
198      {
199        mapSelectedWells();
200      }
201    }
202   
203    function destWellOnMouseOver(row, column)
204    {
205      var well = destPlate.getWell(row, column);
206      if (!well) return;
207      well.drawLink(graphics, pen, false);
208    }
209   
210    function destWellOnMouseOut(row, column)
211    {
212      var well = destPlate.getWell(row, column);
213      if (!well) return;
214      if (!well.selected && !(well.mappedWell && well.mappedWell.selected))
215      {
216        well.hideLink(graphics);
217      }
218    }
219
220    /**
221      Map the selected source and destination wells. Hide and
222      redraw links as needed.
223    */
224    function mapSelectedWells()
225    {
226      // Hide any links that are currently displayed
227      selectedSourceWell.hideLink(graphics);
228      selectedDestWell.hideLink(graphics);
229     
230      // Map to the new well and draw link
231      if (selectedSourceWell.mappedWell != selectedDestWell)
232      {
233        selectedSourceWell.mapToWell(selectedDestWell);
234        selectedSourceWell.drawLink(graphics, pen, true);
235      }
236      else
237      {
238        selectedSourceWell.unmapWell();
239      }
240     
241      // De-select everything
242      selectedSourceWell.setSelected(false);
243      selectedDestWell.setSelected(false);
244      selectedSourceWell = null;
245      selectedDestWell = null;
246    }
247
248   
249    /**
250      Remove all mappings that have been made so far.
251    */
252    function clearMapping()
253    {
254      if (!destPlate)
255      {
256        alert('No destination plate has been selected');
257        return;
258      }
259      if (!confirm('This will remove all placed biomaterial. Continue?')) return;
260      sourcePlate.unmapAll();
261    }
262   
263    /**
264      Automatically move remaining biomaterial to the destination plate filling rows first.
265      Biomaterial and wells that have already been mapped are skipped.
266    */
267    function placeByRow()
268    {
269      if (!destPlate)
270      {
271        alert('No destination plate has been selected');
272        return;
273      }
274      var srcRow = 0;
275      var srcCol = 0;
276      for (var destRow = 0; destRow < destPlate.rows; destRow++)
277      {
278        for (var destCol = 0; destCol < destPlate.columns; destCol++)
279        {
280          var destWell = destPlate.getWell(destRow, destCol);
281          if (!destWell.mappedWell && !destWell.locked)
282          {
283            var mapped = false;
284            var srcWell = sourcePlate.getWell(srcRow, srcCol);
285            while (srcWell && !mapped)
286            {
287              if (srcWell.id && !srcWell.locked && !srcWell.mappedWell)
288              {
289                srcWell.mapToWell(destWell);
290                mapped = true;
291              }
292              else
293              {
294                srcCol++;
295                if (srcCol >= sourcePlate.columns)
296                {
297                  srcCol = 0;
298                  srcRow++;
299                }
300                srcWell = sourcePlate.getWell(srcRow, srcCol);
301              }
302            }
303          }
304        }
305      }
306    }
307 
308    /**
309      Automatically move remaining biomaterial to the destination plate filling columns first.
310      Biomaterial and wells that have already been mapped are skipped.
311    */
312    function placeByColumn()
313    {
314      if (!destPlate)
315      {
316        alert('No destination plate has been selected');
317        return;
318      }
319      var srcRow = 0;
320      var srcCol = 0;
321      for (var destCol = 0; destCol < destPlate.columns; destCol++)
322      {
323        for (var destRow = 0; destRow < destPlate.rows; destRow++)
324        {
325          var destWell = destPlate.getWell(destRow, destCol);
326          if (!destWell.mappedWell && !destWell.locked)
327          {
328            var mapped = false;
329            var srcWell = sourcePlate.getWell(srcRow, srcCol);
330            while (srcWell && !mapped)
331            {
332              if (srcWell.id && !srcWell.locked && !srcWell.mappedWell)
333              {
334                srcWell.mapToWell(destWell);
335                mapped = true;
336              }
337              else
338              {
339                srcRow++;
340                if (srcRow >= sourcePlate.rows)
341                {
342                  srcCol++;
343                  srcRow = 0;
344                }
345                srcWell = sourcePlate.getWell(srcRow, srcCol);
346              }
347            }
348          }
349        }
350      }
351    }
352
353   
354    function selectBioPlateOnClick()
355    {
356      if (destPlate && !confirm('This will reset all moved biomaterial. Continue?')) return;
357     
358      var url = '../bioplates/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectone&callback=setBioPlateCallback';
359      url += '&resetTemporary=1&tmpfilter:INT:bioPlateType.bioMaterialType=<%=itemType == null ? "=" : "|" + itemType.getValue()%>'
360      url += '&exclude='+sourcePlate.id;
361      Main.openPopup(url, 'SelectBioPlate', 1000, 700);
362    }
363
364    function setBioPlateCallback(bioPlateId, name, isSourcePlate)
365    {
366      if (!isSourcePlate && bioPlateId == sourcePlate.id)
367      {
368        alert('It is not possible to use the same plate as both source and destination plate.');
369        return;
370      }
371     
372      var request = Ajax.getXmlHttpRequest();
373      var url = '../bioplates/ajax.jsp?ID=<%=ID%>&cmd=GetFullPlateInfo&item_id=' + bioPlateId;
374      request.open("GET", url, false);
375      // NOTE! 'false' causes code to wait for the response. aka. 'Synchronous AJAX' or SJAX.
376      request.send(null);
377      var response = Ajax.parseResponse(request.responseText);
378      if (response.isError())
379      {
380        alert(response.getErrorMessage());
381        return false;
382      }
383
384      // Get plate and well information from the AJAX response
385      var records = response.getElements();
386      var plateInfo = records[0];
387      var rows = parseInt(plateInfo['rows']);
388      var columns = parseInt(plateInfo['columns']);
389     
390      var bigPlate = rows > 12 || columns > 18;
391      var plateClass = bigPlate ? 'plate bigplate' : 'plate';
392
393      // Remove existing mapping
394      if (sourcePlate) sourcePlate.unmapAll();
395
396      // Create plate and wells
397      var prefix = isSourcePlate ? 'source' : 'dest';
398      var plate = new Plate(prefix, plateInfo['id'], plateInfo['name'], rows, columns, isSourcePlate);
399      for (var i = 1; i < records.length; i++)
400      {
401        var wellInfo = records[i];
402        var row = parseInt(wellInfo['well.row']);
403        var col = parseInt(wellInfo['well.column']);
404        var well = plate.getWell(row, col);
405        well.id = wellInfo['bm.id'];
406        well.name = wellInfo['bm.name'];
407        well.locked = isSourcePlate ? wellInfo['well.can-clear'] == '0' : wellInfo['well.can-add'] == '0' || well.id;
408      }
409     
410      // Create html table representing the bioplate
411      var html = '<table class="'+plateClass+'" cellspacing="0" cellpadding="0" onmouseout="event.cancelBubble=true">';
412      html += '<tr><td></td>';
413      for (var c = 0; c < plate.columns; c++)
414      {
415        html += '<td class="columnheader">' + (c+1) + '</td>';
416      }
417      html += '</tr>';
418      for (var r = 0; r < plate.rows; r++)
419      {
420        html += '<tr><td class="rowheader">' + Plates.toAlphaCoordinate[r] + '</td>';
421        for (var c = 0; c < plate.columns; c++)
422        {
423          var well = plate.getWell(r, c);
424          var cls = 'well';
425          var onclick = '';
426          var onmouseover = '';
427          var onmouseout = '';
428          var title = well.name ? Main.encodeTags(well.name) : '';
429          if (isSourcePlate)
430          {
431            // We can only move a biomaterial if the well is not empty or locked
432            if (well.id)
433            {
434              if (well.locked)
435              {
436                cls += ' filled locked';
437              }
438              else
439              {
440                cls += ' filled editable';
441                onclick = ' onclick="sourceWellOnClick('+r+','+c+')"';
442                onmouseover = ' onmouseover=sourceWellOnMouseOver('+r+','+c+')';
443                onmouseout = ' onmouseout=sourceWellOnMouseOut('+r+','+c+')';
444              }
445            }
446            else
447            {
448              cls += ' empty';
449            }
450          }
451          else
452          {
453            // We only add biomaterial to destination well if it is not locked
454            if (well.locked)
455            {
456              cls += ' unmappable';
457            }
458            else
459            {
460              cls += ' empty editable';
461              onclick = ' onclick="destWellOnClick('+r+','+c+')"';
462              onmouseover = ' onmouseover=destWellOnMouseOver('+r+','+c+')';
463              onmouseout = ' onmouseout=destWellOnMouseOut('+r+','+c+')';
464            }
465          }
466          html += '<td id="'+prefix+'.'+r+'.'+c+'" class="' + cls + '"' + onclick + onmouseover + onmouseout+' title="'+title+'">';
467          html += '<div class="info" id="'+prefix+'.'+r+'.'+c+'.info"></div></td>';
468        }
469        html += '</tr>';
470      }
471      html += '</table>';
472      if (isSourcePlate)
473      {
474        document.getElementById('plate.src').innerHTML = html;
475        document.getElementById('plate.src.name').innerHTML = Main.encodeTags(name);
476        sourcePlate = plate;
477      }
478      else
479      {
480        document.getElementById('plate.dest').innerHTML = html;
481        document.getElementById('plate.dest.name').innerHTML = Main.encodeTags(name);
482        destPlate = plate;
483        Main.showHide('plate.dest.options', !bigPlate);
484        showSourceCoordinatesOnClick();
485      }
486    }
487   
488    /**
489      Save the event.
490    */
491    function doMoveBioMaterial()
492    {
493      if (!destPlate)
494      {
495        alert('No destination plate has been selected');
496        return;
497      }
498      var frm = document.forms['main'];
499      if (Main.trimString(frm.name.value) == '')
500      {
501        alert("You must enter a name for the event.");
502        frm.name.focus();
503        return;
504      }
505     
506      frm.destplate_id.value = destPlate.id;
507      frm.rows.value = destPlate.rows;
508      frm.columns.value = destPlate.columns;
509     
510      var numMapped = 0;
511      for (var row = 0; row < destPlate.rows; row++)
512      {
513        for (var column = 0; column < destPlate.columns; column++)
514        {
515          var well = destPlate.getWell(row, column);
516         
517          if (well.mappedWell)
518          {
519            Forms.createHidden(frm, 'well.' + row + '.' + column, well.mappedWell.id);
520            numMapped++;
521          }
522        }
523      }
524     
525      if (numMapped == 0)
526      {
527        alert('No wells have been mapped.');
528        return;
529      }
530     
531      frm.submit();
532    }
533   
534
535    function selectHardwareOnClick()
536    {
537      var frm = document.forms['main'];
538      var url = '../../admin/hardware/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectone&callback=setHardwareCallback';
539      if (frm.hardware_id.length > 1)
540      {
541        var id = Math.abs(parseInt(frm.hardware_id[1].value));       
542        url += '&item_id='+id;
543      }
544      url += '&resetTemporary=1';
545      Main.openPopup(url, 'SelectHardware', 1000, 700);
546    }
547    function setHardwareCallback(id, name)
548    {
549      var frm = document.forms['main'];
550      var list = frm.hardware_id;
551      if (list.length < 2 || list[1].value == '0') // >
552      {
553        Forms.addListOption(list, 1, new Option());
554      }
555      list[1].value = id;
556      list[1].text = name;
557      list.selectedIndex = 1;
558    }
559 
560    function selectProtocolOnClick()
561    {
562      var frm = document.forms['main'];
563      var url = '../../admin/protocols/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectone&callback=setProtocolCallback';
564      if (frm.protocol_id.length > 1)
565      {
566        var id = Math.abs(parseInt(frm.protocol_id[1].value));       
567        url += '&item_id='+id;
568      }
569      url += '&resetTemporary=1';
570      Main.openPopup(url, 'SelectProtocol', 1000, 700);
571    }
572    function setProtocolCallback(id, name)
573    {
574      var frm = document.forms['main'];
575      var list = frm.protocol_id;
576      if (list.length < 2 || list[1].value == '0') // >
577      {
578        Forms.addListOption(list, 1, new Option());
579      }
580      list[1].value = id;
581      list[1].text = name;
582      list.selectedIndex = 1;
583    }
584   
585    function selectPlateMappingOnClick()
586    {
587      if (!destPlate)
588      {
589        alert('No destination plate has been selected');
590        return;
591      }
592      var url = '../../lims/platemappings/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectone&callback=setPlateMappingCallback';
593      url += '&resetTemporary=1';
594      url += '&tmpfilter:INT:sourceGeometry.rows='+sourcePlate.rows;
595      url += '&tmpfilter:INT:sourceGeometry.columns='+sourcePlate.columns;
596      url += '&tmpfilter:INT:sourceCount=1';
597      url += '&tmpfilter:INT:destinationGeometry.rows='+destPlate.rows;
598      url += '&tmpfilter:INT:destinationGeometry.columns='+destPlate.columns;
599      url += '&tmpfilter:INT:destinationCount=1';
600      Main.openPopup(url, 'SelectPlateMapping', 1000, 700);
601    }
602   
603    function setPlateMappingCallback(plateMappingId, name)
604    {
605      var request = Ajax.getXmlHttpRequest();
606      var url = '../../lims/platemappings/ajax.jsp?ID=<%=ID%>&cmd=GetMappingDetails&item_id=' + plateMappingId;
607      request.open("GET", url, false);
608      request.send(null);
609      var response = Ajax.parseResponse(request.responseText);
610      if (response.isError())
611      {
612        alert(response.getErrorMessage());
613        return false;
614      }
615     
616      var records = response.getElements();
617      var mappingInfo = records[0];
618      if (mappingInfo['source.plates'] != '1' || mappingInfo['source.rows'] != sourcePlate.rows || mappingInfo['source.columns'] != sourcePlate.columns)
619      {
620        if (!confirm("The selected mapping doesn't match the geometry of the source plate.\nContinue mapping overlapping positions?")) return;
621      }
622      else if (mappingInfo['destination.plates'] != '1' || mappingInfo['destination.rows'] != destPlate.rows || mappingInfo['destination.columns'] != destPlate.columns)
623      {
624        if (!confirm("The selected mapping doesn't match the geometry of the destination plate.\nContinue mapping overlapping positions?")) return;
625      }
626     
627      var mappings = records[1];
628      var numMapped = 0;
629      for (var i = 0; i < mappings.length; i++)
630      {
631        var mapping = mappings[i].split(',');
632        var srcWell = sourcePlate.getWell(parseInt(mapping[1]), parseInt(mapping[2]));
633        var destWell = destPlate.getWell(parseInt(mapping[4]), parseInt(mapping[5]));
634        if (srcWell && destWell)
635        {
636          if (!destWell.mappedWell && !destWell.locked && srcWell.id && !srcWell.locked && !srcWell.mappedWell)
637          {
638            srcWell.mapToWell(destWell);
639            numMapped++;
640          }
641        }
642      }
643    }
644   
645    function showSourceCoordinatesOnClick()
646    {
647      var frm = document.forms['main'];
648      Main.addOrRemoveClass(document.getElementById('plate.dest'), 'noinfo', !frm.showSourceCoordinates.checked);
649    }
650    </script>
651  </base:head>
652  <base:body onload="init()">
653    <div id="canvas"></div>
654    <h3>Move biomaterial to plate</h3>
655    <div class="boxedbottom" style="height: <%=(int)(scale*500)%>px; padding: 0px;">
656      <form name="main" action="index.jsp" method="post">
657      <input type="hidden" name="ID" value="<%=ID%>">
658      <input type="hidden" name="cmd" value="MoveBioMaterial">
659      <input type="hidden" name="sourceplate_id" value="<%=sourcePlateId%>">
660      <input type="hidden" name="destplate_id" value="">
661      <input type="hidden" name="rows" value="">
662      <input type="hidden" name="columns" value=""> 
663     
664      <table cellspacing="0" border="0" width="100%" style="background: #e0e0e0; padding-bottom: 6px;">
665      <tr valign="top">
666      <td>
667        <table class="form" cellspacing="0">
668        <tr>
669          <td class="prompt" style="width: 90px;">Event name</td>
670          <td><input <%=requiredClazz%> type="text" name="name" 
671            value="Move biomaterial" 
672            size="40" maxlength="<%=BioPlateEvent.MAX_NAME_LENGTH%>"></td>
673        </tr>
674        <tr>
675          <td class="prompt">Event date</td>
676          <td>
677            <table border="0" cellspacing="0" cellpadding="0">
678            <tr>
679            <td>
680              <input <%=clazz%> type="text" name="event_date" 
681                value="<%=HTML.encodeTags(dateFormatter.format(new Date()))%>" 
682                size="20" maxlength="20" title="Enter date in format: <%=htmlDateFormat%>">
683              &nbsp;
684            </td>
685            <td>
686            <base:button 
687              onclick="<%="Dates.selectDate('Event date', 'main', 'event_date', null, '"+jsDateFormat+"')"%>"
688              image="calendar.png"
689              title="Calendar&hellip;" 
690              tooltip="Select a date from a calendar" 
691            />
692            </td>
693            </tr>
694            </table>
695          </td>
696        </tr>
697        <tr>
698          <td class="prompt">Protocol</td>
699          <td>
700            <base:select 
701              id="protocol_id"
702              clazz="selectionlist"
703              required="false"
704              current="<%=null%>"
705              recent="<%=recentProtocols%>"
706              onselect="selectProtocolOnClick()"
707            />
708          </td>
709        </tr>
710        <tr>
711          <td class="prompt">Hardware</td>
712          <td>
713            <base:select 
714              id="hardware_id"
715              clazz="selectionlist"
716              required="false"
717              current="<%=null%>"
718              recent="<%=recentHardware%>"
719              onselect="selectHardwareOnClick()"
720            />
721          </td>
722        </tr>
723        </table>
724      </td>
725      <td>
726        <b>Description</b><br>
727        <textarea <%=clazz%> rows="4" cols="40" name="description" wrap="virtual"
728          ></textarea>
729        <a href="javascript:Main.zoom('Description', 'main', 'description')"
730          title="Edit in larger window"><base:icon image="zoom.gif" /></a>
731      </td>
732    </tr>
733    </table>
734
735    <tbl:toolbar id="toolbar.mappings" style="border-left: 0px; border-right: 0px;">
736      <tbl:button title="Select plate&hellip;" 
737          onclick="javascript:selectBioPlateOnClick()" 
738          image="move_to_plate.png" 
739          tooltip="Select the destination plate"
740        />
741        <tbl:button title="Clear" 
742          onclick="clearMapping()" 
743          image="cancel.gif" 
744          tooltip="Clear all mapped wells"
745        />
746        <tbl:button title="Place by row" 
747          onclick="placeByRow()" 
748          image="place_by_row.png" 
749          tooltip="Place remaining items; start with rows"
750        />
751        <tbl:button title="Place by column" 
752          onclick="placeByColumn()" 
753          image="place_by_column.png" 
754          tooltip="Place remaining items; start with columns"
755        />
756        <tbl:button title="Predefined mapping&hellip;" 
757          onclick="selectPlateMappingOnClick()" 
758          image="star.png" 
759          tooltip="Select a predefined plate mapping"
760        />
761      </tbl:toolbar>
762 
763      <table cellspacing="0" cellpadding="0" border="0" width="100%" style="padding: 4px;">
764      <tr valign="top">
765        <td style="width: 50%;">
766          <div style="max-height: <%=(int)(scale*350)%>px; overflow: auto;">
767            <b>Source plate:</b> <span id="plate.src.name"></span>
768            <div id="plate.src"></div>
769          </div>
770        </td>
771        <td style="width: 50%;">
772          <div style="max-height: <%=(int)(scale*350)%>px; overflow: auto;">
773            <b>Destination plate:</b> <span id="plate.dest.name"><i>not selected</i></span>
774            <div id="plate.dest"></div>
775            <div id="plate.dest.options" style="display: none;">
776            <input type="checkbox" name="showSourceCoordinates" 
777              <%=showSourceCoordinates ? "checked" : ""%> value="1"
778              onclick="showSourceCoordinatesOnClick()">Show source coordinates
779            </div>
780          </div>
781        </td>
782      </tr>
783      </table>
784    </div>
785    </form>
786
787    <table align="center">
788    <tr>
789      <td width="50%"><base:button onclick="doMoveBioMaterial()" title="Save" /></td>
790      <td width="50%"><base:button onclick="window.close()" title="Cancel" /></td>
791    </tr>
792    </table>
793   
794  </base:body>
795  </base:page>
796  <%
797}
798finally
799{
800  if (dc != null) dc.close();
801}
802%>
Note: See TracBrowser for help on using the repository browser.