source: trunk/www/plugins/net/sf/basedb/plugins/executor/external_plugin_parameters.jsp @ 5946

Last change on this file since 5946 was 5946, checked in by Nicklas Nordborg, 10 years ago

References #1655: GUI improvements

Replaces a lot of GIF images with PNG.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.1 KB
Line 
1<%-- $Id: external_plugin_parameters.jsp 5946 2012-02-03 13:18:47Z nicklas $
2  ------------------------------------------------------------------
3  Copyright (C) 2010 Martin Svensson
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 Martin
23  @version 2.15
24--%>
25<%@ page pageEncoding="UTF-8" session="false"
26  import="net.sf.basedb.core.DbControl"
27  import="net.sf.basedb.core.Item"
28  import="net.sf.basedb.core.ItemContext"
29  import="net.sf.basedb.core.ParameterType"
30  import="net.sf.basedb.core.PluginDefinition"
31  import="net.sf.basedb.core.PluginConfiguration"
32  import="net.sf.basedb.core.PluginConfigurationRequest"
33  import="net.sf.basedb.core.PluginParameter" 
34  import="net.sf.basedb.core.RequestInformation"
35  import="net.sf.basedb.core.SessionControl"
36  import="net.sf.basedb.core.StringParameterType"
37  import="net.sf.basedb.clients.web.Base"
38  import="net.sf.basedb.clients.web.WebException"
39  import="net.sf.basedb.clients.web.util.HTML" 
40  import="net.sf.basedb.plugins.executor.ExternalProgramExecutor"
41  import="net.sf.basedb.plugins.executor.ParameterDefinition"
42  import="net.sf.basedb.util.Values" 
43  import="java.util.ArrayList"
44  import="java.util.Arrays"
45  import="java.util.Collections"
46  import="java.util.HashMap"
47  import="java.util.Iterator"
48  import="java.util.List"
49  import="java.util.Map" 
50  import="org.jdom.Element"
51%>
52<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
53<%@ taglib prefix="tbl" uri="/WEB-INF/table.tld" %>
54<%
55  final SessionControl sc = Base.getExistingSessionControl(pageContext, true);
56final String ID = sc.getId();
57final float scale = Base.getScale(sc);
58final String clazz = "class=\"text\"";
59final String requiredClazz = "class=\"text required\"";
60
61DbControl dc = null;
62try
63{
64  PluginDefinition plugin = (PluginDefinition)sc.getSessionSetting("plugin.configure.plugin"); 
65  PluginConfiguration pluginConfig = (PluginConfiguration)sc.getSessionSetting("plugin.configure.config");
66  PluginConfigurationRequest pcRequest = (PluginConfigurationRequest)sc.getSessionSetting("plugin.configure.request");
67  RequestInformation ri = pcRequest.getRequestInformation();
68  String title = HTML.encodeTags(ri.getTitle());
69  String helpText = ri.getDescription(); 
70  if (helpText == null && config != null) helpText = pluginConfig.getDescription();
71  if (helpText == null) helpText = plugin.getDescription();
72
73  String errorMessage = (String)sc.getSessionSetting("plugin.configure.errors.message");
74  List<Throwable> errors = (List<Throwable>)sc.getSessionSetting("plugin.configure.errors.list");
75 
76  String xml = request.getParameter("parameter:externalParameters");
77  if (xml == null) xml = (String)pcRequest.getCurrentParameterValue("externalParameters");
78  List<ParameterDefinition> externalParameters = null;
79  try
80  {
81    externalParameters = ParameterDefinition.parseXml(xml, false);
82  }
83  catch (Throwable ex)
84  {
85    errorMessage = "Could not load parameter definitions";
86    errors = Collections.singletonList(ex);
87  }
88  %>
89  <base:page type="popup" title="<%=title%>">
90  <base:head scripts="plugin.js,xml.js" styles="parameters.css,toolbar.css">
91    <script language="JavaScript">
92      function init()
93      {
94        var frm = document.forms['configure'];
95        var pd;
96        <%
97        if (externalParameters != null)
98        {
99          for (ParameterDefinition pdef : externalParameters)
100          {
101            %>
102            pd = new ParameterDefinition('<%=pdef.getType()%>', '<%=HTML.javaScriptEncode(pdef.getName())%>', <%=pdef.isRequired() ? 1 : 0%>);
103            pd.multiple = <%=pdef.isMultiple() ? "1" : "0"%>;
104            pd.defaultValue = '<%=HTML.javaScriptEncode(pdef.getDefaultValue())%>';
105            pd.description = '<%=HTML.javaScriptEncode(pdef.getDescription())%>';
106            <%
107            for (String option : pdef.getOptions())
108            {
109              %>
110              pd.setOption('<%=option%>', '<%=HTML.javaScriptEncode(pdef.getOption(option))%>');
111              <%
112            }
113            %>
114            allParameters[allParameters.length] = pd;
115            pd.addToList(frm.programParameters);
116            <%
117          }
118        }
119        %>
120      }
121
122      function hideErrorList()
123      {
124        Main.hide('errorlist');
125        Main.show('showerrorlist');
126      }
127      function showErrorList()
128      {
129        Main.show('errorlist');
130        Main.hide('showerrorlist');
131      }
132      function toggleStacktrace(index)
133      {
134        Main.showHide('stacktrace.' + index);
135        var img = document.getElementById('stacktracelink.'+index);
136        if (img.src.indexOf('show_section') > 0)
137        {
138          img.src = getRoot() + '/images/hide_section.png';
139        }
140        else
141        {
142          img.src = getRoot() + '/images/show_section.png';
143        }
144      }
145
146      function doCancel()
147      {
148        location = 'index.jsp?ID=<%=ID%>&cmd=CancelWizard';
149      }
150
151      function saveSettings()
152      {
153        var frm = document.forms['configure'];
154        var xml = '<parameter-definition>\n';
155        for (var i=0; i < allParameters.length; i++)
156        {
157          var pdef = allParameters[i];
158          var error = pdef.validate(frm);
159          if (error)
160          {
161            frm.programParameters.selectedIndex = i;
162            parameterOnClick();
163            if (error.field.focus) error.field.focus();
164            alert(error.msg);
165            return;
166          }
167          xml += pdef.toXml() + '\n';
168        }
169        xml += '</parameter-definition>\n';
170        frm['parameter:externalParameters'].value = xml;
171        frm.submit();
172      }
173
174      function setRadio(name, index)
175      {
176        var frm = document.forms['configure'];
177        frm[name][index].click();
178      }
179
180      function parameterTypeOnChange()
181      {
182        updateForm();
183        onFormChange();
184      }
185     
186      function onFormChange()
187      {
188        var frm = document.forms['configure'];
189        var parameterDef = allParameters[currentParameter];
190        parameterDef.readFromForm(frm);
191        parameterDef.updateListOption(frm.programParameters[currentParameter]);
192      }
193
194      function addOnClick()
195      {
196        var frm = document.forms['configure'];
197        var pdef = new ParameterDefinition('string', 'new', 0);
198        allParameters[allParameters.length] = pdef;
199        pdef.addToList(frm.programParameters);
200        frm.programParameters.selectedIndex = frm.programParameters.length-1;
201        parameterOnClick();
202        frm.parameterName.focus();
203        frm.parameterName.select();
204      }
205
206
207      function removeOnClick()
208      {
209        var frm = document.forms['configure'];
210        var selected = frm.programParameters.selectedIndex;
211        if (!confirm('Remove ' + allParameters[selected].name + '?')) return;
212        frm.programParameters[selected] = null;
213        allParameters.splice(selected, 1);
214        Main.hide('parameterDefinition');
215      }
216     
217      function moveParameter(up)
218      {
219        var frm = document.forms['configure'];
220        var selected = frm.programParameters.selectedIndex;
221        Forms.moveListOptions(frm.programParameters, up);
222        var moveTo = -1;
223        if (up)
224        {
225          if (selected < allParameters.length - 1) moveTo = selected + 1;
226        }
227        else 
228        {
229          if (selected > 0) moveTo = selected - 1;
230        }
231        if (moveTo >= 0)
232        {
233          var pp = allParameters[selected];
234          allParameters[selected] = allParameters[moveTo];
235          allParameters[moveTo] = pp;
236        }
237      }
238
239      var currentParameter;
240      function parameterOnClick()
241      {
242        var frm = document.forms['configure'];
243        if (frm.programParameters.selectedIndex < 0) return;
244        currentParameter = frm.programParameters.selectedIndex;
245        var parameterDef = allParameters[currentParameter];
246        if (!parameterDef) return;
247        Main.show('parameterDefinition');
248        parameterDef.writeToForm(frm);
249        updateForm();
250      }
251
252      function updateForm()
253      {
254        var frm = document.forms['configure'];
255        var type = frm.parameterType[frm.parameterType.selectedIndex].value;
256        if (type == 'integer')
257        {
258          frm.parameterDefault.setAttribute("onkeypress", "return Numbers.integerOnly(event)");
259          frm.minValue.setAttribute("onkeypress", "return Numbers.integerOnly(event)");
260          frm.maxValue.setAttribute("onkeypress", "return Numbers.integerOnly(event)");
261          Main.show('minMax');
262        }
263        else if (type == 'float')
264        {
265          frm.parameterDefault.setAttribute("onkeypress", "return Numbers.numberOnly(event)");
266          frm.minValue.setAttribute("onkeypress", "return Numbers.numberOnly(event)");
267          frm.maxValue.setAttribute("onkeypress", "return Numbers.numberOnly(event)");
268          Main.show('minMax');
269        }
270        else
271        {
272          frm.parameterDefault.setAttribute("onkeypress", null);
273          Main.hide('minMax');
274        }
275        if (type == 'boolean')
276        {
277          Main.show('booleanDefault');
278          Main.hide('regularDefault');
279        }
280        else
281        {
282          Main.hide('booleanDefault');
283          Main.show('regularDefault');
284        }
285        if (type == 'enumeration')
286        {
287          Main.show('enumerationOptions');
288        }
289        else
290        {
291          Main.hide('enumerationOptions');
292        }
293       
294      }
295
296     
297      var allParameters = new Array();
298      function ParameterDefinition(parameterType, name, required)
299      {
300        this.parameterType = parameterType;
301        this.name = name;
302        this.required = required;
303        this.multiple = 0;
304        this.defaultValue = '';
305        this.description = '';
306        this.options = new Array();
307
308        this.setOption = function(key, value)
309        {
310          this.options[key] = value;
311        }
312
313        this.getOption = function(key)
314        {
315          return this.options[key];
316        }
317       
318        this.writeToForm = function(frm)
319        {
320          Forms.selectListOption(frm.parameterType, this.parameterType);
321          frm.parameterName.value = this.name;
322          frm.parameterIsRequired.checked = this.required;
323          frm.parameterIsMultiple.checked = this.multiple;
324          if (this.parameterType == 'boolean')
325          {
326            Forms.checkRadio(frm.booleanDefault, this.defaultValue);
327          }
328          else
329          {
330            frm.parameterDefault.value = this.defaultValue;
331          }
332          frm.enumerationOptions.value = this.options['enum'] || '';
333          frm.minValue.value = this.options['min'] || '';
334          frm.maxValue.value = this.options['max'] || '';
335          frm.parameterDescription.value = this.description;
336          if (frm.parameterXML) frm.parameterXML.value = this.toXml();
337        }
338
339        this.readFromForm = function(frm)
340        {
341          this.parameterType = frm.parameterType[frm.parameterType.selectedIndex].value;
342          this.name = frm.parameterName.value;
343          this.required = frm.parameterIsRequired.checked ? 1 : 0;
344          this.multiple = frm.parameterIsMultiple.checked ? 1 : 0;
345          if (this.parameterType == 'boolean')
346          {
347            var radio = Forms.getCheckedRadio(frm.booleanDefault);
348            this.defaultValue = radio ? radio.value : '';
349          }
350          else
351          {
352            this.defaultValue = frm.parameterDefault.value;
353          }
354          if (this.parameterType == 'enumeration')
355          {
356            this.setOption('enum', frm.enumerationOptions.value);
357          }
358          if (this.parameterType == 'integer' || this.parameterType == 'float')
359          {
360            this.setOption('min', frm.minValue.value);
361            this.setOption('max', frm.maxValue.value);
362          }
363          this.description = frm.parameterDescription.value;
364        }
365
366        this.updateListOption = function(listOption)
367        {
368          listOption.value = this.name;
369          listOption.text = this.toString();
370        }
371       
372        this.addToList = function(list)
373        {
374          Forms.addListOption(list, -1, new Option(this.toString(), this.name));
375        }
376       
377        this.toString = function()
378        {
379          return this.name + ' (' + this.parameterType + ')';
380        }
381
382        this.toXml = function()
383        {
384          var doc = Xml.createDocument('parameter');
385          var root = doc.firstChild;
386          Xml.setAttribute(root, 'type', this.parameterType);
387          Xml.setAttribute(root, 'name', this.name);
388          Xml.setAttribute(root, 'required', this.required ? 'true' : 'false');
389          Xml.setAttribute(root, 'multiple', this.multiple ? 'true' : 'false');
390          if (this.description) Xml.addTag(root, 'description', this.description);
391          if (this.defaultValue) Xml.addTag(root, 'default', this.defaultValue);
392          var optionsTag;
393          for (var option in this.options)
394          {
395            if (!optionsTag) optionsTag = Xml.addTag(root, 'options');
396            var optionTag = Xml.addTag(optionsTag, 'option', this.options[option]);
397            Xml.setAttribute(optionTag, 'key', option);
398          }
399          return Xml.toString(doc);
400        }
401
402        this.validate = function(frm)
403        {
404          // A parameter name is required
405          if (Main.trimString(this.name) == '')
406          {
407            return new ValidationError('Missing name for parameter', frm.parameterName);
408          }
409          // A parameter type is required
410          else if (Main.trimString(this.parameterType) == '')
411          {
412            return new ValidationError('Missing type for parameter', frm.parameterType);
413          }
414          // The name must be unique
415          for (var i = 0; i < allParameters.length; i++)
416          {
417            var other = allParameters[i];
418            if (other == this) break;
419            if (other.name == this.name)
420            {
421              return new ValidationError('Parameter has duplicate name: ' + this.name, 
422                  frm.parameterName);
423            }
424          }
425          if (this.parameterType == 'enumeration')
426          {
427            // An enumeration must have at least one option
428            var options = Main.trimString(this.getOption('enum'));
429            if (options == '')
430            {
431              return new ValidationError('No options for enumeration: ' + this.name, 
432                  frm.enumerationOptions);
433            }
434            // If a default value is specified it must be among the options
435            else if (this.defaultValue)
436            {
437              var opt = options.split(/[\n\r]/);
438              var index = -1;
439              for (var i = 0; i < opt.length; i++)
440              {
441                if (opt[i] == this.defaultValue)
442                {
443                  index = i;
444                  break;
445                }
446              }
447              if (index == -1)
448              {
449                return new ValidationError("'" + this.defaultValue + "' is not an option in enumeration: " + this.name, 
450                    frm.parameterDefault);
451              }
452            }
453          }
454          else if (this.parameterType == 'integer' || this.parameterType == 'float')
455          {
456            // If a default value is specified, it must be within max and min limits
457            if (this.defaultValue)
458            {
459              var def = parseFloat(this.defaultValue);
460              var min = parseFloat(this.getOption('min'));
461              var max = parseFloat(this.getOption('max'));
462              if (def < min)
463              {
464                return new ValidationError(def + ' < ' + min + ' for parameter: ' + this.name, 
465                    frm.parameterDefault);
466              }
467              else if (def > max)
468              {
469                return new ValidationError(def + ' > ' + max + ' for parameter: ' + this.name,
470                    frm.parameterDefault);
471              }
472            }
473          }
474          return null;
475        }
476      }
477
478      function ValidationError(msg, field)
479      {
480        this.msg = msg;
481        this.field = field;
482      }
483     
484    </script>
485  </base:head>
486  <base:body onload="init()">
487    <p>
488    <form action="index.jsp" method="post" name="configure" onsubmit="return false;">
489    <input type="hidden" name="ID" value="<%=ID%>">
490    <input type="hidden" name="cmd" value="SetParameters">
491    <input type="hidden" name="requestId" value="<%=request.getParameter("requestId")%>">
492    <input type="hidden" name="parameter:externalParameters" value="">
493   
494    <h3 class="docked"><%=title%> <base:help helpid="executor.program.parameters" /></h3>
495    <div class="boxed">
496      <table class="form">
497      <tr >
498        <td class="prompt">Plugin</td>
499        <td><%=plugin == null ? "<i>- none -</i>" : HTML.encodeTags(plugin.getName())%></td>
500        <td class="prompt">Configuration</td>
501        <td><%=pluginConfig == null ? "<i>- none -</i>" : HTML.encodeTags(pluginConfig.getName())%></td>
502      </tr>
503      </table>
504     
505      <div class="pluginhelp">
506        <%=HTML.niceFormat(helpText)%>
507      </div>
508     
509      <%
510      if (errorMessage != null || (errors != null && errors.size() > 0))
511      {
512        %>
513        <div id="errors" style="margin-bottom: 12px;" class="parameterhelp">
514          <div class="error" style="margin: 0px;">
515          <%=errorMessage %>
516          </div>
517          <%
518          if (errors != null && errors.size() > 0)
519          {
520            %>
521            <div id="showerrorlist" style="display: none;">
522              <base:icon image="bullet.png" /><a href="javascript:showErrorList()">Show</a>
523            </div>
524            <div id="errorlist">
525              <ol>
526              <%
527              int i = 0;
528              java.io.PrintWriter pw = new java.io.PrintWriter(out);
529              for (Throwable t : errors)
530              {
531                ++i;
532                t.printStackTrace();
533                %>
534                <li><%=t.getMessage()%><br>
535                  <base:icon 
536                    image="show_section.png" 
537                    onclick="<%="toggleStacktrace(" + i + ")"%>" 
538                    tooltip="Toggle display of detailed stacktrace"
539                    id="<%="stacktracelink." + i %>"
540                    style="float: left;"
541                  />
542                  <div id="stacktrace.<%=i%>" style="display:none; font-size: smaller; position: relative; left: 1em; top: -1em; overflow: auto;">
543                  <%
544                  out.print("<pre>");
545                  while (t != null)
546                  {
547                    out.println(t.toString());
548                    StackTraceElement[] st = t.getStackTrace();
549                    for (int index = 0; index < st.length; ++index)
550                    {
551                      out.print("...at ");
552                      out.println(st[index].toString());
553                    }
554                    t = t.getCause();
555                    if (t != null) out.print("\nCaused by: ");
556                  }
557                  out.print("</pre>");
558                  %>
559                  </div>
560                </li>
561                <%
562              }
563              %>
564              </ol>
565              <base:icon image="bullet.png" /><a href="javascript:hideErrorList()">Hide all</a>
566            </div>
567            <%
568          }
569          %>
570        </div>
571        <%
572      }
573      %>
574      <table class="form" cellspacing="0" border="0" cellpadding="0" width="100%">
575      <tr>
576      <td>     
577        <table cellspacing="2" border="0" cellpadding="0" cellspacing="0">
578        <tr >
579        <td>
580          <tbl:toolbar>
581            <tbl:button 
582              image="add.png" 
583              title="Add" 
584              onclick="addOnClick()"
585              tooltip="Add a new parameter definition"
586            />
587            <tbl:button 
588              image="remove.png" 
589              title="Remove" 
590              onclick="removeOnClick()"
591              tooltip="Remove the selected parameter(s)"
592            />
593            <tbl:button 
594              image="move_up.png"
595              onclick="moveParameter(false)" 
596              tooltip="Move the selected paramer(s) up"
597            />
598            <tbl:button 
599              image="move_down.png" 
600              onclick="moveParameter(true)" 
601              tooltip="Move the selected paramer(s) down"
602            />
603          </tbl:toolbar>
604          <select name="programParameters" size="18" style="width: 100%;" onclick="parameterOnClick()"></select>
605        </td>
606        </tr>
607        </table>
608      </td>
609      <td>
610        <table id="parameterDefinition" style="display: none;">
611        <tr>
612          <td class="prompt">Name</td>
613          <td><input type="text" <%=requiredClazz%> name="parameterName" style="width:24em;" onchange="onFormChange()"></td>
614        </tr>
615        <tr>
616          <td class="prompt">Parameter type</td>
617          <td>
618            <select name="parameterType" size="1" style="width:15em;" onClick="parameterTypeOnChange()" class="required">
619              <option value="string" 
620                title="A free-text string no more than 255 characters"
621                >String (short)</option>
622              <option value="text"
623                title="A free-text string up to 64K characters"
624                >String (long)</option>
625              <option value="integer"
626                title="An integer that is optionally bounded"
627                >Integer</option>
628              <option value="float"
629                title="A floating point number"
630                >Float</option>
631              <option value="boolean"
632                title="A true/false selection"
633                >Boolean</option>
634              <option value="enumeration"
635                title="Select value(s) from a predefined list"
636                >Enumeration</option>
637              <option value="factor"
638                title="Select experimental factor(s) to include in the export"
639                >Experimental factor</option>
640              <option value="spotformula"
641                title="Select a spot formula to include in the export"
642                >Spot field/formula</option>
643              <option value="assays"
644                title="Select special assays (all are still included in the export)"
645                >Bioassay selection</option>
646            </select>
647            <br>
648            <input type="checkbox" name="parameterIsRequired" id="parameterIsRequired" value="1" onclick="onFormChange()">
649            <label for="parameterIsRequired">Required</label>
650            <input type="checkbox" name="parameterIsMultiple" id="parameterIsMultiple" value="1" onclick="onFormChange()">
651            <label for="parameterIsMultiple">Multiple values</label>
652          </td>
653        </tr>
654        <tr id="minMax" style="display:none;">
655          <td class="prompt">Min</td>
656          <td>
657            <input type="text" <%=clazz%> name="minValue" style="width:8em;" onchange="onFormChange()">
658            <b>Max</b>
659            <input type="text" <%=clazz%> name="maxValue" style="width:8em;" onchange="onFormChange()">
660          </td>
661        </tr>
662        <tr id="enumerationOptions" style="display:none;">
663          <td class="prompt">Options</td>
664          <td>
665            <textarea name="enumerationOptions" rows="5" style="width:24em;" 
666              onchange="onFormChange()" title="One option per line"></textarea>
667          </td>
668        </tr>
669        <tr id="regularDefault">
670          <td class="prompt">Default value</td>
671          <td><input type="text" <%=clazz%> name="parameterDefault" style="width:24em;" 
672            onchange="onFormChange()" title="Enter a default values for the parameter"></td>
673        </tr>
674        <tr id="booleanDefault" style="display:none;">
675          <td class="prompt">Default value</td>
676          <td><input type="radio" name="booleanDefault" id="booleanDefaultTrue" value="1" 
677              onclick="onFormChange()"><label for="booleanDefaultTrue">true</label>
678            <input type="radio" name="booleanDefault" id="booleanDefaultFalse" value="0" 
679              onclick="onFormChange()"><label for="booleanDefaultFalse">false</label>
680          </td>
681        </tr>
682        <tr>
683          <td class="prompt">Description</td>
684          <td><textarea name="parameterDescription" rows="5" style="width:24em;" 
685            onchange="onFormChange()" title="Enter a description/help text for this parameter"></textarea></td>
686        </tr>
687        <!--
688        <tr>
689          <td class="prompt">XML (debug)</td>
690          <td><textarea name="parameterXML" rows="5" style="width:24em;"></textarea></td>
691        </tr>
692        -->
693        </table>
694               
695           
696
697        </td>   
698        </tr>
699      </table>
700    </div>
701    </form>
702    <div align="center">
703    <base:buttongroup>     
704      <base:button onclick="saveSettings()" title="Next" />
705      <base:button onclick="doCancel()" title="Cancel" />
706    </base:buttongroup>
707    </div>
708  </base:body>
709  </base:page>
710  <%
711}
712finally
713{
714  if (dc != null)
715    dc.close();
716}
717%>
Note: See TracBrowser for help on using the repository browser.