Clover icon

Coverage Report

  1. Project Clover database Wed Nov 5 2025 13:15:40 GMT
  2. Package jalview.io

File FileLoader.java

 

Coverage histogram

../../img/srcFileCovDistChart7.png
30% of files have more coverage

Code metrics

92
187
21
1
711
505
83
0.44
8.9
21
3.95

Classes

Class Line # Actions
FileLoader 52 187 83
0.676666767.7%
 

Contributing tests

This file is covered by 164 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.io;
22   
23    import java.io.File;
24    import java.io.IOException;
25    import java.util.StringTokenizer;
26    import java.util.Vector;
27   
28    import javax.swing.SwingUtilities;
29   
30    import jalview.api.ComplexAlignFile;
31    import jalview.api.FeatureSettingsModelI;
32    import jalview.api.FeaturesDisplayedI;
33    import jalview.api.FeaturesSourceI;
34    import jalview.bin.Cache;
35    import jalview.bin.Jalview;
36    import jalview.datamodel.AlignmentI;
37    import jalview.datamodel.HiddenColumns;
38    import jalview.datamodel.PDBEntry;
39    import jalview.datamodel.SequenceI;
40    import jalview.gui.AlignFrame;
41    import jalview.gui.AlignViewport;
42    import jalview.gui.Desktop;
43    import jalview.gui.JvOptionPane;
44    import jalview.gui.QuitHandler;
45    import jalview.json.binding.biojson.v1.ColourSchemeMapper;
46    import jalview.project.Jalview2XML;
47    import jalview.schemes.ColourSchemeI;
48    import jalview.structure.StructureSelectionManager;
49    import jalview.util.MessageManager;
50    import jalview.ws.utils.UrlDownloadClient;
51   
 
