a1f9e8e96f4fda1d255cc820f0606be8a7066595
[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 getSelectedSequencesFrom(getDefaultTargetFrame());
52   }
53   public String getSelectedSequencesFrom(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 getAlignmentFrom(getDefaultTargetFrame(), format, "true");
75   }
76   public String getAlignmentFrom(AlignFrame alf, String format)
77   {
78     return getAlignmentFrom(alf, format, "true");
79   }
80   public String getAlignment(String format, String suffix)
81   {
82     return getAlignmentFrom(getDefaultTargetFrame(), format, suffix);
83   }
84   public String getAlignmentFrom(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     loadAnnotationFrom(getDefaultTargetFrame(), annotation);
104   }
105   public void loadAnnotationFrom(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 getFeaturesFrom(getDefaultTargetFrame(), format);
123   }
124   public String getFeaturesFrom(AlignFrame alf, String format)
125   {
126     return alf.outputFeatures(false, format);
127   }
128   public String getAnnotation()
129   {
130     return getAnnotationFrom(getDefaultTargetFrame());
131   }
132   public String getAnnotationFrom(AlignFrame alf)
133   {
134     return alf.outputAnnotations(false);
135   }
136   public AlignFrame newView()
137   {
138     return newViewFrom(getDefaultTargetFrame());
139   }
140   public AlignFrame newView(String name)
141   {
142     return newViewFrom(getDefaultTargetFrame(), name);
143   }
144
145   public AlignFrame newViewFrom(AlignFrame alf)
146   {
147     return alf.newView(null);
148   }
149   public AlignFrame newViewFrom(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   /**
192    * The currentAlignFrame is static, it will change
193    * if and when the user selects a new window.
194    * Note that it will *never* point back to the embedded AlignFrame 
195    * if the applet is started as embedded on the page and then afterwards a new view is created.
196    */
197   public static AlignFrame currentAlignFrame;
198
199   /** 
200    * This is the first frame to be displayed, and does not change.
201    * API calls will default to this instance if currentAlignFrame is null.
202    */
203   AlignFrame initialAlignFrame;
204
205   boolean embedded = false;
206
207   public boolean jmolAvailable = false;
208   public static boolean debug;
209
210   /**
211    * init method for Jalview Applet
212    */
213   public void init()
214   {
215     String dbg = getParameter("debug");
216     if (dbg!=null)
217     {
218       debug = dbg.toLowerCase().equals("true");
219     }
220     /**
221      * get the separator parameter if present
222      */
223     String sep = getParameter("separator");
224     if (sep!=null)
225     {
226       if (sep.length()>0)
227       {      separator = sep;
228         if (debug)
229         {
230           System.err.println("Separator set to '"+separator+"'");
231         }
232       } else {
233         throw new Error("Invalid separator parameter - must be non-zero length");
234       }
235     }
236     int r = 255;
237     int g = 255;
238     int b = 255;
239     String param = getParameter("RGB");
240
241     if (param != null)
242     {
243       try
244       {
245         r = Integer.parseInt(param.substring(0, 2), 16);
246         g = Integer.parseInt(param.substring(2, 4), 16);
247         b = Integer.parseInt(param.substring(4, 6), 16);
248       }
249       catch (Exception ex)
250       {
251         r = 255;
252         g = 255;
253         b = 255;
254       }
255     }
256
257     param = getParameter("label");
258     if (param != null)
259     {
260       launcher.setLabel(param);
261     }
262
263     this.setBackground(new Color(r, g, b));
264
265     file = getParameter("file");
266
267     if (file == null)
268     {
269       //Maybe the sequences are added as parameters
270       StringBuffer data = new StringBuffer("PASTE");
271       int i = 1;
272       while ( (file = getParameter("sequence" + i)) != null)
273       {
274         data.append(file.toString() + "\n");
275         i++;
276       }
277       if (data.length() > 5)
278       {
279         file = data.toString();
280       }
281     }
282
283     LoadJmolThread jmolAvailable = new LoadJmolThread();
284     jmolAvailable.start();
285
286     final JalviewLite applet = this;
287     if (getParameter("embedded") != null
288         && getParameter("embedded").equalsIgnoreCase("true"))
289     {
290       embedded = true;
291       LoadingThread loader = new LoadingThread(file, applet);
292       loader.start();
293     }
294     else if (file != null)
295     {
296       add(launcher);
297
298       launcher.addActionListener(new java.awt.event.ActionListener()
299       {
300         public void actionPerformed(ActionEvent e)
301         {
302           LoadingThread loader = new LoadingThread(file,
303               applet);
304           loader.start();
305         }
306       });
307     }
308     else
309     {
310       file = "NO FILE";
311       fileFound = false;
312     }
313   }
314
315
316   /**
317    * Initialises and displays a new java.awt.Frame
318    *
319    * @param frame java.awt.Frame to be displayed
320    * @param title title of new frame
321    * @param width width if new frame
322    * @param height height of new frame
323    */
324   public static void addFrame(final Frame frame, String title, int width,
325                               int height)
326   {
327     frame.setLocation(lastFrameX, lastFrameY);
328     lastFrameX += 40;
329     lastFrameY += 40;
330     frame.setSize(width, height);
331     frame.setTitle(title);
332     frame.addWindowListener(new WindowAdapter()
333     {
334       public void windowClosing(WindowEvent e)
335       {
336         if (frame instanceof AlignFrame)
337         {
338           ( (AlignFrame) frame).closeMenuItem_actionPerformed();
339         }
340         if (currentAlignFrame == frame)
341         {
342           currentAlignFrame = null;
343         }
344         lastFrameX -= 40;
345         lastFrameY -= 40;
346         frame.setMenuBar(null);
347         frame.dispose();
348       }
349       
350       public void windowActivated(WindowEvent e)
351       {
352         if (frame instanceof AlignFrame)
353         {
354           currentAlignFrame = (AlignFrame) frame;
355           if (debug)
356           {
357             System.err.println("Activated window "+frame);
358           }
359         }
360         // be good.
361         super.windowActivated(e);
362       }
363       /* Probably not necessary to do this - see TODO above.
364        * (non-Javadoc)
365        * @see java.awt.event.WindowAdapter#windowDeactivated(java.awt.event.WindowEvent)
366        *
367       public void windowDeactivated(WindowEvent e)
368       {
369         if (currentAlignFrame == frame)
370         {
371           currentAlignFrame = null;
372           if (debug)
373           {
374             System.err.println("Deactivated window "+frame);
375           }
376         }
377         super.windowDeactivated(e);
378       }
379        */
380     });
381     frame.setVisible(true);
382   }
383
384   /**
385    * This paints the background surrounding the "Launch Jalview button"
386    * <br>
387    * <br>If file given in parameter not found, displays error message
388    *
389    * @param g graphics context
390    */
391   public void paint(Graphics g)
392   {
393     if (!fileFound)
394     {
395       g.setColor(new Color(200, 200, 200));
396       g.setColor(Color.cyan);
397       g.fillRect(0, 0, getSize().width, getSize().height);
398       g.setColor(Color.red);
399       g.drawString("Jalview can't open file", 5, 15);
400       g.drawString("\"" + file + "\"", 5, 30);
401     }
402     else if (embedded)
403     {
404       g.setColor(Color.black);
405       g.setFont(new Font("Arial", Font.BOLD, 24));
406       g.drawString("Jalview Applet", 50, this.getSize().height / 2 - 30);
407       g.drawString("Loading Data...", 50, this.getSize().height / 2);
408     }
409   }
410
411
412   class LoadJmolThread extends Thread
413   {
414     public void run()
415     {
416       try
417       {
418         if (!System.getProperty("java.version").startsWith("1.1"))
419         {
420           Class.forName("org.jmol.adapter.smarter.SmarterJmolAdapter");
421           jmolAvailable = true;
422         }
423       }
424       catch (java.lang.ClassNotFoundException ex)
425       {
426         System.out.println("Jmol not available - Using MCview for structures");
427       }
428     }
429   }
430
431
432   class LoadingThread
433       extends Thread
434   {
435     String file;
436     String protocol;
437     String format;
438     JalviewLite applet;
439
440     public LoadingThread(String _file,
441                          JalviewLite _applet)
442     {
443       if (applet.debug)
444       {
445         System.err.println("Loading thread started with:\n>>file\n"+_file+">>endfile");
446       }
447       file = _file;
448       if (file.startsWith("PASTE"))
449       {
450         file = file.substring(5);
451         protocol = AppletFormatAdapter.PASTE;
452       }
453       else if (inArchive(file))
454       {
455         protocol = AppletFormatAdapter.CLASSLOADER;
456       }
457       else
458       {
459         file = addProtocol(file);
460         protocol = AppletFormatAdapter.URL;
461       }
462       if (applet.debug)
463       {
464         System.err.println("Protocol identified as '"+protocol+"'");
465       }
466       format = new jalview.io.IdentifyFile().Identify(file, protocol);
467       if (applet.debug)
468       {
469         System.err.println("File identified as '"+format+"'");
470       }
471       applet = _applet;
472     }
473
474     public void run()
475     {
476       startLoading();
477     }
478
479     private void startLoading()
480     {
481       Alignment al = null;
482       try
483       {
484         al = new AppletFormatAdapter().readFile(file, protocol,
485                                                 format);
486       }
487       catch (java.io.IOException ex)
488       {
489         ex.printStackTrace();
490       }
491       if ( (al != null) && (al.getHeight() > 0))
492       {
493         initialAlignFrame =  new AlignFrame(al,
494                                            applet,
495                                            file,
496                                            embedded);
497         // update the focus.
498         currentAlignFrame = initialAlignFrame;
499
500         if (protocol == jalview.io.AppletFormatAdapter.PASTE)
501         {
502           currentAlignFrame.setTitle("Sequences from " + getDocumentBase());
503         }
504
505         currentAlignFrame.statusBar.setText("Successfully loaded file " + file);
506
507         String treeFile = applet.getParameter("tree");
508         if (treeFile == null)
509         {
510           treeFile = applet.getParameter("treeFile");
511         }
512
513         if (treeFile != null)
514         {
515           try
516           {
517             if (inArchive(treeFile))
518             {
519               protocol = AppletFormatAdapter.CLASSLOADER;
520             }
521             else
522             {
523               protocol = AppletFormatAdapter.URL;
524               treeFile = addProtocol(treeFile);
525             }
526
527             jalview.io.NewickFile fin = new jalview.io.NewickFile(treeFile,
528                 protocol);
529
530             fin.parse();
531
532             if (fin.getTree() != null)
533             {
534               currentAlignFrame.loadTree(fin, treeFile);
535             }
536           }
537           catch (Exception ex)
538           {
539             ex.printStackTrace();
540           }
541         }
542
543         String param = getParameter("features");
544         if (param != null)
545         {
546           if (!inArchive(param))
547           {
548             param = addProtocol(param);
549           }
550
551           currentAlignFrame.parseFeaturesFile(param, protocol);
552         }
553
554         param = getParameter("showFeatureSettings");
555         if (param != null && param.equalsIgnoreCase("true"))
556         {
557           currentAlignFrame.viewport.showSequenceFeatures(true);
558           new FeatureSettings(currentAlignFrame.alignPanel);
559         }
560
561         param = getParameter("annotations");
562         if (param != null)
563         {
564           if (!inArchive(param))
565           {
566             param = addProtocol(param);
567           }
568
569           new AnnotationFile().readAnnotationFile(
570               currentAlignFrame.viewport.getAlignment(),
571               param,
572               protocol);
573
574           currentAlignFrame.alignPanel.fontChanged();
575           currentAlignFrame.alignPanel.setScrollValues(0, 0);
576
577         }
578
579         param = getParameter("jnetfile");
580         if (param != null)
581         {
582           try
583           {
584             if (inArchive(param))
585             {
586               protocol = AppletFormatAdapter.CLASSLOADER;
587             }
588             else
589             {
590               protocol = AppletFormatAdapter.URL;
591               param = addProtocol(param);
592             }
593
594             jalview.io.JPredFile predictions = new jalview.io.JPredFile(
595                 param, protocol);
596             new JnetAnnotationMaker().add_annotation(predictions,
597                 currentAlignFrame.viewport.getAlignment(),
598                 0, false); // do not add sequence profile from concise output
599             currentAlignFrame.alignPanel.fontChanged();
600             currentAlignFrame.alignPanel.setScrollValues(0, 0);
601           }
602           catch (Exception ex)
603           {
604             ex.printStackTrace();
605           }
606         }
607
608         /*
609          <param name="PDBfile" value="1gaq.txt PDB|1GAQ|1GAQ|A PDB|1GAQ|1GAQ|B PDB|1GAQ|1GAQ|C">
610
611          <param name="PDBfile2" value="1gaq.txt A=SEQA B=SEQB C=SEQB">
612
613          <param name="PDBfile3" value="1q0o Q45135_9MICO">
614         */
615
616
617         int pdbFileCount = 0;
618         do{
619           if (pdbFileCount > 0)
620             param = getParameter("PDBFILE" + pdbFileCount);
621           else
622             param = getParameter("PDBFILE");
623
624           if (param != null)
625           {
626             PDBEntry pdb = new PDBEntry();
627
628             String seqstring;
629             SequenceI[] seqs = null;
630             String [] chains = null;
631
632             StringTokenizer st = new StringTokenizer(param, " ");
633
634             if (st.countTokens() < 2)
635             {
636               String sequence = applet.getParameter("PDBSEQ");
637               if (sequence != null)
638                 seqs = new SequenceI[]
639                     {
640                     (Sequence) currentAlignFrame.
641                     getAlignViewport().getAlignment().
642                     findName(sequence)};
643
644             }
645             else
646             {
647               param = st.nextToken();
648               Vector tmp = new Vector();
649               Vector tmp2 = new Vector();
650
651               while (st.hasMoreTokens())
652               {
653                 seqstring = st.nextToken();
654                 StringTokenizer st2 = new StringTokenizer(seqstring,"=");
655                 if(st2.countTokens()>1)
656                 {
657                   //This is the chain
658                   tmp2.addElement(st2.nextToken());
659                   seqstring = st2.nextToken();
660                 }
661                 tmp.addElement( (Sequence) currentAlignFrame.
662                                  getAlignViewport().getAlignment().
663                                  findName(seqstring));
664               }
665
666               seqs = new SequenceI[tmp.size()];
667               tmp.copyInto(seqs);
668               if(tmp2.size()==tmp.size())
669               {
670                 chains = new String[tmp2.size()];
671                 tmp2.copyInto(chains);
672               }
673             }
674
675             if (inArchive(param) && !jmolAvailable)
676             {
677               protocol = AppletFormatAdapter.CLASSLOADER;
678             }
679             else
680             {
681               protocol = AppletFormatAdapter.URL;
682               param = addProtocol(param);
683             }
684
685             pdb.setFile(param);
686
687             if(seqs!=null)
688             {
689               for (int i = 0; i < seqs.length; i++)
690               {
691                 ( (Sequence) seqs[i]).addPDBId(pdb);
692               }
693
694               if (jmolAvailable)
695               {
696                 new jalview.appletgui.AppletJmol(pdb,
697                                                  seqs,
698                                                  chains,
699                                                  currentAlignFrame.alignPanel,
700                                                  protocol);
701                 lastFrameX += 40;
702                 lastFrameY+=40;
703               }
704               else
705                     new MCview.AppletPDBViewer(pdb,
706                                            seqs,
707                                            chains,
708                                            currentAlignFrame.alignPanel,
709                                            protocol);
710             }
711           }
712
713           pdbFileCount++;
714         }
715         while(pdbFileCount < 10);
716         
717         /////////////////////////////
718         // modify display of features
719         //
720         // hide specific groups
721         param = getParameter("hidefeaturegroups");
722         if (param != null)
723         {
724           applet.setFeatureGroupState(param, false);
725         }
726         // show specific groups
727         param = getParameter("showfeaturegroups");
728         if (param != null)
729         {
730           applet.setFeatureGroupState(param, true);
731         }
732       }
733       else
734       {
735         fileFound = false;
736         remove(launcher);
737         repaint();
738       }
739     }
740
741     /**
742      * Discovers whether the given file is in the Applet Archive
743      * @param file String
744      * @return boolean
745      */
746     boolean inArchive(String file)
747     {
748       //This might throw a security exception in certain browsers
749       //Netscape Communicator for instance.
750       try
751       {
752         return (getClass().getResourceAsStream("/" + file) != null);
753       }
754       catch (Exception ex)
755       {
756         System.out.println("Exception checking resources: " + file + " " + ex);
757         return false;
758       }
759     }
760
761     String addProtocol(String file)
762     {
763       if (file.indexOf("://") == -1)
764       {
765         file = getCodeBase() + file;
766       }
767
768       return file;
769     }
770   }
771   /**
772    * @return the default alignFrame acted on by the public applet methods.
773    * May return null with an error message on System.err indicating the fact. 
774    */
775   protected AlignFrame getDefaultTargetFrame()
776   {
777     if (currentAlignFrame!=null)
778     {
779       return currentAlignFrame;
780     }
781     if (initialAlignFrame!=null)
782     {
783       return initialAlignFrame;
784     }
785     System.err.println("Implementation error: Jalview Applet API cannot work out which AlignFrame to use.");
786     return null;
787   }
788   /**
789    * separator used for separatorList
790    */
791   protected String separator = "|"; // this is a safe(ish) separator - tabs don't work for firefox
792   /**
793    * parse the string into a list
794    * @param list
795    * @return elements separated by separator
796    */
797   public String[] separatorListToArray(String list)
798   {
799     int seplen = separator.length();
800     if (list==null || list.equals(""))
801       return null;
802     java.util.Vector jv = new Vector();
803     int cp=0,pos;
804     while ((pos=list.indexOf(separator,cp))>cp)
805     {
806       jv.addElement(list.substring(cp,pos));
807       cp = pos+seplen;
808     }
809     if (cp<list.length())
810     {
811       jv.addElement(list.substring(cp));
812     }
813     if (jv.size()>0)
814     { String[] v = new String[jv.size()];
815       for (int i=0; i<v.length; i++)
816       {
817         v[i] = (String) jv.elementAt(i);
818       }
819       jv.removeAllElements();
820       if (debug)
821       {
822         System.err.println("Array from '"+separator+"' separated List:\n"+v.length);
823         for (int i=0; i<v.length;i++)
824         {
825           System.err.println("item "+i+" '"+v[i]+"'");
826         }
827       }
828       return v;
829     }
830     if (debug)
831     {
832       System.err.println("Empty Array from '"+separator+"' separated List");
833     }
834     return null;
835   }
836   /**
837    * concatenate the list with separator
838    * @param list
839    * @return concatenated string
840    */
841   public String arrayToSeparatorList(String[] list)
842   {
843     StringBuffer v = new StringBuffer();
844     if (list!=null)
845     {
846       for (int i=0,iSize=list.length-1;i<iSize;i++)
847       { 
848         if (list[i]!=null)
849         {  
850           v.append(list[i]); 
851         }
852         v.append(separator);
853       }
854       if (list[list.length-1]!=null)
855       { v.append(list[list.length-1]);
856       }
857       if (debug)
858       {
859         System.err.println("Returning '"+separator+"' separated List:\n");
860         System.err.println(v);
861       }
862       return v.toString();
863     }
864     if (debug)
865     {
866       System.err.println("Returning empty '"+separator+"' separated List\n");
867     }
868     return "";
869   }
870   /**
871    * @return
872    * @see jalview.appletgui.AlignFrame#getFeatureGroups()
873    */
874   public String getFeatureGroups()
875   {
876     String lst = arrayToSeparatorList(getDefaultTargetFrame().getFeatureGroups());
877     return lst;
878   }
879   /**
880    * @param alf alignframe to get feature groups on
881    * @return
882    * @see jalview.appletgui.AlignFrame#getFeatureGroups()
883    */
884   public String getFeatureGroupsOn(AlignFrame alf)
885   {
886     String lst = arrayToSeparatorList(alf.getFeatureGroups());
887     return lst;
888   }
889   /**
890    * @param visible
891    * @return
892    * @see jalview.appletgui.AlignFrame#getFeatureGroupsOfState(boolean)
893    */
894   public String getFeatureGroupsOfState(boolean visible)
895   {
896     return arrayToSeparatorList(getDefaultTargetFrame().getFeatureGroupsOfState(visible));
897   }
898   /**
899    * @param alf align frame to get groups of state visible
900    * @param visible
901    * @return
902    * @see jalview.appletgui.AlignFrame#getFeatureGroupsOfState(boolean)
903    */
904   public String getFeatureGroupsOfStateOn(AlignFrame alf, boolean visible)
905   {
906     return arrayToSeparatorList(alf.getFeatureGroupsOfState(visible));
907   }  /**
908    * @param groups tab separated list of group names 
909    * @param state true or false
910    * @see jalview.appletgui.AlignFrame#setFeatureGroupState(java.lang.String[], boolean)
911    */
912   public void setFeatureGroupStateOn(AlignFrame alf, String groups, boolean state)
913   {
914     boolean st = state;//!(state==null || state.equals("") || state.toLowerCase().equals("false"));
915     alf.setFeatureGroupState(separatorListToArray(groups), st);
916   }
917   public void setFeatureGroupState(String groups, boolean state)
918   {
919     setFeatureGroupStateOn(getDefaultTargetFrame(), groups, state);
920   }
921   /**
922    * List separator string
923    * @return the separator
924    */
925   public String getSeparator()
926   {
927     return separator;
928   }
929   /**
930    * List separator string
931    * @param separator the separator to set
932    */
933   public void setSeparator(String separator)
934   {
935     this.separator = separator;
936   }
937 }