applied copyright 2008
[jalview.git] / src / jalview / io / FileLoader.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3  * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.io;
20
21 import java.util.*;
22
23 import javax.swing.*;
24
25 import jalview.datamodel.*;
26 import jalview.gui.*;
27
28 public class FileLoader implements Runnable
29 {
30   String file;
31
32   String protocol;
33
34   String format;
35
36   FileParse source = null; // alternative specification of where data comes
37
38   // from
39
40   AlignViewport viewport;
41
42   AlignFrame alignFrame;
43
44   long loadtime;
45
46   long memused;
47
48   boolean raiseGUI = true;
49   /**
50    * default constructor always raised errors in GUI dialog boxes 
51    */
52   public FileLoader() {
53     this(true);
54   }
55   /**
56    * construct a Fileloader that may raise errors non-interactively 
57    * @param raiseGUI true if errors are to be raised as GUI dialog boxes
58    */
59   public FileLoader(boolean raiseGUI)
60   {
61     this.raiseGUI = raiseGUI;
62   }
63
64   public void LoadFile(AlignViewport viewport, String file,
65           String protocol, String format)
66   {
67     this.viewport = viewport;
68     LoadFile(file, protocol, format);
69   }
70
71   public void LoadFile(String file, String protocol, String format)
72   {
73     this.file = file;
74     this.protocol = protocol;
75     this.format = format;
76
77     final Thread loader = new Thread(this);
78
79     SwingUtilities.invokeLater(new Runnable()
80     {
81       public void run()
82       {
83         loader.start();
84       }
85     });
86   }
87
88   /**
89    * Load a (file, protocol) source of unknown type
90    * 
91    * @param file
92    * @param protocol
93    */
94   public void LoadFile(String file, String protocol)
95   {
96     LoadFile(file, protocol, null);
97   }
98
99   /**
100    * Load alignment from (file, protocol) and wait till loaded
101    * 
102    * @param file
103    * @param protocol
104    * @return alignFrame constructed from file contents
105    */
106   public AlignFrame LoadFileWaitTillLoaded(String file, String protocol)
107   {
108     return LoadFileWaitTillLoaded(file, protocol, null);
109   }
110
111   /**
112    * Load alignment from (file, protocol) of type format and wait till loaded
113    * 
114    * @param file
115    * @param protocol
116    * @param format
117    * @return alignFrame constructed from file contents
118    */
119   public AlignFrame LoadFileWaitTillLoaded(String file, String protocol,
120           String format)
121   {
122     this.file = file;
123     this.protocol = protocol;
124     this.format = format;
125     return _LoadFileWaitTillLoaded();
126   }
127
128   /**
129    * Load alignment from FileParse source of type format and wait till loaded
130    * 
131    * @param source
132    * @param format
133    * @return alignFrame constructed from file contents
134    */
135   public AlignFrame LoadFileWaitTillLoaded(FileParse source, String format)
136   {
137     this.source = source;
138     file = source.getInFile();
139     protocol = source.type;
140     this.format = format;
141     return _LoadFileWaitTillLoaded();
142   }
143
144   /**
145    * start thread and wait until finished, then return the alignFrame that's
146    * (hopefully) been read.
147    * 
148    * @return
149    */
150   protected AlignFrame _LoadFileWaitTillLoaded()
151   {
152     Thread loader = new Thread(this);
153     loader.start();
154
155     while (loader.isAlive())
156     {
157       try
158       {
159         Thread.sleep(500);
160       } catch (Exception ex)
161       {
162       }
163     }
164
165     return alignFrame;
166   }
167
168   public void updateRecentlyOpened()
169   {
170     Vector recent = new Vector();
171
172     String type = protocol.equals(FormatAdapter.FILE) ? "RECENT_FILE"
173             : "RECENT_URL";
174
175     String historyItems = jalview.bin.Cache.getProperty(type);
176
177     StringTokenizer st;
178
179     if (historyItems != null)
180     {
181       st = new StringTokenizer(historyItems, "\t");
182
183       while (st.hasMoreTokens())
184       {
185         recent.addElement(st.nextElement().toString().trim());
186       }
187     }
188
189     if (recent.contains(file))
190     {
191       recent.remove(file);
192     }
193
194     StringBuffer newHistory = new StringBuffer(file);
195     for (int i = 0; i < recent.size() && i < 10; i++)
196     {
197       newHistory.append("\t");
198       newHistory.append(recent.elementAt(i));
199     }
200
201     jalview.bin.Cache.setProperty(type, newHistory.toString());
202
203     if (protocol.equals(FormatAdapter.FILE))
204     {
205       jalview.bin.Cache.setProperty("DEFAULT_FILE_FORMAT", format);
206     }
207   }
208
209   public void run()
210   {
211     String title = protocol.equals(AppletFormatAdapter.PASTE) ? "Copied From Clipboard"
212             : file;
213     Runtime rt = Runtime.getRuntime();
214     try
215     {
216       if (Desktop.instance != null)
217       {
218         Desktop.instance.startLoading(file);
219       }
220       if (format == null)
221       {
222         // just in case the caller didn't identify the file for us
223         if (source != null)
224         {
225           format = new IdentifyFile().Identify(source, false); // identify
226           // stream and
227           // rewind rather
228           // than close
229         }
230         else
231         {
232           format = new IdentifyFile().Identify(file, protocol);
233         }
234       }
235       if (Desktop.desktop != null && Desktop.desktop.isShowMemoryUsage())
236       {
237         System.gc();
238         memused = (rt.maxMemory() - rt.totalMemory() + rt.freeMemory()); // free memory before load
239       }
240       loadtime = -System.currentTimeMillis();
241       Alignment al = null;
242
243       if (format.equalsIgnoreCase("Jalview"))
244       {
245         if (source != null)
246         {
247           // Tell the user (developer?) that this is going to cause a problem
248           System.err
249                   .println("IMPLEMENTATION ERROR: Cannot read consecutive Jalview XML projects from a stream.");
250           // We read the data anyway - it might make sense.
251         }
252         alignFrame = new Jalview2XML(raiseGUI).LoadJalviewAlign(file);
253       }
254       else
255       {
256         String error = AppletFormatAdapter.SUPPORTED_FORMATS;
257         if (FormatAdapter.isValidFormat(format))
258         {
259           try
260           {
261             if (source != null)
262             {
263               // read from the provided source
264               al = new FormatAdapter().readFromFile(source, format);
265             }
266             else
267             {
268
269               // open a new source and read from it
270               FormatAdapter fa = new FormatAdapter();
271               al = fa.readFile(file, protocol, format);
272               source = fa.afile; // keep reference for later if necessary.
273             }
274           } catch (java.io.IOException ex)
275           {
276             error = ex.getMessage();
277           }
278         }
279         else
280         {
281           if (format != null && format.length() > 7)
282           {
283             // ad hoc message in format.
284             error = format + "\n" + error;
285           }
286         }
287
288         if ((al != null) && (al.getHeight() > 0))
289         {
290           if (viewport != null)
291           {
292             for (int i = 0; i < al.getHeight(); i++)
293             {
294               viewport.getAlignment().addSequence(al.getSequenceAt(i));
295             }
296             viewport.firePropertyChange("alignment", null, viewport
297                     .getAlignment().getSequences());
298
299           }
300           else
301           {
302             alignFrame = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH,
303                     AlignFrame.DEFAULT_HEIGHT);
304
305             alignFrame.statusBar.setText("Successfully loaded file "
306                     + title);
307
308             if (!protocol.equals(AppletFormatAdapter.PASTE))
309               alignFrame.setFileName(file, format);
310
311             Desktop.addInternalFrame(alignFrame, title,
312                     AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
313
314             try
315             {
316               alignFrame.setMaximum(jalview.bin.Cache.getDefault(
317                       "SHOW_FULLSCREEN", false));
318             } catch (java.beans.PropertyVetoException ex)
319             {
320             }
321           }
322         }
323         else
324         {
325           if (Desktop.instance != null)
326           {
327             Desktop.instance.stopLoading();
328           }
329
330           final String errorMessage = "Couldn't load file " + title + "\n"
331                   + error;
332           if (raiseGUI)
333           {
334             javax.swing.SwingUtilities.invokeLater(new Runnable()
335             {
336               public void run()
337               {
338                 JOptionPane.showInternalMessageDialog(Desktop.desktop,
339                         errorMessage, "Error loading file",
340                         JOptionPane.WARNING_MESSAGE);
341               }
342             });
343           }
344           else
345           {
346             System.err.println(errorMessage);
347           }
348         }
349       }
350
351       updateRecentlyOpened();
352
353     }
354     catch (Exception er)
355     {
356       System.err.println("Exception whilst opening file '"+file);
357       er.printStackTrace();
358       if (raiseGUI)
359       {
360         javax.swing.SwingUtilities.invokeLater(new Runnable()
361         {
362           public void run()
363           {
364             javax.swing.JOptionPane
365                     .showInternalMessageDialog(
366                             Desktop.desktop,
367                             "Encountered problems opening "
368                                     + file
369                                     + "!!"
370                                     , "File open error",
371                             javax.swing.JOptionPane.WARNING_MESSAGE);
372           }
373         });
374       }
375       alignFrame = null;
376     }
377     catch (OutOfMemoryError er)
378     {
379
380       er.printStackTrace();
381       alignFrame = null;
382       if (raiseGUI)
383       {
384         javax.swing.SwingUtilities.invokeLater(new Runnable()
385         {
386           public void run()
387           {
388             javax.swing.JOptionPane
389                     .showInternalMessageDialog(
390                             Desktop.desktop,
391                             "Out of memory loading file "
392                                     + file
393                                     + "!!"
394                                     + "\nSee help files for increasing Java Virtual Machine memory.",
395                             "Out of memory",
396                             javax.swing.JOptionPane.WARNING_MESSAGE);
397           }
398         });
399       }
400       else
401       {
402         System.err.println("Out of memory loading file " + file + "!!");
403       }
404     }
405     loadtime += System.currentTimeMillis();
406
407     // System.gc();
408     memused = memused - (rt.maxMemory() - rt.totalMemory() + rt.freeMemory()); // difference in free memory after load
409     if (Desktop.desktop != null && Desktop.desktop.isShowMemoryUsage())
410     {
411       if (alignFrame != null)
412       {
413         AlignmentI al = alignFrame.getViewport().getAlignment();
414
415         System.out.println("Loaded '" + title + "' in "
416                 + (loadtime / 1000.0) + "s, took an additional "
417                 + (1.0 * memused / (1024.0 * 1024.0)) + " MB ("
418                 + al.getHeight() + " seqs by " + al.getWidth() + " cols)");
419       } else {
420         // report that we didn't load anything probably due to an out of memory error
421         System.out.println("Failed to load '"+title+"' in "
422                 + (loadtime / 1000.0) + "s, took an additional "
423                 + (1.0 * memused / (1024.0 * 1024.0)) + " MB (alignment is null)");
424       }
425     }
426     // remove the visual delay indicator
427     if (Desktop.instance != null)
428     {
429       Desktop.instance.stopLoading();
430     }
431
432   }
433
434   /*
435    * (non-Javadoc)
436    * 
437    * @see java.lang.Object#finalize()
438    */
439   protected void finalize() throws Throwable
440   {
441     source = null;
442     alignFrame = null;
443     viewport = null;
444     super.finalize();
445   }
446
447 }