52    public class FileLoader implements Runnable
53    {
54    String file;
55   
56    DataSourceType protocol;
57   
58    FileFormatI format;
59   
60    AlignmentFileReaderI source = null; // alternative specification of where data
61    // comes
62   
63    // from
64   
65    AlignViewport viewport;
66   
67    AlignFrame alignFrame;
68   
69    long loadtime;
70   
71    long memused;
72   
73    boolean raiseGUI = true;
74   
75    private File selectedFile;
76   
77    private static boolean useDefaultFileFormat = false;
78   
79    /**
80    * default constructor always raised errors in GUI dialog boxes
81    */
 
82  128 toggle public FileLoader()
83    {
84  128 this(true);
85    }
86   
87    /**
88    * construct a Fileloader that may raise errors non-interactively
89    *
90    * @param raiseGUI
91    * true if errors are to be raised as GUI dialog boxes
92    */
 
93  457 toggle public FileLoader(boolean raiseGUI)
94    {
95  457 this.raiseGUI = raiseGUI;
96    }
97   
 
98  1 toggle public void LoadFile(AlignViewport viewport, Object file,
99    DataSourceType protocol, FileFormatI format)
100    {
101  1 LoadFile(viewport, file, protocol, format, true);
102    }
103   
 
104  21 toggle public void LoadFile(AlignViewport viewport, Object file,
105    DataSourceType protocol, FileFormatI format, boolean async)
106    {
107  21 this.viewport = viewport;
108  21 if (file instanceof File)
109    {
110  0 this.selectedFile = (File) file;
111  0 file = selectedFile.getPath();
112    }
113  21 LoadFile(file.toString(), protocol, format, async);
114    }
115   
 
116  0 toggle public void LoadFile(String file, DataSourceType protocol,
117    FileFormatI format)
118    {
119  0 LoadFile(file, protocol, format, true);
120    }
121   
 
122  21 toggle public void LoadFile(String file, DataSourceType protocol,
123    FileFormatI format, boolean async)
124    {
125  21 this.file = file;
126  21 this.protocol = protocol;
127  21 this.format = format;
128   
129  21 if (async)
130    {
131  1 final Thread loader = new Thread(this);
132   
133  1 SwingUtilities.invokeLater(new Runnable()
134    {
 
135  1 toggle @Override
136    public void run()
137    {
138  1 loader.start();
139    }
140    });
141    }
142    else
143    {
144  20 this.run();
145    }
146    }
147   
148    /**
149    * Load a (file, protocol) source of unknown type
150    *
151    * @param file
152    * @param protocol
153    */
 
154  0 toggle public void LoadFile(String file, DataSourceType protocol)
155    {
156  0 LoadFile(file, protocol, null);
157    }
158   
159    /**
160    * Load alignment from (file, protocol) and wait till loaded
161    *
162    * @param file
163    * @param sourceType
164    * @return alignFrame constructed from file contents
165    */
 
166  148 toggle public AlignFrame LoadFileWaitTillLoaded(String file,
167    DataSourceType sourceType)
168    {
169  148 return LoadFileWaitTillLoaded(file, sourceType, null);
170    }
171   
172    /**
173    * Load alignment from (file, protocol) of type format and wait till loaded
174    *
175    * @param file
176    * @param sourceType
177    * @param format
178    * @return alignFrame constructed from file contents
179    */
 
180  336 toggle public AlignFrame LoadFileWaitTillLoaded(String file,
181    DataSourceType sourceType, FileFormatI format)
182    {
183  336 this.file = file;
184  336 this.protocol = sourceType;
185  336 this.format = format;
186  336 return _LoadFileWaitTillLoaded();
187    }
188   
189    /**
190    * Load alignment from (file, protocol) of type format and wait till loaded
191    *
192    * @param file
193    * @param sourceType
194    * @param format
195    * @return alignFrame constructed from file contents
196    */
 
197  6 toggle public AlignFrame LoadFileWaitTillLoaded(File file,
198    DataSourceType sourceType, FileFormatI format)
199    {
200  6 this.selectedFile = file;
201  6 this.file = file.getPath();
202  6 this.protocol = sourceType;
203  6 this.format = format;
204  6 return _LoadFileWaitTillLoaded();
205    }
206   
207    /**
208    * Load alignment from FileParse source of type format and wait till loaded
209    *
210    * @param source
211    * @param format
212    * @return alignFrame constructed from file contents
213    */
 
214  0 toggle public AlignFrame LoadFileWaitTillLoaded(AlignmentFileReaderI source,
215    FileFormatI format)
216    {
217  0 this.source = source;
218   
219  0 file = source.getInFile();
220  0 protocol = source.getDataSourceType();
221  0 this.format = format;
222  0 return _LoadFileWaitTillLoaded();
223    }
224   
225    /**
226    * runs the 'run' method (in this thread), then return the alignFrame that's
227    * (hopefully) been read
228    *
229    * @return
230    */
 
231  342 toggle protected AlignFrame _LoadFileWaitTillLoaded()
232    {
233  342 this.run();
234   
235  338 return alignFrame;
236    }
237   
 
238  338 toggle public void updateRecentlyOpened()
239    {
240  338 Vector<String> recent = new Vector<>();
241  338 if (protocol == DataSourceType.PASTE)
242    {
243    // do nothing if the file was pasted in as text... there is no filename to
244    // refer to it as.
245  50 return;
246    }
247  288 if (file != null
248    && file.indexOf(System.getProperty("java.io.tmpdir")) > -1)
249    {
250    // ignore files loaded from the system's temporary directory
251  21 return;
252    }
253  267 String type = protocol == DataSourceType.FILE ? "RECENT_FILE"
254    : "RECENT_URL";
255   
256  267 String historyItems = Cache.getProperty(type);
257   
258  267 StringTokenizer st;
259   
260  267 if (historyItems != null)
261    {
262  252 st = new StringTokenizer(historyItems, "\t");
263   
264  1979 while (st.hasMoreTokens())
265    {
266  1727 recent.addElement(st.nextToken().trim());
267    }
268    }
269   
270  267 if (recent.contains(file))
271    {
272  173 recent.remove(file);
273    }
274   
275  267 StringBuffer newHistory = new StringBuffer(file);
276  1796 for (int i = 0; i < recent.size() && i < 10; i++)
277    {
278  1529 newHistory.append("\t");
279  1529 newHistory.append(recent.elementAt(i));
280    }
281   
282  267 Cache.setProperty(type, newHistory.toString());
283   
284  267 if (protocol == DataSourceType.FILE)
285    {
286  264 Cache.setProperty("DEFAULT_FILE_FORMAT", format.getName());
287    }
288    }
289   
 
290  363 toggle @Override
291    public void run()
292    {
293  363 String title = protocol == DataSourceType.PASTE
294    ? "Copied From Clipboard"
295    : file;
296  363 Runtime rt = Runtime.getRuntime();
297   
298  363 try
299    {
300  363 if (Desktop.instance != null)
301    {
302  312 Desktop.instance.startLoading(file);
303    }
304  363 if (format == null)
305    {
306    // just in case the caller didn't identify the file for us
307  168 if (source != null)
308    {
309  0 format = new IdentifyFile().identify(source, false);
310    // identify stream and rewind rather than close
311    }
312  168 else if (selectedFile != null)
313    {
314  0 format = new IdentifyFile().identify(selectedFile, protocol);
315    }
316    else
317    {
318  168 format = new IdentifyFile().identify(file, protocol);
319    }
320   
321    }
322   
323  363 if (format == null)
324    {
325  0 Desktop.instance.stopLoading();
326  0 jalview.bin.Console.errPrintln("The input file \"" + file
327    + "\" has null or unidentifiable data content!");
328  0 if (!Jalview.isHeadlessMode() && !Jalview.isBatchMode())
329    {
330  0 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
331    MessageManager.getString("label.couldnt_read_data")
332    + " in " + file + "\n"
333    + AppletFormatAdapter.getSupportedFormats(),
334    MessageManager.getString("label.couldnt_read_data"),
335    JvOptionPane.WARNING_MESSAGE);
336    }
337    // don't set shouldBeSaved if didn't load anything
338    // this.setShouldBeSaved();
339  0 return;
340    }
341    // TODO: cache any stream datasources as a temporary file (eg. PDBs
342    // retrieved via URL)
343  363 if (Desktop.desktop != null && Desktop.desktop.isShowMemoryUsage())
344    {
345  0 System.gc();
346  0 memused = (rt.maxMemory() - rt.totalMemory() + rt.freeMemory()); // free
347    // memory
348    // before
349    // load
350    }
351  363 loadtime = -System.currentTimeMillis();
352  363 AlignmentI al = null;
353   
354  363 if (FileFormat.Jalview.equals(format))
355    {
356  34 if (source != null)
357    {
358    // Tell the user (developer?) that this is going to cause a problem
359  0 jalview.bin.Console.errPrintln(
360    "IMPLEMENTATION ERROR: Cannot read consecutive Jalview XML projects from a stream.");
361    // We read the data anyway - it might make sense.
362    }
363    // BH 2018 switch to File object here instead of filename
364  34 alignFrame = new Jalview2XML(raiseGUI && !Jalview.isBatchMode())
365    .loadJalviewAlign(
366  34 selectedFile == null ? file : selectedFile);
367    }
368    else
369    {
370  329 String error = AppletFormatAdapter.getSupportedFormats();
371  329 try
372    {
373  329 if (source != null)
374    {
375    // read from the provided source
376  0 al = new FormatAdapter().readFromFile(source, format);
377    }
378    else
379    {
380   
381    // open a new source and read from it
382  329 FormatAdapter fa = new FormatAdapter();
383  329 boolean downloadStructureFile = format.isStructureFile()
384    && protocol.equals(DataSourceType.URL);
385  329 if (downloadStructureFile)
386    {
387   
388    // TODO JAL-2690 this breaks retrieving URLs for .cif files
389   
390  0 String structExt = format.getExtensions().split(",")[0];
391  0 String urlLeafName = file.substring(
392    file.lastIndexOf(
393    System.getProperty("file.separator")),
394    file.lastIndexOf("."));
395  0 String tempStructureFileStr = createNamedJvTempFile(
396    urlLeafName, structExt);
397   
398    // BH - switching to File object here so as to hold
399    // ._bytes array directly
400  0 File tempFile = new File(tempStructureFileStr);
401  0 UrlDownloadClient.download(file, tempFile);
402   
403  0 al = fa.readFile(tempFile, DataSourceType.FILE, format);
404  0 source = fa.getAlignFile();
405    }
406    else
407    {
408  329 if (selectedFile == null)
409    {
410  323 al = fa.readFile(null, file, protocol, format);
411   
412    }
413    else
414    {
415  6 al = fa.readFile(selectedFile, null, protocol, format);
416    }
417  329 source = fa.getAlignFile(); // keep reference for later if
418   
419    // necessary.
420    }
421    }
422    } catch (java.io.IOException ex)
423    {
424  0 error = ex.getMessage();
425    }
426   
427  329 if ((al != null) && (al.getHeight() > 0) && al.hasValidSequence())
428    {
429    // construct and register dataset sequences
430  329 for (SequenceI sq : al.getSequences())
431    {
432  2725 while (sq.getDatasetSequence() != null)
433    {
434  2 sq = sq.getDatasetSequence();
435    }
436  2723 if (sq.getAllPDBEntries() != null)
437    {
438  2723 for (PDBEntry pdbe : sq.getAllPDBEntries())
439    {
440    // register PDB entries with desktop's structure selection
441    // manager
442  50 StructureSelectionManager
443    .getStructureSelectionManager(Desktop.instance)
444    .registerPDBEntry(pdbe);
445    }
446    }
447    }
448   
449  329 FeatureSettingsModelI proxyColourScheme = source
450    .getFeatureColourScheme();
451  329 if (viewport != null)
452    {
453    // append to existing alignment
454  21 viewport.addAlignment(al, title);
455  21 viewport.applyFeaturesStyle(proxyColourScheme);
456    }
457    else
458    {
459    // otherwise construct the alignFrame
460   
461  308 if (source instanceof ComplexAlignFile)
462    {
463  0 HiddenColumns colSel = ((ComplexAlignFile) source)
464    .getHiddenColumns();
465  0 SequenceI[] hiddenSeqs = ((ComplexAlignFile) source)
466    .getHiddenSequences();
467  0 String colourSchemeName = ((ComplexAlignFile) source)
468    .getGlobalColourScheme();
469  0 FeaturesDisplayedI fd = ((ComplexAlignFile) source)
470    .getDisplayedFeatures();
471  0 alignFrame = new AlignFrame(al, hiddenSeqs, colSel,
472    AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
473  0 alignFrame.getViewport().setFeaturesDisplayed(fd);
474  0 alignFrame.getViewport().setShowSequenceFeatures(
475    ((ComplexAlignFile) source).isShowSeqFeatures());
476  0 ColourSchemeI cs = ColourSchemeMapper
477    .getJalviewColourScheme(colourSchemeName, al);
478  0 if (cs != null)
479    {
480  0 alignFrame.changeColour(cs);
481    }
482    }
483    else
484    {
485  308 alignFrame = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH,
486    AlignFrame.DEFAULT_HEIGHT);
487  304 if (source instanceof FeaturesSourceI)
488    {
489  1 alignFrame.getViewport().setShowSequenceFeatures(true);
490    }
491    }
492    // add metadata and update ui
493  304 if (!(protocol == DataSourceType.PASTE))
494    {
495  254 alignFrame.setFileName(file, format);
496  254 alignFrame.setFileObject(selectedFile); // BH 2018 SwingJS
497    }
498  304 if (proxyColourScheme != null)
499    {
500  14 alignFrame.getViewport()
501    .applyFeaturesStyle(proxyColourScheme);
502    }
503  304 alignFrame.setStatus(MessageManager.formatMessage(
504    "label.successfully_loaded_file", new String[]
505    { title }));
506   
507  304 if (raiseGUI)
508    {
509    // add the window to the GUI
510    // note - this actually should happen regardless of raiseGUI
511    // status in Jalview 3
512    // TODO: define 'virtual desktop' for benefit of headless scripts
513    // that perform queries to find the 'current working alignment'
514  231 Desktop.addInternalFrame(alignFrame, title,
515    AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
516   
517    /*
518    * for an Overview automatically opened with alignment,
519    * set its title now alignFrame title has been set
520    */
521  231 alignFrame.alignPanel.setOverviewTitle(alignFrame);
522    }
523   
524  304 try
525    {
526  304 alignFrame.setMaximum(
527    Cache.getDefault("SHOW_FULLSCREEN", false));
528    } catch (java.beans.PropertyVetoException ex)
529    {
530    }
531    }
532  325 alignFrame.alignPanel.alignmentChanged();
533    }
534    else
535    {
536  0 if (Desktop.instance != null)
537    {
538  0 Desktop.instance.stopLoading();
539    }
540   
541  0 final String errorMessage = MessageManager.getString(
542    "label.couldnt_load_file") + " " + title + "\n" + error;
543    // TODO: refactor FileLoader to be independent of Desktop / Applet GUI
544    // bits ?
545  0 if (raiseGUI && !Jalview.isBatchMode() && Desktop.desktop != null)
546    {
547  0 javax.swing.SwingUtilities.invokeLater(new Runnable()
548    {
 
549  0 toggle @Override
550    public void run()
551    {
552  0 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
553    errorMessage,
554    MessageManager
555    .getString("label.error_loading_file"),
556    JvOptionPane.WARNING_MESSAGE);
557    }
558    });
559    }
560    else
561    {
562  0 jalview.bin.Console.errPrintln(errorMessage);
563    }
564    }
565    }
566   
567  338 updateRecentlyOpened();
568   
569    } catch (Exception er)
570    {
571  21 jalview.bin.Console
572    .errPrintln("Exception whilst opening file '" + file);
573  21 er.printStackTrace();
574  21 if (raiseGUI && !Jalview.isBatchMode())
575    {
576  1 javax.swing.SwingUtilities.invokeLater(new Runnable()
577    {
 
578  1 toggle @Override
579    public void run()
580    {
581  1 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
582    MessageManager.formatMessage(
583    "label.problems_opening_file", new String[]
584    { file }),
585    MessageManager.getString("label.file_open_error"),
586    JvOptionPane.WARNING_MESSAGE);
587    }
588    });
589    }
590  21 alignFrame = null;
591    } catch (OutOfMemoryError er)
592    {
593   
594  0 er.printStackTrace();
595  0 alignFrame = null;
596  0 if (raiseGUI && !Jalview.isBatchMode())
597    {
598  0 javax.swing.SwingUtilities.invokeLater(new Runnable()
599    {
 
600  0 toggle @Override
601    public void run()
602    {
603  0 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
604    MessageManager.formatMessage(
605    "warn.out_of_memory_loading_file", new String[]
606    { file }),
607    MessageManager.getString("label.out_of_memory"),
608    JvOptionPane.WARNING_MESSAGE);
609    }
610    });
611    }
612  0 jalview.bin.Console
613    .errPrintln("Out of memory loading file " + file + "!!");
614   
615    }
616  359 loadtime += System.currentTimeMillis();
617    // TODO: Estimate percentage of memory used by a newly loaded alignment -
618    // warn if more memory will be needed to work with it
619    // System.gc();
620  359 memused = memused
621    - (rt.maxMemory() - rt.totalMemory() + rt.freeMemory()); // difference
622    // in free
623    // memory
624    // after
625    // load
626  359 if (Desktop.desktop != null && Desktop.desktop.isShowMemoryUsage())
627    {
628  0 if (alignFrame != null)
629    {
630  0 AlignmentI al = alignFrame.getViewport().getAlignment();
631   
632  0 jalview.bin.Console.outPrintln("Loaded '" + title + "' in "
633    + (loadtime / 1000.0) + "s, took an additional "
634    + (1.0 * memused / (1024.0 * 1024.0)) + " MB ("
635    + al.getHeight() + " seqs by " + al.getWidth() + " cols)");
636    }
637    else
638    {
639    // report that we didn't load anything probably due to an out of memory
640    // error
641  0 jalview.bin.Console.outPrintln("Failed to load '" + title + "' in "
642    + (loadtime / 1000.0) + "s, took an additional "
643    + (1.0 * memused / (1024.0 * 1024.0))
644    + " MB (alignment is null)");
645    }
646    }
647    // remove the visual delay indicator
648  359 if (Desktop.instance != null)
649    {
650  308 Desktop.instance.stopLoading();
651    }
652   
653  359 this.setShouldBeSaved();
654    // after first file loaded we revert to assuming a default file format
655  359 useDefaultFileFormat = true;
656    }
657   
658    /**
659    * This method creates the file -
660    * {tmpdir}/jalview/{current_timestamp}/fileName.exetnsion using the supplied
661    * file name and extension
662    *
663    * @param fileName
664    * the name of the temp file to be created
665    * @param extension
666    * the extension of the temp file to be created
667    * @return
668    */
 
