c9977fd0d30d24080354498a06054b080d374aa1
[jalview.git] / src / jalview / bin / JalviewLite.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2007 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.bin;
20
21 import java.applet.*;
22
23 import java.awt.*;
24 import java.awt.event.*;
25 import java.util.*;
26
27 import jalview.appletgui.*;
28 import jalview.datamodel.*;
29 import jalview.io.*;
30
31 /**
32  * Jalview Applet. Runs in Java 1.18 runtime
33  *
34  * @author $author$
35  * @version $Revision$
36  */
37 public class JalviewLite
38     extends Applet
39 {
40
41
42
43   ///////////////////////////////////////////
44   //The following public methods maybe called
45   //externally, eg via javascript in HTML page
46   /**
47    * @return list of selected sequences separated by "¬"
48    */
49   public String getSelectedSequences()
50   {
51     return getSelectedSequences(currentAlignFrame);
52   }
53   public String getSelectedSequences(AlignFrame alf)
54   {
55     StringBuffer result = new StringBuffer("");
56
57     if (alf.viewport.getSelectionGroup() != null)
58     {
59       SequenceI[] seqs = alf.viewport.getSelectionGroup().
60           getSequencesInOrder(
61                   alf.viewport.getAlignment());
62
63       for (int i = 0; i < seqs.length; i++)
64       {
65         result.append(seqs[i].getName() + "¬");
66       }
67     }
68
69     return result.toString();
70   }
71   
72   public String getAlignment(String format)
73   {
74     return getAlignment(currentAlignFrame, format, "true");
75   }
76   public String getAlignment(AlignFrame alf, String format)
77   {
78     return getAlignment(alf, format, "true");
79   }
80   public String getAlignment(String format, String suffix)
81   {
82     return getAlignment(currentAlignFrame, format, suffix);
83   }
84   public String getAlignment(AlignFrame alf, String format, String suffix)
85   {
86     try
87     {
88       boolean seqlimits = suffix.equalsIgnoreCase("true");
89
90       String reply = new AppletFormatAdapter().formatSequences(format,
91           alf.viewport.getAlignment(), seqlimits);
92       return reply;
93     }
94     catch (Exception ex)
95     {
96       ex.printStackTrace();
97       return "Error retrieving alignment in " + format + " format. ";
98     }
99   }
100
101   public void loadAnnotation(String annotation)
102   {
103     loadAnnotation(currentAlignFrame, annotation);
104   }
105   public void loadAnnotation(AlignFrame alf, String annotation)
106   {
107     if (new AnnotationFile().readAnnotationFile(
108         alf.getAlignViewport().getAlignment(), annotation,
109         AppletFormatAdapter.PASTE))
110     {
111       alf.alignPanel.fontChanged();
112       alf.alignPanel.setScrollValues(0, 0);
113     }
114     else
115     {
116       alf.parseFeaturesFile(annotation, AppletFormatAdapter.PASTE);
117     }
118   }
119
120   public String getFeatures(String format)
121   {
122     return getFeatures(currentAlignFrame, format);
123   }
124   public String getFeatures(AlignFrame alf, String format)
125   {
126     return alf.outputFeatures(false, format);
127   }
128   public String getAnnotation()
129   {
130     return getAnnotation(currentAlignFrame);
131   }
132   public String getAnnotation(AlignFrame alf)
133   {
134     return alf.outputAnnotations(false);
135   }
136   public AlignFrame newView()
137   {
138     return newView(currentAlignFrame);
139   }
140   public AlignFrame newView(String name)
141   {
142     return newView(currentAlignFrame, name);
143   }
144
145   public AlignFrame newView(AlignFrame alf)
146   {
147     return alf.newView(null);
148   }
149   public AlignFrame newView(AlignFrame alf, String name)
150   {
151     return alf.newView(name);
152   }
153   /**
154    * 
155    * @param text alignment file as a string
156    * @param title window title 
157    * @return null or new alignment frame
158    */
159   public AlignFrame loadAlignment(String text, String title)
160   {
161     Alignment al = null;
162     String format = new IdentifyFile().Identify(text, AppletFormatAdapter.PASTE);
163     try
164     {
165       al = new AppletFormatAdapter().readFile(text,
166                                               AppletFormatAdapter.PASTE,
167                                               format);
168       if (al.getHeight() > 0)
169       {
170         return new AlignFrame(al, this, title, false);
171       }
172     }
173     catch (java.io.IOException ex)
174     {
175       ex.printStackTrace();
176     }
177     return null;
178   }
179
180   ////////////////////////////////////////////////
181   ////////////////////////////////////////////////
182
183
184
185   static int lastFrameX = 200;
186   static int lastFrameY = 200;
187   boolean fileFound = true;
188   String file = "No file";
189   Button launcher = new Button("Start Jalview");
190
191   //The currentAlignFrame is static, it will change
192   //if and when the user selects a new window
193   public static AlignFrame currentAlignFrame;
194
195   //This is the first frame to be displayed, and does not change
196   AlignFrame initialAlignFrame;
197
198   boolean embedded = false;
199
200   public boolean jmolAvailable = false;
201   public static boolean debug;
202
203   /**
204    * init method for Jalview Applet
205    */
206   public void init()
207   {
208     String dbg = getParameter("debug");
209     if (dbg!=null)
210     {
211       debug = dbg.toLowerCase().equals("true");
212     }
213     int r = 255;
214     int g = 255;
215     int b = 255;
216     String param = getParameter("RGB");
217
218     if (param != null)
219     {
220       try
221       {
222         r = Integer.parseInt(param.substring(0, 2), 16);
223         g = Integer.parseInt(param.substring(2, 4), 16);
224         b = Integer.parseInt(param.substring(4, 6), 16);
225       }
226       catch (Exception ex)
227       {
228         r = 255;
229         g = 255;
230         b = 255;
231       }
232     }
233
234     param = getParameter("label");
235     if (param != null)
236     {
237       launcher.setLabel(param);
238     }
239
240     this.setBackground(new Color(r, g, b));
241
242     file = getParameter("file");
243
244     if (file == null)
245     {
246       //Maybe the sequences are added as parameters
247       StringBuffer data = new StringBuffer("PASTE");
248       int i = 1;
249       while ( (file = getParameter("sequence" + i)) != null)
250       {
251         data.append(file.toString() + "\n");
252         i++;
253       }
254       if (data.length() > 5)
255       {
256         file = data.toString();
257       }
258     }
259
260     LoadJmolThread jmolAvailable = new LoadJmolThread();
261     jmolAvailable.start();
262
263     final JalviewLite applet = this;
264     if (getParameter("embedded") != null
265         && getParameter("embedded").equalsIgnoreCase("true"))
266     {
267       embedded = true;
268       LoadingThread loader = new LoadingThread(file, applet);
269       loader.start();
270     }
271     else if (file != null)
272     {
273       add(launcher);
274
275       launcher.addActionListener(new java.awt.event.ActionListener()
276       {
277         public void actionPerformed(ActionEvent e)
278         {
279           LoadingThread loader = new LoadingThread(file,
280               applet);
281           loader.start();
282         }
283       });
284     }
285     else
286     {
287       file = "NO FILE";
288       fileFound = false;
289     }
290   }
291
292
293   /**
294    * Initialises and displays a new java.awt.Frame
295    *
296    * @param frame java.awt.Frame to be displayed
297    * @param title title of new frame
298    * @param width width if new frame
299    * @param height height of new frame
300    */
301   public static void addFrame(final Frame frame, String title, int width,
302                               int height)
303   {
304     frame.setLocation(lastFrameX, lastFrameY);
305     lastFrameX += 40;
306     lastFrameY += 40;
307     frame.setSize(width, height);
308     frame.setTitle(title);
309     frame.addWindowListener(new WindowAdapter()
310     {
311       public void windowClosing(WindowEvent e)
312       {
313         if (frame instanceof AlignFrame)
314         {
315           ( (AlignFrame) frame).closeMenuItem_actionPerformed();
316         }
317         if (currentAlignFrame == frame)
318         {
319           currentAlignFrame = null;
320         }
321         lastFrameX -= 40;
322         lastFrameY -= 40;
323         frame.setMenuBar(null);
324         frame.dispose();
325       }
326
327       public void windowActivated(WindowEvent e)
328       {
329         if (frame instanceof AlignFrame)
330         {
331           currentAlignFrame = (AlignFrame) frame;
332           if (debug)
333           {
334             System.err.println("Activated window "+frame);
335           }
336         }
337       }
338
339     });
340     frame.setVisible(true);
341   }
342
343   /**
344    * This paints the background surrounding the "Launch Jalview button"
345    * <br>
346    * <br>If file given in parameter not found, displays error message
347    *
348    * @param g graphics context
349    */
350   public void paint(Graphics g)
351   {
352     if (!fileFound)
353     {
354       g.setColor(new Color(200, 200, 200));
355       g.setColor(Color.cyan);
356       g.fillRect(0, 0, getSize().width, getSize().height);
357       g.setColor(Color.red);
358       g.drawString("Jalview can't open file", 5, 15);
359       g.drawString("\"" + file + "\"", 5, 30);
360     }
361     else if (embedded)
362     {
363       g.setColor(Color.black);
364       g.setFont(new Font("Arial", Font.BOLD, 24));
365       g.drawString("Jalview Applet", 50, this.getSize().height / 2 - 30);
366       g.drawString("Loading Data...", 50, this.getSize().height / 2);
367     }
368   }
369
370
371   class LoadJmolThread extends Thread
372   {
373     public void run()
374     {
375       try
376       {
377         if (!System.getProperty("java.version").startsWith("1.1"))
378         {
379           Class.forName("org.jmol.adapter.smarter.SmarterJmolAdapter");
380           jmolAvailable = true;
381         }
382       }
383       catch (java.lang.ClassNotFoundException ex)
384       {
385         System.out.println("Jmol not available - Using MCview for structures");
386       }
387     }
388   }
389
390
391   class LoadingThread
392       extends Thread
393   {
394     String file;
395     String protocol;
396     String format;
397     JalviewLite applet;
398
399     public LoadingThread(String _file,
400                          JalviewLite _applet)
401     {
402       if (applet.debug)
403       {
404         System.err.println("Loading thread started with:\n>>file\n"+_file+">>endfile");
405       }
406       file = _file;
407       if (file.startsWith("PASTE"))
408       {
409         file = file.substring(5);
410         protocol = AppletFormatAdapter.PASTE;
411       }
412       else if (inArchive(file))
413       {
414         protocol = AppletFormatAdapter.CLASSLOADER;
415       }
416       else
417       {
418         file = addProtocol(file);
419         protocol = AppletFormatAdapter.URL;
420       }
421       if (applet.debug)
422       {
423         System.err.println("Protocol identified as '"+protocol+"'");
424       }
425       format = new jalview.io.IdentifyFile().Identify(file, protocol);
426       if (applet.debug)
427       {
428         System.err.println("File identified as '"+format+"'");
429       }
430       applet = _applet;
431     }
432
433     public void run()
434     {
435       startLoading();
436     }
437
438     private void startLoading()
439     {
440       Alignment al = null;
441       try
442       {
443         al = new AppletFormatAdapter().readFile(file, protocol,
444                                                 format);
445       }
446       catch (java.io.IOException ex)
447       {
448         ex.printStackTrace();
449       }
450       if ( (al != null) && (al.getHeight() > 0))
451       {
452         currentAlignFrame = new AlignFrame(al,
453                                            applet,
454                                            file,
455                                            embedded);
456
457         if (protocol == jalview.io.AppletFormatAdapter.PASTE)
458         {
459           currentAlignFrame.setTitle("Sequences from " + getDocumentBase());
460         }
461
462         initialAlignFrame = currentAlignFrame;
463
464         currentAlignFrame.statusBar.setText("Successfully loaded file " + file);
465
466         String treeFile = applet.getParameter("tree");
467         if (treeFile == null)
468         {
469           treeFile = applet.getParameter("treeFile");
470         }
471
472         if (treeFile != null)
473         {
474           try
475           {
476             if (inArchive(treeFile))
477             {
478               protocol = AppletFormatAdapter.CLASSLOADER;
479             }
480             else
481             {
482               protocol = AppletFormatAdapter.URL;
483               treeFile = addProtocol(treeFile);
484             }
485
486             jalview.io.NewickFile fin = new jalview.io.NewickFile(treeFile,
487                 protocol);
488
489             fin.parse();
490
491             if (fin.getTree() != null)
492             {
493               currentAlignFrame.loadTree(fin, treeFile);
494             }
495           }
496           catch (Exception ex)
497           {
498             ex.printStackTrace();
499           }
500         }
501
502         String param = getParameter("features");
503         if (param != null)
504         {
505           if (!inArchive(param))
506           {
507             param = addProtocol(param);
508           }
509
510           currentAlignFrame.parseFeaturesFile(param, protocol);
511         }
512
513         param = getParameter("showFeatureSettings");
514         if (param != null && param.equalsIgnoreCase("true"))
515         {
516           currentAlignFrame.viewport.showSequenceFeatures(true);
517           new FeatureSettings(currentAlignFrame.alignPanel);
518         }
519
520         param = getParameter("annotations");
521         if (param != null)
522         {
523           if (!inArchive(param))
524           {
525             param = addProtocol(param);
526           }
527
528           new AnnotationFile().readAnnotationFile(
529               currentAlignFrame.viewport.getAlignment(),
530               param,
531               protocol);
532
533           currentAlignFrame.alignPanel.fontChanged();
534           currentAlignFrame.alignPanel.setScrollValues(0, 0);
535
536         }
537
538         param = getParameter("jnetfile");
539         if (param != null)
540         {
541           try
542           {
543             if (inArchive(param))
544             {
545               protocol = AppletFormatAdapter.CLASSLOADER;
546             }
547             else
548             {
549               protocol = AppletFormatAdapter.URL;
550               param = addProtocol(param);
551             }
552
553             jalview.io.JPredFile predictions = new jalview.io.JPredFile(
554                 param, protocol);
555             new JnetAnnotationMaker().add_annotation(predictions,
556                 currentAlignFrame.viewport.getAlignment(),
557                 0, false); // do not add sequence profile from concise output
558             currentAlignFrame.alignPanel.fontChanged();
559             currentAlignFrame.alignPanel.setScrollValues(0, 0);
560           }
561           catch (Exception ex)
562           {
563             ex.printStackTrace();
564           }
565         }
566
567         /*
568          <param name="PDBfile" value="1gaq.txt PDB|1GAQ|1GAQ|A PDB|1GAQ|1GAQ|B PDB|1GAQ|1GAQ|C">
569
570          <param name="PDBfile2" value="1gaq.txt A=SEQA B=SEQB C=SEQB">
571
572          <param name="PDBfile3" value="1q0o Q45135_9MICO">
573         */
574
575
576         int pdbFileCount = 0;
577         do{
578           if (pdbFileCount > 0)
579             param = getParameter("PDBFILE" + pdbFileCount);
580           else
581             param = getParameter("PDBFILE");
582
583           if (param != null)
584           {
585             PDBEntry pdb = new PDBEntry();
586
587             String seqstring;
588             SequenceI[] seqs = null;
589             String [] chains = null;
590
591             StringTokenizer st = new StringTokenizer(param, " ");
592
593             if (st.countTokens() < 2)
594             {
595               String sequence = applet.getParameter("PDBSEQ");
596               if (sequence != null)
597                 seqs = new SequenceI[]
598                     {
599                     (Sequence) currentAlignFrame.
600                     getAlignViewport().getAlignment().
601                     findName(sequence)};
602
603             }
604             else
605             {
606               param = st.nextToken();
607               Vector tmp = new Vector();
608               Vector tmp2 = new Vector();
609
610               while (st.hasMoreTokens())
611               {
612                 seqstring = st.nextToken();
613                 StringTokenizer st2 = new StringTokenizer(seqstring,"=");
614                 if(st2.countTokens()>1)
615                 {
616                   //This is the chain
617                   tmp2.addElement(st2.nextToken());
618                   seqstring = st2.nextToken();
619                 }
620                 tmp.addElement( (Sequence) currentAlignFrame.
621                                  getAlignViewport().getAlignment().
622                                  findName(seqstring));
623               }
624
625               seqs = new SequenceI[tmp.size()];
626               tmp.copyInto(seqs);
627               if(tmp2.size()==tmp.size())
628               {
629                 chains = new String[tmp2.size()];
630                 tmp2.copyInto(chains);
631               }
632             }
633
634             if (inArchive(param) && !jmolAvailable)
635             {
636               protocol = AppletFormatAdapter.CLASSLOADER;
637             }
638             else
639             {
640               protocol = AppletFormatAdapter.URL;
641               param = addProtocol(param);
642             }
643
644             pdb.setFile(param);
645
646             if(seqs!=null)
647             {
648               for (int i = 0; i < seqs.length; i++)
649               {
650                 ( (Sequence) seqs[i]).addPDBId(pdb);
651               }
652
653               if (jmolAvailable)
654               {
655                 new jalview.appletgui.AppletJmol(pdb,
656                                                  seqs,
657                                                  chains,
658                                                  currentAlignFrame.alignPanel,
659                                                  protocol);
660                 lastFrameX += 40;
661                 lastFrameY+=40;
662               }
663               else
664                     new MCview.AppletPDBViewer(pdb,
665                                            seqs,
666                                            chains,
667                                            currentAlignFrame.alignPanel,
668                                            protocol);
669             }
670           }
671
672           pdbFileCount++;
673         }
674         while(pdbFileCount < 10);
675         
676         /////////////////////////////
677         // modify display of features
678         //
679         // hide specific groups
680         param = getParameter("hidefeaturegroups");
681         if (param != null)
682         {
683           applet.setFeatureGroupState(param, false);
684         }
685         // show specific groups
686         param = getParameter("showfeaturegroups");
687         if (param != null)
688         {
689           applet.setFeatureGroupState(param, true);
690         }
691       }
692       else
693       {
694         fileFound = false;
695         remove(launcher);
696         repaint();
697       }
698     }
699
700     /**
701      * Discovers whether the given file is in the Applet Archive
702      * @param file String
703      * @return boolean
704      */
705     boolean inArchive(String file)
706     {
707       //This might throw a security exception in certain browsers
708       //Netscape Communicator for instance.
709       try
710       {
711         return (getClass().getResourceAsStream("/" + file) != null);
712       }
713       catch (Exception ex)
714       {
715         System.out.println("Exception checking resources: " + file + " " + ex);
716         return false;
717       }
718     }
719
720     String addProtocol(String file)
721     {
722       if (file.indexOf("://") == -1)
723       {
724         file = getCodeBase() + file;
725       }
726
727       return file;
728     }
729   }
730
731   public String[] tabbedListToArray(String list)
732   {
733     if (list==null || list.equals(""))
734       return null;
735     java.util.Vector jv = new Vector();
736     int cp=0,pos;
737     while ((pos=list.indexOf("\t",cp))>cp)
738     {
739       jv.addElement(list.substring(cp,pos));
740       cp = pos+1;
741     }
742     if (cp<list.length())
743     {
744       jv.addElement(list.substring(cp));
745     }
746     if (jv.size()>0)
747     { String[] v = new String[jv.size()];
748       jv.copyInto(v);
749       jv.removeAllElements();
750       if (debug)
751       {
752         System.err.println("Array from Tabbed List:\n"+v.length+"\n"+v.toString());
753       }
754       return v;
755     }
756     if (debug)
757     {
758       System.err.println("Empty Array from Tabbed List");
759     }
760     return null;
761   }
762
763   public String ArraytotabbedList(String[] list)
764   {
765     StringBuffer v = new StringBuffer();
766     if (list!=null)
767     {
768       for (int i=0,iSize=list.length-1;i<iSize;i++)
769       { 
770         if (list[i]!=null)
771         {  
772           v.append(list[i]); 
773         }
774         v.append("\t");
775       }
776       if (list[list.length-1]!=null)
777       { v.append(list[list.length-1]);
778       }
779       if (debug)
780       {
781         System.err.println("Tabbed List:\n"+v.toString());
782       }
783       return v.toString();
784     }
785     if (debug)
786     {
787       System.err.println("Empty Tabbed List\n");
788     }
789     return "";
790   }
791   /**
792    * @return
793    * @see jalview.appletgui.AlignFrame#getFeatureGroups()
794    */
795   public String getFeatureGroups()
796   {
797     String lst = ArraytotabbedList(currentAlignFrame.getFeatureGroups());
798     return lst;
799   }
800
801   /**
802    * @param visible
803    * @return
804    * @see jalview.appletgui.AlignFrame#getFeatureGroupsOfState(boolean)
805    */
806   public String getFeatureGroupsOfState(boolean visible)
807   {
808     return ArraytotabbedList(currentAlignFrame.getFeatureGroupsOfState(visible));
809   }
810   /**
811    * @param groups tab separated list of group names 
812    * @param state true or false
813    * @see jalview.appletgui.AlignFrame#setFeatureGroupState(java.lang.String[], boolean)
814    */
815   public void setFeatureGroupState(AlignFrame alf, String groups, boolean state)
816   {
817     boolean st = state;//!(state==null || state.equals("") || state.toLowerCase().equals("false"));
818     alf.setFeatureGroupState(tabbedListToArray(groups), st);
819   }
820   public void setFeatureGroupState(String groups, boolean state)
821   {
822     setFeatureGroupState(currentAlignFrame, groups, state);
823   }
824 }