pasted file contents should never be added to the recent URL or recent file list.
[jalview.git] / src / jalview / io / FileLoader.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
3  * Copyright (C) 2009 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     if (protocol.equals(FormatAdapter.PASTE))
177     {
178       // do nothing if the file was pasted in as text... there is no filename to refer to it as.
179       return;
180     }
181     String type = protocol.equals(FormatAdapter.FILE) ? "RECENT_FILE"
182             : "RECENT_URL";
183
184     String historyItems = jalview.bin.Cache.getProperty(type);
185
186     StringTokenizer st;
187
188     if (historyItems != null)
189     {
190       st = new StringTokenizer(historyItems, "\t");
191
192       while (st.hasMoreTokens())
193       {
194         recent.addElement(st.nextElement().toString().trim());
195       }
196     }
197
198     if (recent.contains(file))
199     {
200       recent.remove(file);
201     }
202
203     StringBuffer newHistory = new StringBuffer(file);
204     for (int i = 0; i < recent.size() && i < 10; i++)
205     {
206       newHistory.append("\t");
207       newHistory.append(recent.elementAt(i));
208     }
209
210     jalview.bin.Cache.setProperty(type, newHistory.toString());
211
212     if (protocol.equals(FormatAdapter.FILE))
213     {
214       jalview.bin.Cache.setProperty("DEFAULT_FILE_FORMAT", format);
215     }
216   }
217
218   public void run()
219   {
220     String title = protocol.equals(AppletFormatAdapter.PASTE) ? "Copied From Clipboard"
221             : file;
222     Runtime rt = Runtime.getRuntime();
223     try
224     {
225       if (Desktop.instance != null)
226       {
227         Desktop.instance.startLoading(file);
228       }
229       if (format == null)
230       {
231         // just in case the caller didn't identify the file for us
232         if (source != null)
233         {
234           format = new IdentifyFile().Identify(source, false); // identify
235           // stream and
236           // rewind rather
237           // than close
238         }
239         else
240         {
241           format = new IdentifyFile().Identify(file, protocol);
242         }
243       }
244       if (Desktop.desktop != null && Desktop.desktop.isShowMemoryUsage())
245       {
246         System.gc();
247         memused = (rt.maxMemory() - rt.totalMemory() + rt.freeMemory()); // free
248                                                                           // memory
249                                                                           // before
250                                                                           // load
251       }
252       loadtime = -System.currentTimeMillis();
253       Alignment al = null;
254
255       if (format.equalsIgnoreCase("Jalview"))
256       {
257         if (source != null)
258         {
259           // Tell the user (developer?) that this is going to cause a problem
260           System.err
261                   .println("IMPLEMENTATION ERROR: Cannot read consecutive Jalview XML projects from a stream.");
262           // We read the data anyway - it might make sense.
263         }
264         alignFrame = new Jalview2XML(raiseGUI).LoadJalviewAlign(file);
265       }
266       else
267       {
268         String error = AppletFormatAdapter.SUPPORTED_FORMATS;
269         if (FormatAdapter.isValidFormat(format))
270         {
271           try
272           {
273             if (source != null)
274             {
275               // read from the provided source
276               al = new FormatAdapter().readFromFile(source, format);
277             }
278             else
279             {
280
281               // open a new source and read from it
282               FormatAdapter fa = new FormatAdapter();
283               al = fa.readFile(file, protocol, format);
284               source = fa.afile; // keep reference for later if necessary.
285             }
286           } catch (java.io.IOException ex)
287           {
288             error = ex.getMessage();
289           }
290         }
291         else
292         {
293           if (format != null && format.length() > 7)
294           {
295             // ad hoc message in format.
296             error = format + "\n" + error;
297           }
298         }
299
300         if ((al != null) && (al.getHeight() > 0))
301         {
302           if (viewport != null)
303           {
304             for (int i = 0; i < al.getHeight(); i++)
305             {
306               viewport.getAlignment().addSequence(al.getSequenceAt(i));
307             }
308             viewport.firePropertyChange("alignment", null, viewport
309                     .getAlignment().getSequences());
310
311           }
312           else
313           {
314             alignFrame = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH,
315                     AlignFrame.DEFAULT_HEIGHT);
316
317             alignFrame.statusBar.setText("Successfully loaded file "
318                     + title);
319
320             if (!protocol.equals(AppletFormatAdapter.PASTE))
321               alignFrame.setFileName(file, format);
322
323             Desktop.addInternalFrame(alignFrame, title,
324                     AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
325
326             try
327             {
328               alignFrame.setMaximum(jalview.bin.Cache.getDefault(
329                       "SHOW_FULLSCREEN", false));
330             } catch (java.beans.PropertyVetoException ex)
331             {
332             }
333           }
334         }
335         else
336         {
337           if (Desktop.instance != null)
338           {
339             Desktop.instance.stopLoading();
340           }
341
342           final String errorMessage = "Couldn't load file " + title + "\n"
343                   + error;
344           if (raiseGUI)
345           {
346             javax.swing.SwingUtilities.invokeLater(new Runnable()
347             {
348               public void run()
349               {
350                 JOptionPane.showInternalMessageDialog(Desktop.desktop,
351                         errorMessage, "Error loading file",
352                         JOptionPane.WARNING_MESSAGE);
353               }
354             });
355           }
356           else
357           {
358             System.err.println(errorMessage);
359           }
360         }
361       }
362
363       updateRecentlyOpened();
364
365     } catch (Exception er)
366     {
367       System.err.println("Exception whilst opening file '" + file);
368       er.printStackTrace();
369       if (raiseGUI)
370       {
371         javax.swing.SwingUtilities.invokeLater(new Runnable()
372         {
373           public void run()
374           {
375             javax.swing.JOptionPane.showInternalMessageDialog(
376                     Desktop.desktop, "Encountered problems opening " + file
377                             + "!!", "File open error",
378                     javax.swing.JOptionPane.WARNING_MESSAGE);
379           }
380         });
381       }
382       alignFrame = null;
383     } catch (OutOfMemoryError er)
384     {
385
386       er.printStackTrace();
387       alignFrame = null;
388       if (raiseGUI)
389       {
390         javax.swing.SwingUtilities.invokeLater(new Runnable()
391         {
392           public void run()
393           {
394             javax.swing.JOptionPane
395                     .showInternalMessageDialog(
396                             Desktop.desktop,
397                             "Out of memory loading file "
398                                     + file
399                                     + "!!"
400                                     + "\nSee help files for increasing Java Virtual Machine memory.",
401                             "Out of memory",
402                             javax.swing.JOptionPane.WARNING_MESSAGE);
403           }
404         });
405       }
406       System.err.println("Out of memory loading file " + file + "!!");
407
408     }
409     loadtime += System.currentTimeMillis();
410     // TODO: Estimate percentage of memory used by a newly loaded alignment -
411     // warn if more memory will be needed to work with it
412     // System.gc();
413     memused = memused
414             - (rt.maxMemory() - rt.totalMemory() + rt.freeMemory()); // difference
415                                                                       // in free
416                                                                       // memory
417                                                                       // after
418                                                                       // load
419     if (Desktop.desktop != null && Desktop.desktop.isShowMemoryUsage())
420     {
421       if (alignFrame != null)
422       {
423         AlignmentI al = alignFrame.getViewport().getAlignment();
424
425         System.out.println("Loaded '" + title + "' in "
426                 + (loadtime / 1000.0) + "s, took an additional "
427                 + (1.0 * memused / (1024.0 * 1024.0)) + " MB ("
428                 + al.getHeight() + " seqs by " + al.getWidth() + " cols)");
429       }
430       else
431       {
432         // report that we didn't load anything probably due to an out of memory
433         // error
434         System.out.println("Failed to load '" + title + "' in "
435                 + (loadtime / 1000.0) + "s, took an additional "
436                 + (1.0 * memused / (1024.0 * 1024.0))
437                 + " MB (alignment is null)");
438       }
439     }
440     // remove the visual delay indicator
441     if (Desktop.instance != null)
442     {
443       Desktop.instance.stopLoading();
444     }
445
446   }
447
448   /*
449    * (non-Javadoc)
450    * 
451    * @see java.lang.Object#finalize()
452    */
453   protected void finalize() throws Throwable
454   {
455     source = null;
456     alignFrame = null;
457     viewport = null;
458     super.finalize();
459   }
460
461 }