source: trunk/www/common/expression_builder.jsp @ 3913

Last change on this file since 3913 was 3913, checked in by Nicklas Nordborg, 14 years ago

Fixes #778: Add expression to formula

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Id
File size: 16.1 KB
Line 
1<%-- $Id: expression_builder.jsp 3913 2007-11-06 09:42:09Z nicklas $
2  ------------------------------------------------------------------
3  Copyright (C) 2006, 2007 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 modify it
9  under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  BASE is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  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, Boston, MA
21  02111-1307, USA. 
22  ------------------------------------------------------------------
23
24  @author Nicklas
25  @version 2.0
26--%>
27<%@ page session="false"
28  import="net.sf.basedb.core.DbControl"
29  import="net.sf.basedb.core.SessionControl"
30  import="net.sf.basedb.core.Item"
31  import="net.sf.basedb.core.BioAssaySet"
32  import="net.sf.basedb.core.RawDataType"
33  import="net.sf.basedb.core.RawDataTypes"
34  import="net.sf.basedb.core.RawDataProperty"
35  import="net.sf.basedb.core.ExtendedProperty"
36  import="net.sf.basedb.core.ExtendedProperties"
37  import="net.sf.basedb.core.Formula"
38  import="net.sf.basedb.core.ReporterList"
39  import="net.sf.basedb.core.ItemQuery"
40  import="net.sf.basedb.core.Include"
41  import="net.sf.basedb.core.query.Orders"
42  import="net.sf.basedb.core.query.Hql"
43  import="net.sf.basedb.util.Enumeration"
44  import="net.sf.basedb.util.jep.Jep"
45  import="net.sf.basedb.clients.web.Base"
46  import="net.sf.basedb.util.Values"
47  import="net.sf.basedb.clients.web.util.HTML"
48  import="net.sf.basedb.clients.web.DynamicUtil"
49  import="net.sf.basedb.clients.web.taglib.table.TableColumn"
50  import="java.util.List"
51  import="java.util.LinkedList"
52%>
53<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
54<%@ taglib prefix="tbl" uri="/WEB-INF/table.tld" %>
55<%
56  String title = request.getParameter("title");
57  String form = request.getParameter("form");
58  String textarea = request.getParameter("textarea");
59  String callback = request.getParameter("callback");
60  Formula.Type formulaType = Formula.Type.valueOf(request.getParameter("formulatype"));
61  RawDataType rawDataType = RawDataTypes.getRawDataType(request.getParameter("rawdatatype"));
62  int bioAssaySetId = Values.getInt(request.getParameter("bioassayset_id"), -1);
63  boolean restrictions = Values.getBoolean(request.getParameter("restrictions"));
64  int channels = Values.getInt(request.getParameter("channels"));
65  final SessionControl sc = Base.getExistingSessionControl(pageContext, true);
66 
67  DbControl dc = sc.newDbControl();
68  try
69  {
70    BioAssaySet bas = bioAssaySetId == -1 ? null : BioAssaySet.getById(dc, bioAssaySetId);
71    int maxRawMappings = bas == null ? 1 : bas.getMaxRawMappingsForSpot();
72
73    List<TableColumn> spotProperties = new LinkedList<TableColumn>();
74    DynamicUtil.addSpotColumns(spotProperties, dc, channels);
75    List<TableColumn> rawProperties = new LinkedList<TableColumn>();
76    if (rawDataType != null)
77    {
78      DynamicUtil.addFormulaColumns(spotProperties, dc, rawDataType, Formula.Type.COLUMN_EXPRESSION, "", "", maxRawMappings == 1);
79      if (bas != null) DynamicUtil.addExtraColumns(spotProperties, dc, bas, "", "", "[Xtra] ");
80      if (maxRawMappings == 1) DynamicUtil.addRawDataColumns(rawProperties, dc, rawDataType, "", "", "");
81    }
82    List<TableColumn> reporterProperties = new LinkedList<TableColumn>();
83    DynamicUtil.addReporterColumns(reporterProperties, dc, "", "", "");
84   
85    ItemQuery<ReporterList> reporterListQuery = ReporterList.getQuery();
86    reporterListQuery.include(Include.MINE, Include.SHARED, Include.IN_PROJECT, Include.OTHERS);
87    reporterListQuery.order(Orders.asc(Hql.property("name")));
88    List<ReporterList> reporterLists = reporterListQuery.list(dc);
89   
90  %>
91  <base:page type="popup" title="<%=title%>">
92  <base:head scripts="table.js" styles="toolbar.css">
93    <script language="JavaScript">
94    function getText()
95    {
96      document.forms['expression'].expression.value = window.opener.document.forms['<%=form%>'].elements['<%=textarea%>'].value;
97    }
98    function setExpressionAndClose()
99    {
100      var value = document.forms['expression'].expression.value;
101      <%
102      if (callback != null)
103      {
104        StringBuilder sb = new StringBuilder();
105        sb.append("window.opener.");
106        sb.append(callback).append("(");
107        if (form != null) sb.append("'").append(form).append("',");
108        if (textarea != null) sb.append("'").append(textarea).append("',");
109        sb.append("value)");
110        %>
111        <%=sb.toString()%>
112        <%
113      }
114      else
115      {
116        %>
117        var textElement = window.opener.document.forms['<%=form%>'].elements['<%=textarea%>'];
118        if (textElement.type == 'text') value = value.replace(/\n/g, '');
119        textElement.value = value;
120        <%
121      }
122      %>
123      window.close();
124    }
125    function insertSelected(list, prefix, suffix)
126    {
127      var value = list[list.selectedIndex].value;
128      if (value != '')
129      {
130        if (prefix) value = prefix + value;
131        if (!suffix) suffix = '';
132        encloseSelection(value, suffix);
133      }
134      list.selectedIndex = 0;
135    }
136    function insertReporterListFunction()
137    {
138      var frm = document.forms['expression'];
139      var listFunction = frm.listFunction[frm.listFunction.selectedIndex].value;
140      var listId = frm.reporterList[frm.reporterList.selectedIndex].value;
141      encloseSelection(listFunction+'(' + listId + ')', '');
142      frm.reporterList.selectedIndex = 0;
143    }
144 
145    /*
146      Enclose the selected text with prefix and suffix. Code taken
147      from Trac: http://projects.edgewall.com/trac/
148    */
149    function encloseSelection(prefix, suffix)
150    {
151      var frm = document.forms['expression'];
152      var textarea = frm.expression;
153      textarea.focus();
154        var start, end, sel, scrollPos, subst;
155        if (typeof(document["selection"]) != "undefined")
156        {
157          sel = document.selection.createRange().text;
158        }
159        else if (typeof(textarea["setSelectionRange"]) != "undefined")
160        {
161          start = textarea.selectionStart;
162          end = textarea.selectionEnd;
163          scrollPos = textarea.scrollTop;
164          sel = textarea.value.substring(start, end);
165        }
166        if (sel.match(/ $/))
167        {
168          // exclude ending space char, if any
169            sel = sel.substring(0, sel.length - 1);
170            suffix = suffix + " ";
171        }
172        subst = prefix + sel + suffix;
173        if (typeof(document["selection"]) != "undefined")
174        {
175          var range = document.selection.createRange().text = subst;
176          textarea.caretPos -= suffix.length;
177        }
178        else if (typeof(textarea["setSelectionRange"]) != "undefined")
179        {
180          textarea.value = textarea.value.substring(0, start) + subst +
181                           textarea.value.substring(end);
182          if (sel)
183          {
184            textarea.setSelectionRange(start + subst.length, start + subst.length);
185          }
186          else
187          {
188            textarea.setSelectionRange(start + prefix.length, start + prefix.length);
189          }
190          textarea.scrollTop = scrollPos;
191        }
192      }
193   
194    var properties = new Array();
195    <%
196    for (TableColumn tc : rawProperties)
197    {
198      %>
199      properties['raw.<%=tc.getProperty()%>'] = 1;
200      <%
201    }
202    for (TableColumn tc : reporterProperties)
203    {
204      %>
205      properties['reporter.<%=tc.getProperty()%>'] = 1;
206      <%
207    }
208    %>
209     
210    function validateOnClick()
211    {
212      var frm = document.forms['expression'];
213      if (frm.expression.value != '')
214      {
215        var expression = frm.expression.value.replace('if(', 'jepIf(');
216        try
217        {
218          var result = eval(expression);
219          alert('The expressions seems to be ok.\nNote! This feature is experimental and may not be 100% correct.');
220        }
221        catch (er)
222        {
223          alert(er + '\nNote! This feature is experimental and may not be 100% correct.');
224        }
225      }
226    }
227   
228    function raw(property)
229    {
230      <%
231      if (maxRawMappings != 1)
232      {
233        %>
234        throw 'Cannot use function raw() for bioassayset that has multiple mappings to raw data';
235        <%
236      }
237      %>
238      var rdt = '<%=rawDataType == null ? "" : rawDataType.getId()%>';
239      if (!property) throw 'Property must be specified for function raw()';
240      if (rdt == '') throw 'Cannot use function raw(). No raw data type selected';
241      if (!properties['raw.'+property]) throw 'Property '+property+' not found for raw data type ' + rdt;
242      return Math.random() * 100;
243    }
244   
245    function mean(property)
246    {
247      var rdt = '<%=rawDataType == null ? "" : rawDataType.getId()%>';
248      if (!property) throw 'Property must be specified for function mean()';
249      if (rdt == '') throw 'Cannot use function mean(). No raw data type selected';
250      if (!properties['property.'+property]) throw 'Property '+property+' not found for raw data type ' + rdt;
251      return Math.random() * 100;
252    }
253 
254    function ch(channel)
255    {
256      var type = '<%=formulaType.name()%>';
257      if (type == '<%=Formula.Type.INTENSITY_EXPRESSION.name()%>')
258      {
259        // Channel function not available
260        throw 'Function ch() is not available for ' + type;
261      }
262 
263      var channels = <%=channels%>;
264      if (!channel || channel <= 0 || channel > channels) throw 'Invalid channel: ' + channel + '; must be between 1 and '+ channels;
265      return channel;
266    }
267   
268    function rep(property)
269    {
270      if (!property) throw 'Property must be specified for function rep()';
271      if (!properties['reporter.'+property]) throw 'Property '+property+' not found for reporter';
272      return Math.random() * 100;
273    }
274   
275    function xtra(arg)
276    {
277      if (!arg) throw 'One argument is required for function xtra()';
278      return Math.random() * 100;
279    }
280   
281    function log(value)
282    {
283      return Math.log(value);
284    }
285    function log2(value)
286    {
287      return Math.log(value);
288    }
289    function ln(value)
290    {
291      return Math.log(value);
292    }
293    function sqrt(value)
294    {
295      return Math.sqrt(value);
296    }
297    function abs(value)
298    {
299      return Math.abs(value);
300    }
301    function exp(value)
302    {
303      return Math.exp(value);
304    }
305    function score(reporterListId)
306    {
307      return Math.random() * 100;
308    }
309    function jepIf(condition, ifTrue, ifFalse)
310    {
311      if (condition == undefined || ifTrue == undefined || ifFalse == undefined)
312      {
313        throw 'if() needs 3 arguments';
314      }
315      return condition ? ifTrue : ifFalse;
316    }
317    </script>
318  </base:head>
319  <base:body onload="getText()">
320 
321    <form name="expression" onsubmit="return false;">
322 
323        <h3 class="docked">Expression builder <base:help helpid="expressionbuilder" /></h3>
324       
325        <tbl:toolbar>
326          <tbl:label
327            style="width: 100px;"
328            title="Operators:"
329          />
330          <tbl:button 
331            title="AND"
332            tooltip="BOOLEAN AND: expr1 &amp;&amp; expr2"
333            onclick="encloseSelection(' &amp;&amp; ', '')"
334          />
335          <tbl:button 
336            title="OR"
337            tooltip="BOOLEAN OR: expr1 || expr2"
338            onclick="encloseSelection(' || ', '')"
339          />
340          <tbl:button 
341            title="NOT"
342            tooltip="BOOLEAN NOT: !expr1"
343            onclick="encloseSelection('!', '')"
344          />
345          <tbl:button 
346            title="=="
347            tooltip="EQUAL: expr1 == expr2"
348            onclick="encloseSelection(' == ', '')"
349          />
350          <tbl:button 
351            title="!="
352            tooltip="INEQUAL: expr1 != expr2"
353            onclick="encloseSelection(' != ', '')"
354          />
355          <tbl:button 
356            title="&lt;"
357            tooltip="LESS: expr1 &lt; expr2"
358            onclick="encloseSelection(' &lt; ', '')"
359          />
360          <tbl:button 
361            title="&lt;="
362            tooltip="LESS OR EQUAL: expr1 &lt;= expr2"
363            onclick="encloseSelection(' &lt;= ', '')"
364          />
365          <tbl:button 
366            title="&gt;="
367            tooltip="MORE OR EQUAL: expr1 &gt;= expr2"
368            onclick="encloseSelection(' &gt;= ', '')"
369            visible="<%=restrictions%>"
370          />
371          <tbl:button 
372            title="&gt;"
373            tooltip="MORE: expr1 &gt; expr2"
374            onclick="encloseSelection(' &gt; ', '')"
375          />
376          <tbl:button 
377            title="+"
378            tooltip="ADD: expr1 + expr2"
379            onclick="encloseSelection(' + ', '')"
380          />
381          <tbl:button 
382            title="-"
383            tooltip="SUBTRACT: expr1 - expr2"
384            onclick="encloseSelection(' - ', '')"
385          />
386          <tbl:button 
387            title="*"
388            tooltip="MULTIPLY: expr1 * expr2"
389            onclick="encloseSelection(' * ', '')"
390          />
391          <tbl:button 
392            title="/"
393            tooltip="DIVIDE: expr1 / expr2"
394            onclick="encloseSelection(' / ', '')"
395          />
396          <tbl:button 
397            title="( )"
398            tooltip="PARENTHESIS: (expr1)"
399            onclick="encloseSelection('(', ')')"
400          />
401        </tbl:toolbar>
402        <tbl:toolbar
403          style="border-top: 0px;"
404          >
405          <tbl:label
406            title="Functions:"
407            style="width: 100px;"
408          />
409          <%
410          Enumeration<String, String> functions = Jep.getFunctions();
411          for (int i = 0; i < functions.size(); ++i)
412          {
413            String function = functions.getKey(i);
414            %>
415            <tbl:button 
416              title="<%=function%>"
417              tooltip="<%=functions.getValue(i)%>"
418              onclick="<%="encloseSelection('" + function +"(', ')')"%>"
419            />
420            <%
421          }
422          %>
423          <tbl:label
424            title="Constants:"
425            style="width: 100px;"
426          />
427          <tbl:button 
428            title="null"
429            tooltip="The null (unknown) value"
430            onclick="<%="encloseSelection('', 'null')"%>"
431          />
432          <tbl:button 
433            title="pi"
434            tooltip="<%="The pi value: " + Math.PI %>"
435            onclick="<%="encloseSelection('', '"+Math.PI+"')"%>"
436          />
437          <tbl:button 
438            title="e"
439            tooltip="<%="The base of the natural logarithm: " + Math.E%>"
440            onclick="<%="encloseSelection('', '"+Math.E+"')"%>"
441          />
442        </tbl:toolbar>
443        <tbl:toolbar
444          style="border-top: 0px;">
445          <td class="label">Spot:
446            <select name="spot" onchange="insertSelected(this)" >
447            <option value="">- select -
448            <%
449            for (TableColumn tc : spotProperties)
450            {
451              if (tc.getJepExpression() != null)
452              {
453                %>
454                <option value="<%=tc.getJepExpression()%>" 
455                  title="<%=HTML.encodeTags(tc.getDescription())%>"><%=HTML.encodeTags(tc.getTitle())%>
456                <%
457              }
458            }
459            %>
460            </select>   
461          </td>
462          <%
463          if (rawDataType != null && rawDataType.isStoredInDb() && rawProperties.size() > 0)
464          {
465            %>
466            <td class="label">Raw data:
467              <select name="rawdata" onchange="insertSelected(this)" >
468              <option value="">- select -
469              <%
470              for (TableColumn tc : rawProperties)
471              {
472                %>
473                <option value="<%=tc.getJepExpression()%>" 
474                  title="<%=HTML.encodeTags(tc.getDescription())%>"><%=HTML.encodeTags(tc.getTitle())%>
475                <%
476              }
477              %>
478              </select>
479            </td>
480            <%
481          }
482          %>
483         
484          <td class="label">Reporter:
485            <select name="reporter" onchange="insertSelected(this)">
486            <option value="">- select -
487              <%
488              for (TableColumn tc : reporterProperties)
489              {
490                %>
491                <option value="<%=tc.getJepExpression()%>" 
492                  title="<%=HTML.encodeTags(tc.getDescription())%>"><%=HTML.encodeTags(tc.getTitle())%>
493                <%
494              }
495              %>
496            </select>
497        </tbl:toolbar>
498        <tbl:toolbar
499          style="border-top: 0px;"
500          visible="<%=reporterLists.size() > 0%>">
501          <td class="label">
502            Reporter lists:
503           
504            <select name="listFunction" >
505            <option value="score">score
506            <%
507            if (restrictions)
508            {
509              %>
510              <option value="inList">in
511              <option value="notInList">not in
512              <%
513            }
514            %>
515            </select>
516           
517            <select name="reporterList" onchange="insertReporterListFunction()">
518            <option value="">- select -
519              <%
520              for (ReporterList list : reporterLists)
521              {
522                %>
523                <option value="<%=list.getId()%>" 
524                  title="<%=HTML.encodeTags(list.getDescription())%>"><%=HTML.encodeTags(list.getName())%>
525                <%
526              }
527              %>
528            </select>
529          </td>
530        </tbl:toolbar>
531        <br>
532        <b>Expression</b><br>
533        <textarea name="expression" rows="16" cols="80" wrap="soft" style="width: 100%;"></textarea>
534
535        <br><br>
536        <table align="center">
537        <tr>
538          <td width="33%"><base:button 
539            onclick="validateOnClick()" title="Validate&hellip;" 
540            image="validate_formula.gif"
541            tooltip="Validate the expression. EXPERIMENTAL!!" /></td>
542          <td width="33%"><base:button onclick="setExpressionAndClose()" title="Ok" /></td>
543          <td width="33%"><base:button onclick="window.close()" title="Cancel" /></td>
544         
545        </tr>
546        </table>
547 
548    </form>
549  </base:body>
550  </base:page>
551  <%
552  }
553finally
554{
555  if (dc != null) dc.close();
556}
557%> 
Note: See TracBrowser for help on using the repository browser.