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