669  0 toggle private static String createNamedJvTempFile(String fileName,
670    String extension) throws IOException
671    {
672  0 String seprator = System.getProperty("file.separator");
673  0 String jvTempDir = System.getProperty("java.io.tmpdir") + "jalview"
674    + seprator + System.currentTimeMillis();
675  0 File tempStructFile = new File(
676    jvTempDir + seprator + fileName + "." + extension);
677  0 tempStructFile.mkdirs();
678  0 return tempStructFile.toString();
679    }
680   
681    /*
682    * set whether quit should ask to save when just loaded this source
683    */
 
684  359 toggle private void setShouldBeSaved()
685    {
686  359 if (protocol == null)
687  0 return;
688  359 AlignFrame af = this.alignFrame;
689  359 if (af == null)
690  21 return;
691  338 AlignViewport avp = af.getViewport();
692  338 if (avp == null)
693  0 return;
694  338 boolean upToDate = !protocol.isDynamic();
695  338 if (protocol.isUrl() && !Cache
696    .getDefault(PROMPT_SAVE_UNCHANGED_URL_ALIGNMENTS, true))
697    {
698  0 upToDate = true;
699    }
700  338 avp.setSavedUpToDate(upToDate,
701  338 upToDate ? null : QuitHandler.Message.UNSAVED_ALIGNMENTS);
702    }
703   
704    public static final String PROMPT_SAVE_UNCHANGED_URL_ALIGNMENTS = "PROMPT_SAVE_UNCHANGED_URL_ALIGNMENTS";
705   
 
706  88 toggle public static boolean getUseDefaultFileFormat()
707    {
708  88 return useDefaultFileFormat;
709    }
710   
711    }