source: trunk/www/common/datafiles/select_files.jsp @ 5713

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

References #1604: Support for multiple files of the same type in a FileSet?

Added data and core layer classes. Started with the gui and seems to work when adding single files of a type. There are some remaining things to implement when used with multiple files. File validation is not yet fully functional. Some of the batch importers need to be fixed as well to be able to handle multiple files of the same type.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Id
File size: 16.9 KB
Line 
1<%-- $Id:select_files.jsp 3820 2007-10-12 10:03:18Z nicklas $
2  ------------------------------------------------------------------
3  Copyright (C) 2005 Nicklas Nordborg
4  Copyright (C) 2006 Jari Häkkinen, Nicklas Nordborg
5  Copyright (C) 2007 Nicklas Nordborg
6
7  This file is part of BASE - BioArray Software Environment.
8  Available at http://base.thep.lu.se/
9
10  BASE is free software; you can redistribute it and/or
11  modify it under the terms of the GNU General Public License
12  as published by the Free Software Foundation; either version 3
13  of the License, or (at your option) any later version.
14
15  BASE is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License
21  along with BASE. If not, see <http://www.gnu.org/licenses/>.
22  ------------------------------------------------------------------
23 
24--%>
25<%@ page pageEncoding="UTF-8" session="false"
26  import="net.sf.basedb.core.SessionControl"
27  import="net.sf.basedb.core.DbControl"
28  import="net.sf.basedb.core.Item"
29  import="net.sf.basedb.core.ItemContext"
30  import="net.sf.basedb.core.Type"
31  import="net.sf.basedb.core.BasicItem"
32  import="net.sf.basedb.core.Permission"
33  import="net.sf.basedb.core.Nameable"
34  import="net.sf.basedb.core.FileStoreEnabled"
35  import="net.sf.basedb.core.FileSet"
36  import="net.sf.basedb.core.FileSetMember"
37  import="net.sf.basedb.core.File"
38  import="net.sf.basedb.core.Platform"
39  import="net.sf.basedb.core.PlatformVariant"
40  import="net.sf.basedb.core.PlatformFileType"
41  import="net.sf.basedb.core.UsableDataFileType"
42  import="net.sf.basedb.core.DataFileType"
43  import="net.sf.basedb.core.Subtypable"
44  import="net.sf.basedb.core.ItemSubtype"
45  import="net.sf.basedb.core.ItemQuery"
46  import="net.sf.basedb.core.Include"
47  import="net.sf.basedb.core.ItemResultList"
48  import="net.sf.basedb.core.PermissionDeniedException"
49  import="net.sf.basedb.core.query.Expressions"
50  import="net.sf.basedb.core.query.Restrictions"
51  import="net.sf.basedb.core.query.Hql"
52  import="net.sf.basedb.core.query.Orders"
53  import="net.sf.basedb.clients.web.Base"
54  import="net.sf.basedb.clients.web.util.HTML"
55  import="net.sf.basedb.util.formatter.Formatter"
56  import="net.sf.basedb.clients.web.formatter.FormatterFactory"
57  import="net.sf.basedb.clients.web.formatter.FormatterSettings"
58  import="net.sf.basedb.util.Values"
59  import="java.util.ArrayList"
60  import="java.util.List"
61  import="java.util.Date"
62  import="java.util.Map"
63  import="java.util.HashMap"
64%>
65<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
66<%
67final SessionControl sc = Base.getExistingSessionControl(pageContext, true);
68final String ID = sc.getId();
69final float scale = Base.getScale(sc);
70final Item itemType = Item.valueOf(request.getParameter("item_type"));
71final int itemId = Values.getInt(request.getParameter("item_id"));
72final int platformId = Values.getInt(request.getParameter("platform_id"), -1);
73final int variantId = Values.getInt(request.getParameter("variant_id"), -1);
74final int itemSubtypeId = Values.getInt(request.getParameter("itemsubtype_id"), -1);
75final ItemContext cc = sc.getCurrentContext(itemType);
76
77final DbControl dc = sc.newDbControl();
78try
79{
80
81  // Get the current item; null if we are editing a new item
82  final FileStoreEnabled item = itemId == 0 ? null : (FileStoreEnabled)itemType.getById(dc, itemId);
83  FileSet fileSet = null;
84  // Get the current files organized per data file type
85  Map<DataFileType, List<FileSetMember>> members = new HashMap<DataFileType, List<FileSetMember>>();
86  if (item != null && item.hasFileSet())
87  {
88    fileSet = item.getFileSet();
89    ItemQuery<FileSetMember> query = fileSet.getMembers();
90    query.order(Orders.asc(Hql.property("dataFileType.name")));
91    query.order(Orders.asc(Hql.property("file.name")));
92    List<FileSetMember> all = query.list(dc);
93    for (FileSetMember m : all)
94    {
95      DataFileType dft = m.getDataFileType();
96      List<FileSetMember> tmp = members.get(dft);
97      if (tmp == null)
98      {
99        tmp = new ArrayList<FileSetMember>();
100        members.put(dft, tmp);
101      }
102      tmp.add(m);
103    }
104  }
105
106  // Get the current platform/variant/itemsubtype
107  // -- if not submitted in URL use values from current item
108  PlatformVariant variant = null;
109  Platform platform = null;
110  ItemSubtype itemSubtype = null;
111  boolean deniedPlatform = false;
112  try
113  {
114    if (itemSubtypeId > 0)
115    {
116      itemSubtype = ItemSubtype.getById(dc, itemSubtypeId);
117    }
118    else if (item instanceof Subtypable)
119    {
120      itemSubtype = ((Subtypable)item).getItemSubtype();
121    }
122    if (variantId > 0)
123    {
124      variant = PlatformVariant.getById(dc, variantId);
125      platform = variant.getPlatform();
126    }
127    else if (platformId > 0)
128    {
129      platform = Platform.getById(dc, platformId);
130    }
131    else if (item != null)
132    {
133      variant = item.getVariant();
134      platform = item.getPlatform();
135    }
136  }
137  catch (PermissionDeniedException ex)
138  {
139    deniedPlatform = true; 
140  }
141 
142  // Query to load data file types for specific itemType/platform/variant
143  final ItemQuery<DataFileType> fileTypeQuery = 
144    Base.getDataFileTypes(itemType, item, platform, variant, itemSubtype);
145  List<DataFileType> fileTypes = fileTypeQuery.list(dc);
146  String title = "Select data files for " + 
147    HTML.encodeTags((item instanceof Nameable ? ((Nameable)item).getName() : 
148      (item == null ? " new item" : item.toString())));
149
150  final String clazz = "class=\"text\"";
151  final String requiredClazz = "class=\"text required\"";
152  %>
153  <base:page type="popup" title="<%=title%>">
154  <base:head >
155 
156  <script language="JavaScript">
157  function init()
158  {
159    if (document.body.addEventListener)
160    {
161      // Mozilla
162      document.body.addEventListener('click', hideVisibleRecentFilesDiv, false);
163    }
164    else
165    {
166      // IE.
167      div.onclick = hideVisibleRecentFilesDiv;
168    }
169
170  }
171 
172  var lastFileTypeId;
173  var updateCheckboxes = false;
174  function addFilesOnClick(fileTypeId, extension, updateCheck)
175  {
176    var frm = document.forms['datafiles'];
177    updateCheckboxes = updateCheck;
178    var url = '../../filemanager/index.jsp?ID=<%=ID%>&cmd=SelectMultiple&callback=addFileCallback';
179    if (extension)
180    {
181      url += '&resetTemporary=1&tmpfilter:STRING:name='+escape('%.' + extension);
182    }
183    else
184    {
185      url += '&resetTemporary=1&filter:STRING:name=';
186    }
187    lastFileTypeId = fileTypeId;
188    Main.openPopup(url, 'SelectFile', 1000, 700);
189  }
190  function addFileCallback(fileId, path)
191  {
192    addFile(lastFileTypeId, fileId, path);
193  }
194  function removeFilesOnClick(inputName, updateCheck)
195  {
196  }
197 
198  function browseOnClick(fileTypeId, extension, updateCheck)
199  {
200    var frm = document.forms['datafiles'];
201    updateCheckboxes = updateCheck;
202    var url = '../../filemanager/index.jsp?ID=<%=ID%>&cmd=SelectOne&callback=setFileCallback';
203    if (extension)
204    {
205      url += '&resetTemporary=1&tmpfilter:STRING:name='+escape('%.' + extension);
206    }
207    else
208    {
209      url += '&resetTemporary=1&filter:STRING:name=';
210    }
211    lastFileTypeId = fileTypeId;
212    Main.openPopup(url, 'SelectFile', 1000, 700);
213  }
214  function setFileCallback(fileId, path)
215  {
216    setFile(lastFileTypeId, fileId, path);
217  }
218  function setFile(fileTypeId, fileId, path)
219  {
220    var frm = document.forms['datafiles'];
221    document.getElementById('filelist.'+fileTypeId+'.file').innerHTML = path;
222    new FileAction('setfile', fileTypeId, fileId);
223  }
224  function addFile(fileTypeId, fileId, path)
225  {
226    var fileDiv = document.getElementById('filelist.'+fileTypeId+'.'+fileId);
227    if (fileDiv) return;
228   
229    fileDiv = document.createElement('div');
230    fileDiv.id = 'filelist.'+fileTypeId+'.'+fileId;
231    fileDiv.innerHTML = path;
232    document.getElementById('filelist.'+fileTypeId+'.file').appendChild(fileDiv);
233    Main.hide('filelist.'+fileTypeId+'.0');
234    new FileAction('addfile', fileTypeId, fileId);
235  }
236  function removeOnClick(fileTypeId, updateCheck)
237  {
238    document.getElementById('filelist.'+fileTypeId+'.file').innerHTML = '<i>- not selected -</i>';
239    new FileAction('setfile', fileTypeId, 0);
240  }
241 
242  /*
243  function fileOnChange(inputName, updateCheckbox)
244  {
245    var frm = document.forms['datafiles'];
246    var validateCheckbox = frm['datafiles.validate'];
247
248    // Check boxes should be updated if the data file type
249    //supports validation or metadata-extraction
250    if (updateCheckbox)
251    {
252      if (frm[inputName].value != '' || frm[inputName].length > 0)
253      {
254        // Data filetype supports validation
255        if (validateCheckbox)
256        {
257          if (validateCheckbox.disabled) validateCheckbox.disabled = false; 
258          validateCheckbox.checked = "1";
259        }
260      }
261    }   
262  }
263  */
264 
265  function writeFileActions()
266  {
267    Main.debug(fileActions.length, true);
268    for (var i = 0; i < fileActions.length; i++)
269    {
270      var action = fileActions[i];
271      Main.debug(action.action + ':' + action.fileTypeId + '='+action.fileId);
272    }
273  }
274 
275  var fileActions = new Array();
276  function FileAction(action, fileTypeId, fileId)
277  {
278    this.action = action;
279    this.fileTypeId = fileTypeId;
280    this.fileId = fileId;
281   
282    if (action == 'setfile')
283    {
284      for (var i = 0; i < fileActions.length; i++)
285      {
286        var other = fileActions[i];
287        if (other.action == this.action && other.fileTypeId == this.fileTypeId)
288        {
289          fileActions[i] = this;
290          return;
291        }
292      }
293      fileActions[fileActions.length] = this;
294    }
295    else if (action == 'addfile')
296    {
297      for (var i = 0; i < fileActions.length; i++)
298      {
299        var other = fileActions[i];
300        if (other.action == this.action && other.fileTypeId == this.fileTypeId && other.fileId == this.fileId)
301        {
302          return;
303        }
304      }
305      fileActions[fileActions.length] = this;
306    }
307  }
308 
309  function writeFileActionsToForm(frm)
310  {
311    alert(fileActions.length);
312    for (var i = 0; i < fileActions.length; i++)
313    {
314      var action = fileActions[i];
315      Forms.createHidden(frm, action.action + '.' + action.fileTypeId, action.fileId);
316    }
317  }
318 
319  var visibleRecentFilesDiv = null;
320  function recentFilesOnClick(event, fileTypeId)
321  {
322    var recentDiv = document.getElementById('recentfiles.'+fileTypeId);
323    var currentDiv = visibleRecentFilesDiv;
324    hideVisibleRecentFilesDiv();
325    if (currentDiv == recentDiv) return;
326   
327    var fileCell = document.getElementById('filelist.'+fileTypeId+'.file');
328    var pos = Main.getElementPosition(fileCell, true);
329    Main.show('recentfiles.'+fileTypeId);
330   
331    recentDiv.style.top = (pos.bottom-2) + 'px';
332    recentDiv.style.left = (pos.left) + 'px';
333    recentDiv.style.width = (pos.width+18) + 'px';
334
335    visibleRecentFilesDiv = recentDiv;
336    event.cancelBubble = true;
337    event.stopPropagation();
338  }
339
340  function selectRecentFile(fileTypeId, fileId)
341  {
342    var path = document.getElementById('recentfile.'+fileTypeId+'.'+fileId).innerHTML;
343    setFile(fileTypeId, fileId, path);
344  }
345 
346  function hideVisibleRecentFilesDiv()
347  {
348    if (visibleRecentFilesDiv)
349    {
350      visibleRecentFilesDiv.style.display = 'none';
351      visibleRecentFilesDiv = null;
352    }
353  }
354  </script>
355  <style>
356  .filelist {
357    overflow: auto;
358    padding: 0px;
359    border: 1px solid #cccccc;
360    background: #FFFFFF;
361  }
362  .filelist td {
363    border-bottom: 1px dotted #cccccc;
364    padding: 1px 2px 1px 2px;
365  }
366  .filelist .filetype {
367    width: 150px;
368    font-weight: bold;
369    background-color: #f0f0f0;
370    border-right: 1px solid #cccccc;
371    white-space: nowrap;
372  }
373  .filelist .file {
374   
375  }
376  .filelist .required {
377    background: #D0F0FF !important;
378  }
379  .filelist .fileaction {
380    max-width: 18px;
381    width: 18px;
382    text-align: center;
383  }
384  .recentfiles {
385    position: absolute;
386    top: 0px;
387    left: 0px;
388    border: 1px solid #999999;
389    background: #ffffff;
390    text-align: left;
391  }
392  .recentfiles .recentfile {
393    padding: 2px;
394    border-bottom: 1px dotted #e0e0e0;
395  }
396  .recentfiles .recentfile:hover {
397    cursor: pointer;
398    background: #e0e0e0;
399    padding: 2px;
400  }
401  </style>
402  </base:head>
403 
404  <base:body onload="init()" style="background: #E0E0E0;">
405
406    <div id="filelist" class="filelist" style="height: <%=(int)(scale*320)%>px; width:100%">
407    <%
408    boolean hasNonPlatformFiles = true;     
409    boolean activateCheckBoxes = false;
410    boolean validationSupport = true;
411    if (fileTypes.size() == 0)
412    {
413      String what = "";
414      if (platform != null)
415      {
416        what = "'" + HTML.encodeTags(platform.getName()) + "' platform";
417      }
418      else if (itemSubtype != null)
419      {
420        what = "'" + HTML.encodeTags(itemSubtype.getName()) + "' subtype";
421      }
422      %>
423      <div class="error">
424        The <%=what%> doesn't define any file types for
425        <%=itemType.toString() %> items.
426      </div>
427      <%
428    }
429    else if (deniedPlatform)
430    {
431      %>
432      <div class="error">Denied</div>
433      <%
434    }
435    else
436    {
437      %>
438      <table border="0" cellspacing="0" cellpadding="0" width="100%">
439      <%
440      for (DataFileType dft : fileTypes)
441      {
442        String dftId = Integer.toString(dft.getId());
443        String fullLabel = dft.getName();
444        String label = Values.trimString(fullLabel, 25);
445       
446        UsableDataFileType usable = null;
447        if (platform != null) 
448        {
449          usable = platform.getFileType(dft, variant, false);
450          if (usable == null && variant != null)
451          {
452            // If file type is not registered with a variant, also check if it is inherited from platform
453            usable = platform.getFileType(dft, null, false);
454          }
455        }
456        else if (itemSubtype != null)
457        {
458          usable = itemSubtype.getAssociatedDataFileType(dft, false);
459        }
460       
461        boolean isPartOfPlatform = usable != null;
462        boolean isRequired = usable == null ? false : usable.isRequired();
463        boolean allowMultiple = usable == null ? false : usable.getAllowMultiple();
464        String extension = dft.getExtension();
465        boolean hasValidator = dft.hasActiveValidator(dc);
466        boolean affectCheckboxes = hasValidator;
467        validationSupport |= hasValidator;
468        List<FileSetMember> files = members.get(dft);
469        List<File> recentFiles = (List<File>)cc.getRecent(dc, Item.FILE, dft.getExternalId());
470        %>
471        <tr class="item <%=isRequired ? "required" : "" %>" 
472          id="filelist.<%=dftId%>" 
473          onclick="itemOnClick(<%=dftId%>)">
474          <td class="filetype" 
475            id="filelist.<%=dftId%>.label"
476            title="<%=fullLabel == label ? "" : HTML.encodeTags(fullLabel)%>"
477            ><%=HTML.encodeTags(label)%>
478            <%
479            if (!isPartOfPlatform && !deniedPlatform)
480            {
481              hasNonPlatformFiles = true;
482              %>
483              <base:icon image="warning.gif" tooltip="This file is not part of the platform/subtype" />
484              <%
485            }
486            %>
487          </td>
488          <td class="file" id="filelist.<%=dftId%>.file">
489            <%
490            if (files == null || files.size() == 0)
491            {
492              %>
493              <div id="filelist.<%=dftId%>.0">
494              <i>- not selected -</i>
495              </div>
496              <%
497            }
498            else
499            {
500              for (FileSetMember fm : files)
501              {
502                File file = fm.getFile();
503                %>
504                <div id="filelist.<%=dftId%>.<%=file.getId() %>">
505                <%=file.getPath() %>
506                </div>
507                <%
508              }
509              %>
510              <%
511            }
512            %>
513          </td>
514          <td class="fileaction">
515            <base:icon image="mini_scroll_down.png" 
516              visible="<%=recentFiles.size() >= 0 %>"
517              tooltip="Select a recently used file"
518              onclick="<%="recentFilesOnClick(event, " + dftId + ")"%>"
519            />
520              <div id="recentfiles.<%=dftId%>" style="display: none;" class="recentfiles">
521                <div class="recentfile"
522                  onclick="selectRecentFile(<%=dftId%>, 0)"
523                  id="recentfile.<%=dftId%>.0"
524                  ><i>- not selected -</i></div>
525                <%
526                for (File recent : recentFiles)
527                {
528                  %>
529                  <div class="recentfile"
530                    onclick="selectRecentFile(<%=dftId%>, <%=recent.getId()%>)"
531                    id="recentfile.<%=dftId%>.<%=recent.getId()%>"
532                    ><%=HTML.encodeTags(recent.getPath().toString())%></div>
533                  <%
534                }
535                %>
536              </div>
537          </td>
538          <td class="fileaction">
539            <base:icon image="add.png" 
540              onclick="<%="addFilesOnClick("+dftId+", '" + HTML.javaScriptEncode(extension) + "', "+ affectCheckboxes + ")"%>"
541              visible="<%=allowMultiple %>"
542            />
543            <base:icon image="browse.png" 
544              onclick="<%="browseOnClick("+dftId+", '" + HTML.javaScriptEncode(extension) + "', "+ affectCheckboxes + ")"%>"
545              visible="<%=!allowMultiple%>"
546            />
547          </td>
548          <!--
549          <td class="fileaction">
550            <base:icon image="remove.png"
551              id="remove"
552              onclick="<%="removeOnClick("+dftId+", "+ affectCheckboxes + ")"%>"
553              visible="<%=!allowMultiple %>"
554            />
555          </td>
556          -->
557        </tr>
558        <%
559      }
560      %>
561      </table>
562      <%
563    }
564    %>
565    </div>
566
567      <form name="datafiles">
568      <table width="100%">
569      <tr>
570        <td>
571          <%
572          if (validationSupport)
573          {
574            %>
575            <b>Validate</b>
576            <input type="checkbox" value="1" disabled name="datafiles.validate">
577            <%
578          }
579          %>
580        </td>
581        <td>
582          <%
583          if (hasNonPlatformFiles)
584          {
585            if (platform != null)
586            {
587              %>
588              <div align="right">
589              <base:icon image="warning.gif" /> 
590              = The file type is not part of the <i><%=HTML.encodeTags(platform.getName())%></i> platform
591              </div>
592              <%
593            }
594            else if (itemSubtype != null)
595            {
596              %>
597              <div align="right">
598              <base:icon image="warning.gif" /> 
599              = The file type is not part of the <i><%=HTML.encodeTags(itemSubtype.getName())%></i> subtype
600              </div>
601              <%
602            }
603          }
604          %>
605        </td>
606      </table>
607    </form>
608    <a href="javascript:writeFileActions()">See</a>
609  </base:body>
610  </base:page>
611  <%
612}
613finally
614{
615  if (dc != null) dc.close();
616}
617%>
Note: See TracBrowser for help on using the repository browser.