featureGroup show/hide and newView methods for applet's javascript API
[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
202   /**
203    * init method for Jalview Applet
204    */
205   public void init()
206   {
207     int r = 255;
208     int g = 255;
209     int b = 255;
210     String param = getParameter("RGB");
211
212     if (param != null)
213     {
214       try
215       {
216         r = Integer.parseInt(param.substring(0, 2), 16);
217         g = Integer.parseInt(param.substring(2, 4), 16);
218         b = Integer.parseInt(param.substring(4, 6), 16);
219       }
220       catch (Exception ex)
221       {
222         r = 255;
223         g = 255;
224         b = 255;
225       }
226     }
227
228     param = getParameter("label");
229     if (param != null)
230     {
231       launcher.setLabel(param);
232     }
233
234     this.setBackground(new Color(r, g, b));
235
236     file = getParameter("file");
237
238     if (file == null)
239     {
240       //Maybe the sequences are added as parameters
241       StringBuffer data = new StringBuffer("PASTE");
242       int i = 1;
243       while ( (file = getParameter("sequence" + i)) != null)
244       {
245         data.append(file.toString() + "\n");
246         i++;
247       }
248       if (data.length() > 5)
249       {
250         file = data.toString();
251       }
252     }
253
254     LoadJmolThread jmolAvailable = new LoadJmolThread();
255     jmolAvailable.start();
256
257     final JalviewLite applet = this;
258     if (getParameter("embedded") != null
259         && getParameter("embedded").equalsIgnoreCase("true"))
260     {
261       embedded = true;
262       LoadingThread loader = new LoadingThread(file, applet);
263       loader.start();
264     }
265     else if (file != null)
266     {
267       add(launcher);
268
269       launcher.addActionListener(new java.awt.event.ActionListener()
270       {
271         public void actionPerformed(ActionEvent e)
272         {
273           LoadingThread loader = new LoadingThread(file,
274               applet);
275           loader.start();
276         }
277       });
278     }
279     else
280     {
281       file = "NO FILE";
282       fileFound = false;
283     }
284   }
285
286
287   /**
288    * Initialises and displays a new java.awt.Frame
289    *
290    * @param frame java.awt.Frame to be displayed
291    * @param title title of new frame
292    * @param width width if new frame
293    * @param height height of new frame
294    */
295   public static void addFrame(final Frame frame, String title, int width,
296                               int height)
297   {
298     frame.setLocation(lastFrameX, lastFrameY);
299     lastFrameX += 40;
300     lastFrameY += 40;
301     frame.setSize(width, height);
302     frame.setTitle(title);
303     frame.addWindowListener(new WindowAdapter()
304     {
305       public void windowClosing(WindowEvent e)
306       {
307         if (frame instanceof AlignFrame)
308         {
309           ( (AlignFrame) frame).closeMenuItem_actionPerformed();
310         }
311         if (currentAlignFrame == frame)
312         {
313           currentAlignFrame = null;
314         }
315         lastFrameX -= 40;
316         lastFrameY -= 40;
317         frame.setMenuBar(null);
318         frame.dispose();
319       }
320
321       public void windowActivated(WindowEvent e)
322       {
323         if (frame instanceof AlignFrame)
324         {
325           currentAlignFrame = (AlignFrame) frame;
326           System.err.println("Activated window "+frame);
327         }
328       }
329
330     });
331     frame.setVisible(true);
332   }
333
334   /**
335    * This paints the background surrounding the "Launch Jalview button"
336    * <br>
337    * <br>If file given in parameter not found, displays error message
338    *
339    * @param g graphics context
340    */
341   public void paint(Graphics g)
342   {
343     if (!fileFound)
344     {
345       g.setColor(new Color(200, 200, 200));
346       g.setColor(Color.cyan);
347       g.fillRect(0, 0, getSize().width, getSize().height);
348       g.setColor(Color.red);
349       g.drawString("Jalview can't open file", 5, 15);
350       g.drawString("\"" + file + "\"", 5, 30);
351     }
352     else if (embedded)
353     {
354       g.setColor(Color.black);
355       g.setFont(new Font("Arial", Font.BOLD, 24));
356       g.drawString("Jalview Applet", 50, this.getSize().height / 2 - 30);
357       g.drawString("Loading Data...", 50, this.getSize().height / 2);
358     }
359   }
360
361
362   class LoadJmolThread extends Thread
363   {
364     public void run()
365     {
366       try
367       {
368         if (!System.getProperty("java.version").startsWith("1.1"))
369         {
370           Class.forName("org.jmol.adapter.smarter.SmarterJmolAdapter");
371           jmolAvailable = true;
372         }
373       }
374       catch (java.lang.ClassNotFoundException ex)
375       {
376         System.out.println("Jmol not available - Using MCview for structures");
377       }
378     }
379   }
380
381
382   class LoadingThread
383       extends Thread
384   {
385     String file;
386     String protocol;
387     String format;
388     JalviewLite applet;
389
390     public LoadingThread(String _file,
391                          JalviewLite _applet)
392     {
393       file = _file;
394       if (file.startsWith("PASTE"))
395       {
396         file = file.substring(5);
397         protocol = AppletFormatAdapter.PASTE;
398       }
399       else if (inArchive(file))
400       {
401         protocol = AppletFormatAdapter.CLASSLOADER;
402       }
403       else
404       {
405         file = addProtocol(file);
406         protocol = AppletFormatAdapter.URL;
407       }
408       format = new jalview.io.IdentifyFile().Identify(file, protocol);
409       applet = _applet;
410     }
411
412     public void run()
413     {
414       startLoading();
415     }
416
417     private void startLoading()
418     {
419       Alignment al = null;
420       try
421       {
422         al = new AppletFormatAdapter().readFile(file, protocol,
423                                                 format);
424       }
425       catch (java.io.IOException ex)
426       {
427         ex.printStackTrace();
428       }
429       if ( (al != null) && (al.getHeight() > 0))
430       {
431         currentAlignFrame = new AlignFrame(al,
432                                            applet,
433                                            file,
434                                            embedded);
435
436         if (protocol == jalview.io.AppletFormatAdapter.PASTE)
437         {
438           currentAlignFrame.setTitle("Sequences from " + getDocumentBase());
439         }
440
441         initialAlignFrame = currentAlignFrame;
442
443         currentAlignFrame.statusBar.setText("Successfully loaded file " + file);
444
445         String treeFile = applet.getParameter("tree");
446         if (treeFile == null)
447         {
448           treeFile = applet.getParameter("treeFile");
449         }
450
451         if (treeFile != null)
452         {
453           try
454           {
455             if (inArchive(treeFile))
456             {
457               protocol = AppletFormatAdapter.CLASSLOADER;
458             }
459             else
460             {
461               protocol = AppletFormatAdapter.URL;
462               treeFile = addProtocol(treeFile);
463             }
464
465             jalview.io.NewickFile fin = new jalview.io.NewickFile(treeFile,
466                 protocol);
467
468             fin.parse();
469
470             if (fin.getTree() != null)
471             {
472               currentAlignFrame.loadTree(fin, treeFile);
473             }
474           }
475           catch (Exception ex)
476           {
477             ex.printStackTrace();
478           }
479         }
480
481         String param = getParameter("features");
482         if (param != null)
483         {
484           if (!inArchive(param))
485           {
486             param = addProtocol(param);
487           }
488
489           currentAlignFrame.parseFeaturesFile(param, protocol);
490         }
491
492         param = getParameter("showFeatureSettings");
493         if (param != null && param.equalsIgnoreCase("true"))
494         {
495           currentAlignFrame.viewport.showSequenceFeatures(true);
496           new FeatureSettings(currentAlignFrame.alignPanel);
497         }
498
499         param = getParameter("annotations");
500         if (param != null)
501         {
502           if (!inArchive(param))
503           {
504             param = addProtocol(param);
505           }
506
507           new AnnotationFile().readAnnotationFile(
508               currentAlignFrame.viewport.getAlignment(),
509               param,
510               protocol);
511
512           currentAlignFrame.alignPanel.fontChanged();
513           currentAlignFrame.alignPanel.setScrollValues(0, 0);
514
515         }
516
517         param = getParameter("jnetfile");
518         if (param != null)
519         {
520           try
521           {
522             if (inArchive(param))
523             {
524               protocol = AppletFormatAdapter.CLASSLOADER;
525             }
526             else
527             {
528               protocol = AppletFormatAdapter.URL;
529               param = addProtocol(param);
530             }
531
532             jalview.io.JPredFile predictions = new jalview.io.JPredFile(
533                 param, protocol);
534             new JnetAnnotationMaker().add_annotation(predictions,
535                 currentAlignFrame.viewport.getAlignment(),
536                 0, false); // do not add sequence profile from concise output
537             currentAlignFrame.alignPanel.fontChanged();
538             currentAlignFrame.alignPanel.setScrollValues(0, 0);
539           }
540           catch (Exception ex)
541           {
542             ex.printStackTrace();
543           }
544         }
545
546         /*
547          <param name="PDBfile" value="1gaq.txt PDB|1GAQ|1GAQ|A PDB|1GAQ|1GAQ|B PDB|1GAQ|1GAQ|C">
548
549          <param name="PDBfile2" value="1gaq.txt A=SEQA B=SEQB C=SEQB">
550
551          <param name="PDBfile3" value="1q0o Q45135_9MICO">
552         */
553
554
555         int pdbFileCount = 0;
556         do{
557           if (pdbFileCount > 0)
558             param = getParameter("PDBFILE" + pdbFileCount);
559           else
560             param = getParameter("PDBFILE");
561
562           if (param != null)
563           {
564             PDBEntry pdb = new PDBEntry();
565
566             String seqstring;
567             SequenceI[] seqs = null;
568             String [] chains = null;
569
570             StringTokenizer st = new StringTokenizer(param, " ");
571
572             if (st.countTokens() < 2)
573             {
574               String sequence = applet.getParameter("PDBSEQ");
575               if (sequence != null)
576                 seqs = new SequenceI[]
577                     {
578                     (Sequence) currentAlignFrame.
579                     getAlignViewport().getAlignment().
580                     findName(sequence)};
581
582             }
583             else
584             {
585               param = st.nextToken();
586               Vector tmp = new Vector();
587               Vector tmp2 = new Vector();
588
589               while (st.hasMoreTokens())
590               {
591                 seqstring = st.nextToken();
592                 StringTokenizer st2 = new StringTokenizer(seqstring,"=");
593                 if(st2.countTokens()>1)
594                 {
595                   //This is the chain
596                   tmp2.addElement(st2.nextToken());
597                   seqstring = st2.nextToken();
598                 }
599                 tmp.addElement( (Sequence) currentAlignFrame.
600                                  getAlignViewport().getAlignment().
601                                  findName(seqstring));
602               }
603
604               seqs = new SequenceI[tmp.size()];
605               tmp.copyInto(seqs);
606               if(tmp2.size()==tmp.size())
607               {
608                 chains = new String[tmp2.size()];
609                 tmp2.copyInto(chains);
610               }
611             }
612
613             if (inArchive(param) && !jmolAvailable)
614             {
615               protocol = AppletFormatAdapter.CLASSLOADER;
616             }
617             else
618             {
619               protocol = AppletFormatAdapter.URL;
620               param = addProtocol(param);
621             }
622
623             pdb.setFile(param);
624
625             if(seqs!=null)
626             {
627               for (int i = 0; i < seqs.length; i++)
628               {
629                 ( (Sequence) seqs[i]).addPDBId(pdb);
630               }
631
632               if (jmolAvailable)
633               {
634                 new jalview.appletgui.AppletJmol(pdb,
635                                                  seqs,
636                                                  chains,
637                                                  currentAlignFrame.alignPanel,
638                                                  protocol);
639                 lastFrameX += 40;
640                 lastFrameY+=40;
641               }
642               else
643                     new MCview.AppletPDBViewer(pdb,
644                                            seqs,
645                                            chains,
646                                            currentAlignFrame.alignPanel,
647                                            protocol);
648             }
649           }
650
651           pdbFileCount++;
652         }
653         while(pdbFileCount < 10);
654
655       }
656       else
657       {
658         fileFound = false;
659         remove(launcher);
660         repaint();
661       }
662     }
663
664     /**
665      * Discovers whether the given file is in the Applet Archive
666      * @param file String
667      * @return boolean
668      */
669     boolean inArchive(String file)
670     {
671       //This might throw a security exception in certain browsers
672       //Netscape Communicator for instance.
673       try
674       {
675         return (getClass().getResourceAsStream("/" + file) != null);
676       }
677       catch (Exception ex)
678       {
679         System.out.println("Exception checking resources: " + file + " " + ex);
680         return false;
681       }
682     }
683
684     String addProtocol(String file)
685     {
686       if (file.indexOf("://") == -1)
687       {
688         file = getCodeBase() + file;
689       }
690
691       return file;
692     }
693   }
694
695   public String[] tabbedListToArray(String list)
696   {
697     if (list==null || list.equals(""))
698       return null;
699     java.util.Vector jv = new Vector();
700     int cp=0,pos;
701     while ((pos=list.indexOf("\t",cp))>cp)
702     {
703       jv.addElement(list.substring(cp,pos));
704       cp = pos+1;
705     }
706     if (cp<list.length())
707     {
708       jv.addElement(list.substring(cp));
709     }
710     if (jv.size()>0)
711     { String[] v = new String[jv.size()];
712       jv.copyInto(v);
713       jv.removeAllElements();
714       System.err.println("Array from Tabbed List:\n"+v.length+"\n"+v.toString());
715       return v;
716     }
717     System.err.println("Empty Array from Tabbed List");
718     return null;
719   }
720
721   public String ArraytotabbedList(String[] list)
722   {
723     StringBuffer v = new StringBuffer();
724     if (list!=null)
725     {
726       for (int i=0,iSize=list.length-1;i<iSize;i++)
727       { 
728         if (list[i]!=null)
729         {  
730           v.append(list[i]); 
731         }
732         v.append("\t");
733       }
734       if (list[list.length-1]!=null)
735       { v.append(list[list.length-1]);
736       }
737       System.err.println("Tabbed List:\n"+v.toString());
738       return v.toString();
739     }
740     System.err.println("Empty Tabbed List\n");
741     return "";
742   }
743   /**
744    * @return
745    * @see jalview.appletgui.AlignFrame#getFeatureGroups()
746    */
747   public String getFeatureGroups()
748   {
749     String lst = ArraytotabbedList(currentAlignFrame.getFeatureGroups());
750     return lst;
751   }
752
753   /**
754    * @param visible
755    * @return
756    * @see jalview.appletgui.AlignFrame#getFeatureGroupsOfState(boolean)
757    */
758   public String getFeatureGroupsOfState(boolean visible)
759   {
760     return ArraytotabbedList(currentAlignFrame.getFeatureGroupsOfState(visible));
761   }
762   /**
763    * @param groups tab separated list of group names 
764    * @param state true or false
765    * @see jalview.appletgui.AlignFrame#setFeatureGroupState(java.lang.String[], boolean)
766    */
767   public void setFeatureGroupState(AlignFrame alf, String groups, boolean state)
768   {
769     boolean st = state;//!(state==null || state.equals("") || state.toLowerCase().equals("false"));
770     alf.setFeatureGroupState(tabbedListToArray(groups), st);
771   }
772   public void setFeatureGroupState(String groups, boolean state)
773   {
774     setFeatureGroupState(currentAlignFrame, groups, state);
775   }
776 }