Merge remote-tracking branch 'origin/merge/Jalview-JS/develop_feature/JAL-3690_callba...
[jalview.git] / src / jalview / bin / JalviewJSApp.java
1 package jalview.bin;
2
3 import java.awt.EventQueue;
4 //import java.applet.AppletContext;
5 import java.io.IOException;
6 import java.net.URL;
7 import java.util.ArrayList;
8 import java.util.List;
9 import java.util.StringTokenizer;
10 import java.util.Vector;
11
12 import javax.swing.SwingUtilities;
13
14 import jalview.api.JalviewJSApi;
15 import jalview.api.StructureSelectionManagerProvider;
16 import jalview.datamodel.Alignment;
17 import jalview.datamodel.AlignmentI;
18 import jalview.datamodel.AlignmentOrder;
19 import jalview.datamodel.ColumnSelection;
20 import jalview.datamodel.HiddenColumns;
21 import jalview.datamodel.PDBEntry;
22 import jalview.datamodel.Sequence;
23 import jalview.datamodel.SequenceGroup;
24 import jalview.datamodel.SequenceI;
25 import jalview.gui.AlignFrame;
26 import jalview.gui.AlignViewport;
27 import jalview.gui.CalculationChooser;
28 import jalview.gui.Desktop;
29 import jalview.gui.StructureViewer;
30 import jalview.io.AnnotationFile;
31 import jalview.io.AppletFormatAdapter;
32 import jalview.io.DataSourceType;
33 import jalview.io.FeaturesFile;
34 import jalview.io.FileFormat;
35 import jalview.io.FileFormatI;
36 import jalview.io.FileFormats;
37 import jalview.io.IdentifyFile;
38 import jalview.io.JPredFile;
39 import jalview.io.JnetAnnotationMaker;
40 import jalview.io.NewickFile;
41 import jalview.structure.SelectionListener;
42 import jalview.structure.SelectionSource;
43 import jalview.structure.StructureSelectionManager;
44 import jalview.util.HttpUtils;
45 import jalview.util.Platform;
46
47 /**
48  * Basically the JalviewLite application, but without JalviewLite
49  * 
50  * Processing all "applet parameters" and also all "applet interface" methods.
51  * 
52  * @author hansonr
53  *
54  */
55 public class JalviewJSApp implements JalviewJSApi
56 {
57   private ArgsParser aparser;
58
59   private String[] ret = new String[1];
60
61   // private boolean alignPDBStructures; From JalviewLite; not implemented
62
63   private String separator = "\u00AC"; // JalviewLite note: the default used to
64                                        // be '|', but many sequence IDS include
65                                        // pipes.
66
67   /**
68    * We maintain a pointer to the jalview instance here, because only with that
69    * do we have a direct connection from the JavaScript "applet" object to the
70    * proper instance of Jalview in case there are multiple applets on a page.
71    */
72   private Jalview jalview;
73
74   public class JsSelectionListener
75           implements jalview.structure.SelectionListener
76   {
77
78     AlignFrame _alf;
79
80     String _listener;
81
82     public JsSelectionListener(AlignFrame alf, String listener)
83     {
84       _alf = alf;
85       _listener = listener;
86     }
87
88     public boolean isFor(AlignFrame alf, String listener)
89     {
90       return (_alf == null || _alf == alf) && _listener.equals(listener);
91     }
92
93     @Override
94     public void selection(SequenceGroup seqsel, ColumnSelection colsel,
95             HiddenColumns hidden, SelectionSource source)
96     {
97       // System.err.println("Testing selection event relay to
98       // jsfunction:"+_listener);
99       String setid = "";
100       AlignFrame srcFrame = (_alf == null ? getCurrentAlignFrame() : _alf);
101       if (source != null)
102       {
103         if (source instanceof AlignViewport
104                 && srcFrame.getViewport() != source)
105         {
106           return;
107         }
108       }
109       String[] seqs = new String[] {};
110       String[] cols = new String[] {};
111       int strt = 0, end = (srcFrame == null) ? -1
112               : srcFrame.alignPanel.av.getAlignment().getWidth();
113       if (seqsel != null && seqsel.getSize() > 0)
114       {
115         seqs = new String[seqsel.getSize()];
116         for (int i = 0; i < seqs.length; i++)
117         {
118           seqs[i] = seqsel.getSequenceAt(i).getName();
119         }
120         if (strt < seqsel.getStartRes())
121         {
122           strt = seqsel.getStartRes();
123         }
124         if (end == -1 || end > seqsel.getEndRes())
125         {
126           end = seqsel.getEndRes();
127         }
128       }
129       if (colsel != null && !colsel.isEmpty())
130       {
131         if (end == -1)
132         {
133           end = colsel.getMax() + 1;
134         }
135         cols = new String[colsel.getSelected().size()];
136         for (int i = 0; i < cols.length; i++)
137         {
138           cols[i] = "" + (1 + colsel.getSelected().get(i).intValue());
139         }
140       }
141       else
142       {
143         if (seqsel != null && seqsel.getSize() > 0)
144         {
145           // send a valid range, otherwise we send the empty selection
146           cols = new String[1];
147           cols[0] = "" + (1 + strt) + "-" + (1 + end);
148         }
149       }
150       doSendCallback(_listener,
151               new Object[]
152               { Jalview.getInstance().j2sAppletID, srcFrame, source, setid,
153                   seqs, cols });
154     }
155
156   }
157
158   public JalviewJSApp(Jalview jalview, ArgsParser aparser)
159   {
160     Platform.setAppClass(this);
161     this.jalview = jalview;
162     this.aparser = aparser;
163   }
164
165   @Override
166   public boolean addPdbFile(String sequenceId, String pdbId, String pdbFile,
167           AlignFrame alf)
168   {
169     if (alf == null)
170     {
171       alf = getCurrentAlignFrame();
172     }
173     SequenceI seq = alf.getViewport().getAlignment().findName(sequenceId);
174     if (seq != null)
175     {
176       Vector<PDBEntry> pdbe = seq.getAllPDBEntries();
177       PDBEntry pdbentry = null;
178       if (pdbe != null && pdbe.size() > 0)
179       {
180         for (int pe = 0, peSize = pdbe.size(); pe < peSize; pe++)
181         {
182           pdbentry = pdbe.elementAt(pe);
183           if (!pdbentry.getId().equals(pdbId)
184                   || pdbFile != null && !pdbentry.getFile().equals(pdbFile))
185           {
186             pdbentry = null;
187           }
188         }
189       }
190       if (pdbentry == null)
191       {
192         pdbentry = new PDBEntry(pdbId, null, pdbFile);
193         if (pdbFile != null)
194         {
195           DataSourceType protocol = AppletFormatAdapter
196                   .resolveProtocol(pdbFile, FileFormat.PDB);
197           if (protocol == null)
198             return false;
199           pdbentry.setProperty("protocol", protocol);
200         }
201         seq.addPDBId(pdbentry);
202         alf.alignPanel.getStructureSelectionManager()
203                 .registerPDBEntry(pdbentry);
204       }
205     }
206     return true;
207   }
208
209   @Override
210   public String getAlignment(String format, boolean addSuffix,
211           AlignFrame alf)
212   {
213     try
214     {
215       if (alf == null)
216       {
217         alf = getCurrentAlignFrame();
218       }
219
220       FileFormatI theFormat = FileFormats.getInstance().forName(format);
221       String reply = new AppletFormatAdapter().formatSequences(theFormat,
222               alf.getViewport().getAlignment(), addSuffix);
223       return reply;
224     } catch (IllegalArgumentException ex)
225     {
226       ex.printStackTrace();
227       return "Error retrieving alignment, possibly invalid format specifier: "
228               + format;
229     }
230   }
231
232   @Override
233   public String[] getAlignmentOrder(AlignFrame alf)
234   {
235     if (alf == null)
236     {
237       alf = getCurrentAlignFrame();
238     }
239     AlignmentI alorder = alf.getViewport().getAlignment();
240     String[] order = new String[alorder.getHeight()];
241     for (int i = 0; i < order.length; i++)
242     {
243       order[i] = alorder.getSequenceAt(i).getName();
244     }
245     return order;// arrayToSeparatorList(order, sep);
246   }
247
248   @Override
249   public String getAnnotation(AlignFrame alf)
250   {
251     if (alf == null)
252     {
253       alf = getCurrentAlignFrame();
254     }
255     String annotation = new AnnotationFile()
256             .printAnnotationsForView(alf.getViewport());
257     return annotation;
258   }
259
260   /**
261    * Get the applet-like code base even though this is an application.
262    */
263
264   @Override
265   public URL getCodeBase()
266   {
267     return Platform.getCodeBase();
268   }
269
270   @Override
271   public AlignFrame getCurrentAlignFrame()
272   {
273     // if (jalview != Jalview.getInstance() || jalview.currentAlignFrame !=
274     // Jalview.getCurrentAlignFrame()) {
275     // /** @j2sNative debugger */
276     // }
277     return jalview.currentAlignFrame;
278   }
279
280   /**
281    * Get the applet-like document base even though this is an application.
282    */
283
284   @Override
285   public URL getDocumentBase()
286   {
287     return Platform.getDocumentBase();
288   }
289
290   @Override
291   public String[] getFeatureGroups(AlignFrame alf)
292   {
293     if (alf == null)
294     {
295       alf = getCurrentAlignFrame();
296     }
297     return alf.getFeatureGroups();
298   }
299
300   @Override
301   public String[] getFeatureGroupsOfState(boolean visible, AlignFrame alf)
302   {
303     if (alf == null)
304     {
305       alf = getCurrentAlignFrame();
306     }
307     return alf.getFeatureGroupsOfState(visible);
308   }
309
310   /**
311    * JavaScript interface to print the alignment frame
312    * 
313    * @param format
314    *          "jalview" or "gff" with or without ";includeComplement" or
315    *          ";includeNonpositional"; default with no ";" is
316    *          ";includeNonpositional"
317    * @param alf
318    * 
319    * @return
320    */
321   @Override
322   public String getFeatures(String format, AlignFrame alf)
323   {
324     if (alf == null)
325     {
326       alf = getCurrentAlignFrame();
327     }
328     String features;
329     FeaturesFile formatter = new FeaturesFile();
330     format = format.toLowerCase();
331     if (format.indexOf(";") < 0)
332       format += ";includenonpositional";
333     boolean nonpos = format.indexOf(";includenonpositional") >= 0;
334     boolean compl = format.indexOf(";includecomplement") >= 0;
335     if (format.startsWith("jalview"))
336     {
337       features = formatter.printJalviewFormat(
338               alf.getViewport().getAlignment().getSequencesArray(),
339               alf.alignPanel.getFeatureRenderer(), nonpos, compl);
340     }
341     else
342     {
343       features = formatter.printGffFormat(
344               alf.getViewport().getAlignment().getSequencesArray(),
345               alf.alignPanel.getFeatureRenderer(), nonpos, compl);
346     }
347
348     if (features == null)
349     {
350       features = "";
351     }
352     return features;
353
354   }
355
356   /**
357    * Get an applet parameter as a string.
358    * 
359    */
360   @Override
361   public String getParameter(String name)
362   {
363     return (String) aparser.getAppletValue(name, null, true);
364   }
365
366   /**
367    * Get an applet parameter as an Object.
368    */
369
370   @Override
371   public Object getParameterAsObject(String name)
372   {
373     return aparser.getAppletValue(name, null, false);
374   }
375
376   /**
377    * read sequence1...sequenceN as a raw alignment
378    * 
379    * @param jalviewApp
380    * @return
381    */
382   public String getPastedSequence(JalviewJSApp jalviewApp)
383   {
384     StringBuffer data = new StringBuffer("PASTE");
385     int i = 1;
386     String file = null;
387     while ((file = getParameter("sequence" + i)) != null)
388     {
389       data.append(file.toString() + "\n");
390       i++;
391     }
392     if (data.length() > 5)
393     {
394       file = data.toString();
395     }
396     return file;
397   }
398
399   /**
400    * @j2sAlias getSelectedSequences
401    * 
402    * @see jalview.appletgui.js.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui
403    *      .AlignFrame)
404    */
405   @Override
406   public SequenceI[] getSelectedSequences(AlignFrame alf)
407   {
408     // return getSelectedSequencesFrom(alf, null);
409     // }
410     //
411     // @Override
412     // public SequenceI[] getSelectedSequencesFrom(AlignFrame alf, String sep)
413     // {
414     if (alf == null)
415     {
416       alf = getCurrentAlignFrame();
417     }
418     AlignViewport v = alf.getViewport();
419     if (v.getSelectionGroup() != null)
420     {
421       return v.getSelectionGroup().getSequencesInOrder(v.getAlignment());
422     }
423     return null;
424   }
425   // /**
426   // *
427   // * @see
428   // jalview.appletgui.js.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui
429   // * .AlignFrame, java.lang.String)
430   // */
431   // @Override
432   // public void highlight(String sequenceId, String position,
433   // String alignedPosition)
434   // {
435   // highlightIn(null, sequenceId, position, alignedPosition);
436   // }
437
438   /**
439    * @j2sAlias getSelectedSequencesAsAlignment
440    */
441   @Override
442   public String getSelectedSequencesAsAlignment(String format,
443           boolean addSuffix, AlignFrame alf)
444   {
445
446     if (alf == null)
447     {
448       alf = getCurrentAlignFrame();
449     }
450     try
451     {
452       AlignViewport vp = alf.getViewport();
453       FileFormatI theFormat = FileFormats.getInstance().forName(format);
454       if (vp.getSelectionGroup() != null)
455       {
456         // JBPNote: getSelectionAsNewSequence behaviour has changed - this
457         // method now returns a full copy of sequence data
458         // TODO consider using getSequenceSelection instead here
459         String reply = new AppletFormatAdapter().formatSequences(theFormat,
460                 new Alignment(vp.getSelectionAsNewSequence()), addSuffix);
461         return reply;
462       }
463     } catch (IllegalArgumentException ex)
464     {
465       ex.printStackTrace();
466       return "Error retrieving alignment, possibly invalid format specifier: "
467               + format;
468     }
469     return "";
470   }
471
472   @Override
473   public void highlight(String sequenceId, String position,
474           String alignedPosition, AlignFrame alf)
475   {
476     if (alf == null)
477     {
478       alf = getCurrentAlignFrame();
479     }
480     // TODO: could try to highlight in all alignments if alf==null
481     jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher(
482             alf.getViewport().getAlignment().getSequencesArray());
483     final SequenceI sq = matcher.findIdMatch(sequenceId);
484     if (sq != null)
485     {
486       int apos = -1;
487       try
488       {
489         apos = Integer.valueOf(position).intValue();
490         apos--;
491       } catch (NumberFormatException ex)
492       {
493         return;
494       }
495       final int pos = apos;
496       // use vamsas listener to broadcast to all listeners in scope
497       if (alignedPosition != null && (alignedPosition.trim().length() == 0
498               || alignedPosition.toLowerCase().indexOf("false") > -1))
499       {
500         java.awt.EventQueue.invokeLater(new Runnable()
501         {
502           @Override
503           public void run()
504           {
505             StructureSelectionManager
506                     .getStructureSelectionManager(Desktop.getInstance())
507                     .mouseOverVamsasSequence(sq, sq.findIndex(pos), null);
508           }
509         });
510       }
511       else
512       {
513         java.awt.EventQueue.invokeLater(new Runnable()
514         {
515           @Override
516           public void run()
517           {
518             StructureSelectionManager
519                     .getStructureSelectionManager(Desktop.getInstance())
520                     .mouseOverVamsasSequence(sq, pos, null);
521           }
522         });
523       }
524     }
525   }
526
527   @Override
528   public AlignFrame loadAlignment(String text, String title, int width,
529           int height)
530   {
531     AlignmentI al = null;
532
533     try
534     {
535       FileFormatI format = new IdentifyFile().identify(text,
536               DataSourceType.PASTE);
537       al = new AppletFormatAdapter().readFile(text, DataSourceType.PASTE,
538               format);
539       if (al.getHeight() > 0)
540       {
541         return new AlignFrame(al,
542                 width > 0 ? width : AlignFrame.DEFAULT_WIDTH,
543                 height > 0 ? height : AlignFrame.DEFAULT_HEIGHT, title);
544       }
545     } catch (IOException ex)
546     {
547       ex.printStackTrace();
548     }
549     return null;
550   }
551
552   @Override
553   public void loadAnnotation(String annotation, AlignFrame alf)
554   {
555     if (alf == null)
556     {
557       alf = getCurrentAlignFrame();
558     }
559     if (new AnnotationFile().annotateAlignmentView(alf.getViewport(),
560             annotation, DataSourceType.PASTE))
561     {
562       alf.alignPanel.fontChanged();
563       alf.alignPanel.setScrollValues(0, 0);
564     }
565     else
566     {
567       alf.parseFeaturesFile(annotation, DataSourceType.PASTE);
568     }
569   }
570
571   @Override
572   public boolean loadFeatures(String features, boolean autoenabledisplay,
573           AlignFrame alf)
574   {
575     if (alf == null)
576     {
577       alf = getCurrentAlignFrame();
578     }
579     boolean ret = alf.parseFeaturesFile(features, DataSourceType.PASTE);
580     if (!ret)
581     {
582       return false;
583     }
584     if (autoenabledisplay)
585     {
586       alf.getViewport().setShowSequenceFeatures(true);
587       // this next was for a checkbox in JalviewLite
588       // ((AlignFrame) alf).getViewport().sequenceFeatures.setState(true);
589     }
590     return true;
591   }
592
593   @Override
594   public boolean loadScoreFile(String fileName, AlignFrame alf)
595   {
596     try
597     {
598       (alf == null ? getCurrentAlignFrame() : alf)
599               .loadJalviewDataFile(fileName, null, null, null);
600       return true;
601     } catch (Throwable t)
602     {
603       return false;
604     }
605   }
606
607   /**
608    * @j2sAlias openPcaPanel
609    * 
610    *           public static method for JalviewJS API to open a PCAPanel without
611    *           necessarily using a dialog.
612    * @param modelName
613    * @param alf
614    * 
615    * @return the PCAPanel, or the string "label.you_need_at_least_n_sequences"
616    *         if number of sequences selected is inappropriate
617    */
618   @Override
619   public Object openPcaPanel(String modelName, AlignFrame alf)
620   {
621     if (alf == null)
622     {
623       alf = getCurrentAlignFrame();
624     }
625     return CalculationChooser.openPcaPanel(alf, modelName, null);
626   }
627
628   /**
629    * @j2sAlias openTreePanel
630    * 
631    *           Open a new Tree panel on the desktop statically. Params are
632    *           standard (not set by Groovy). No dialog is opened.
633    * @param treeType
634    * @param modelName
635    * @param alf
636    * 
637    * @return null, or the string "label.you_need_at_least_n_sequences" if number
638    *         of sequences selected is inappropriate
639    */
640   @Override
641   public Object openTreePanel(String treeType, String modelName,
642           AlignFrame alf)
643   {
644     if (alf == null)
645     {
646       alf = getCurrentAlignFrame();
647     }
648     return CalculationChooser.openTreePanel(alf, treeType, modelName, null);
649   }
650
651   @Override
652   public boolean orderAlignment(String[] ids, String undoName,
653           AlignFrame alf)
654   {
655     if (alf == null)
656       alf = getCurrentAlignFrame();
657     SequenceI[] sqs = null;
658     if (ids != null && ids.length > 0)
659     {
660       jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher(
661               alf.getViewport().getAlignment().getSequencesArray());
662       int s = 0;
663       sqs = new SequenceI[ids.length];
664       for (int i = 0; i < ids.length; i++)
665       {
666         if (ids[i].trim().length() == 0)
667         {
668           continue;
669         }
670         SequenceI sq = matcher.findIdMatch(ids[i]);
671         if (sq != null)
672         {
673           sqs[s++] = sq;
674         }
675       }
676       if (s > 0)
677       {
678         SequenceI[] sqq = new SequenceI[s];
679         System.arraycopy(sqs, 0, sqq, 0, s);
680         sqs = sqq;
681       }
682       else
683       {
684         sqs = null;
685       }
686     }
687     if (sqs == null)
688     {
689       return false;
690     }
691     ;
692     final AlignmentOrder aorder = new AlignmentOrder(sqs);
693
694     if (undoName != null && undoName.trim().length() == 0)
695     {
696       undoName = null;
697     }
698     final String _undoName = undoName;
699     // TODO: deal with synchronization here: cannot raise any events until
700     // alfter
701     // this has returned.
702     return alf.sortBy(aorder, _undoName);
703   }
704
705   /**
706    * Allow an outside entity to initiate the second half of argument parsing
707    * (only).
708    * 
709    * @param args
710    * @return null is good
711    */
712   @Override
713   public Object parseArguments(String[] args)
714   {
715
716     try
717     {
718       jalview.parseArguments(new ArgsParser(args), false);
719       return null;
720     } catch (Throwable t)
721     {
722       return t;
723     }
724   }
725
726   /**
727    * @j2sAlias parseFeatureFile
728    * 
729    * @param filename
730    * @param alf
731    * @return
732    */
733   @Override
734   public boolean parseFeaturesFile(String filename, AlignFrame alf)
735   {
736     ret[0] = filename;
737     DataSourceType protocol = resolveFileProtocol(ret);
738     if (protocol == null)
739       return false;
740     return (alf == null ? getCurrentAlignFrame() : alf)
741             .parseFeaturesFile(ret[0], protocol);
742   }
743
744   @Override
745   public void removeSelectionListener(String listener, AlignFrame alf)
746   {
747
748     List<SelectionListener> listeners = Desktop
749             .getStructureSelectionManager().getListeners();
750     for (int i = listeners.size(); --i >= 0;)
751     {
752       SelectionListener l = listeners.get(i);
753       if (l instanceof JsSelectionListener
754               && ((JsSelectionListener) l).isFor(alf, listener))
755       {
756         listeners.remove(i);
757         break;
758       }
759     }
760   }
761
762   private DataSourceType resolveFileProtocol(String[] retPath)
763   {
764     String path = retPath[0];
765     /*
766      * is it paste data?
767      */
768     if (path.startsWith("PASTE"))
769     {
770       retPath[0] = path.substring(5);
771       return DataSourceType.PASTE;
772     }
773
774     /*
775      * is it a URL?
776      */
777     if (path.indexOf("://") >= 0)
778     {
779       return DataSourceType.URL;
780     }
781
782     /*
783      * try relative to document root
784      */
785     URL documentBase = getDocumentBase();
786     String withDocBase = resolveUrlForLocalOrAbsolute(path, documentBase);
787     if (HttpUtils.isValidUrl(withDocBase))
788     {
789       // if (debug)
790       // {
791       // System.err.println("Prepended document base '" + documentBase
792       // + "' to make: '" + withDocBase + "'");
793       // }
794       retPath[0] = withDocBase;
795       return DataSourceType.URL;
796     }
797
798     /*
799      * try relative to codebase (if different to document base)
800      */
801     URL codeBase = getCodeBase();
802     String withCodeBase = resolveUrlForLocalOrAbsolute(path, codeBase);
803     if (!withCodeBase.equals(withDocBase)
804             && HttpUtils.isValidUrl(withCodeBase))
805     {
806       // if (debug)
807       // {
808       // System.err.println("Prepended codebase '" + codeBase
809       // + "' to make: '" + withCodeBase + "'");
810       // }
811       retPath[0] = withCodeBase;
812       return DataSourceType.URL;
813     }
814
815     /*
816      * try locating by classloader; try this last so files in the directory
817      * are resolved using document base
818      */
819     if (inArchive(getClass(), path))
820     {
821       return DataSourceType.CLASSLOADER;
822     }
823     return null;
824   }
825
826   @Override
827   public void scrollViewTo(int topRow, int leftHandColumn, AlignFrame alf)
828   {
829     // TODO test
830     java.awt.EventQueue.invokeLater(new Runnable()
831     {
832       @Override
833       public void run()
834       {
835         try
836         {
837           (alf == null ? getCurrentAlignFrame() : alf).scrollTo(topRow,
838                   leftHandColumn);
839         } catch (Exception ex)
840         {
841           System.err.println("Couldn't parse integer arguments (topRow='"
842                   + topRow + "' and leftHandColumn='" + leftHandColumn
843                   + "')");
844           ex.printStackTrace();
845         }
846       }
847     });
848   }
849
850   @Override
851   public void select(String ids[], String cols[], AlignFrame alf)
852   {
853     if (alf == null)
854       alf = getCurrentAlignFrame();
855     final SequenceGroup sel = new SequenceGroup();
856     final ColumnSelection csel = new ColumnSelection();
857     AlignmentI al = alf.getViewport().getAlignment();
858     jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher(
859             alf.getViewport().getAlignment().getSequencesArray());
860     int start = 0, end = al.getWidth(), alw = al.getWidth();
861     boolean seqsfound = true;
862     if (ids != null && ids.length > 0)
863     {
864       seqsfound = false;
865       for (int i = 0; i < ids.length; i++)
866       {
867         if (ids[i].trim().length() == 0)
868         {
869           continue;
870         }
871         SequenceI sq = matcher.findIdMatch(ids[i]);
872         if (sq != null)
873         {
874           seqsfound = true;
875           sel.addSequence(sq, false);
876         }
877       }
878     }
879     boolean inseqpos = false;
880     if (cols != null && cols.length > 0)
881     {
882       boolean seset = false;
883       for (int i = 0; i < cols.length; i++)
884       {
885         String cl = cols[i].trim();
886         if (cl.length() == 0)
887         {
888           continue;
889         }
890         int p;
891         if ((p = cl.indexOf("-")) > -1)
892         {
893           int from = -1, to = -1;
894           try
895           {
896             from = Integer.valueOf(cl.substring(0, p)).intValue();
897             from--;
898           } catch (NumberFormatException ex)
899           {
900             System.err.println(
901                     "ERROR: Couldn't parse first integer in range element column selection string '"
902                             + cl + "' - format is 'from-to'");
903             return;
904           }
905           try
906           {
907             to = Integer.valueOf(cl.substring(p + 1)).intValue();
908             to--;
909           } catch (NumberFormatException ex)
910           {
911             System.err.println(
912                     "ERROR: Couldn't parse second integer in range element column selection string '"
913                             + cl + "' - format is 'from-to'");
914             return;
915           }
916           if (from >= 0 && to >= 0)
917           {
918             // valid range
919             if (from < to)
920             {
921               int t = to;
922               to = from;
923               to = t;
924             }
925             if (!seset)
926             {
927               start = from;
928               end = to;
929               seset = true;
930             }
931             else
932             {
933               // comment to prevent range extension
934               if (start > from)
935               {
936                 start = from;
937               }
938               if (end < to)
939               {
940                 end = to;
941               }
942             }
943             for (int r = from; r <= to; r++)
944             {
945               if (r >= 0 && r < alw)
946               {
947                 csel.addElement(r);
948               }
949             }
950           }
951           else
952           {
953             System.err.println("ERROR: Invalid Range '" + cl
954                     + "' deparsed as [" + from + "," + to + "]");
955           }
956         }
957         else
958         {
959           int r = -1;
960           try
961           {
962             r = Integer.valueOf(cl).intValue();
963             r--;
964           } catch (NumberFormatException ex)
965           {
966             if (cl.toLowerCase().equals("sequence"))
967             {
968               // we are in the dataset sequence's coordinate frame.
969               inseqpos = true;
970             }
971             else
972             {
973               System.err.println(
974                       "ERROR: Couldn't parse integer from point selection element of column selection string '"
975                               + cl + "'");
976               return;
977             }
978           }
979           if (r >= 0 && r <= alw)
980           {
981             if (!seset)
982             {
983               start = r;
984               end = r;
985               seset = true;
986             }
987             else
988             {
989               // comment to prevent range extension
990               if (start > r)
991               {
992                 start = r;
993               }
994               if (end < r)
995               {
996                 end = r;
997               }
998             }
999             csel.addElement(r);
1000           }
1001           else
1002           {
1003             System.err.println("ERROR: Invalid Point selection '" + cl
1004                     + "' deparsed as [" + r + "]");
1005           }
1006         }
1007       }
1008     }
1009     if (seqsfound)
1010     {
1011       // we only propagate the selection when it was the null selection, or the
1012       // given sequences were found in the alignment.
1013       if (inseqpos && sel.getSize() > 0)
1014       {
1015         // assume first sequence provides reference frame ?
1016         SequenceI rs = sel.getSequenceAt(0);
1017         start = rs.findIndex(start);
1018         end = rs.findIndex(end);
1019         List<Integer> cs = new ArrayList<>(csel.getSelected());
1020         csel.clear();
1021         for (Integer selectedCol : cs)
1022         {
1023           csel.addElement(rs.findIndex(selectedCol));
1024         }
1025       }
1026       sel.setStartRes(start);
1027       sel.setEndRes(end);
1028       AlignFrame af = alf;
1029       EventQueue.invokeLater(new Runnable()
1030       {
1031         @Override
1032         public void run()
1033         {
1034           af.select(sel, csel,
1035                   af.getCurrentView().getAlignment().getHiddenColumns());
1036         }
1037       });
1038     }
1039   }
1040
1041   //
1042   // @Override
1043   // public void setFeatureGroupState(String[] groups, boolean state)
1044   // {
1045   // setFeatureGroupState(null, groups, state);
1046   // }
1047   //
1048   // @Override
1049   // public void setFeatureGroupState(String[] groups, boolean state)
1050   // { // JalviewLite API
1051   // setFeatureGroupStateOn(null, groups, state);
1052   // }
1053   //
1054   @Override
1055   public void setFeatureGroupState(final String[] groups,
1056           boolean state, AlignFrame alf)
1057   {
1058     // setFeatureGroupState(alf, groups, state);
1059     // java.awt.EventQueue.invokeLater(new Runnable()
1060     // {
1061     // @Override
1062     // public void run()
1063     // {
1064     // (alf == null ? getCurrentAlignFrame() : alf)
1065     // .setFeatureGroupState(
1066     // separatorListToArray(groups, separator), state);
1067     // }
1068     // });
1069     // }
1070     //
1071     // public void setFeatureGroupState(AlignFrame alf, String[] groups, boolean
1072     // state) {
1073     (alf == null ? getCurrentAlignFrame() : alf)
1074             .setFeatureGroupState(groups, state);
1075   }
1076
1077   @Override
1078   public void setSelectionListener(String listener, AlignFrame alf)
1079   {
1080     Desktop.getStructureSelectionManager()
1081             .addSelectionListener(new JsSelectionListener(alf, listener));
1082   }
1083
1084   @Override
1085   public void showOverview()
1086   {
1087     getCurrentAlignFrame().overviewMenuItem_actionPerformed(null);
1088   }
1089
1090   /**
1091    * @j2sAlias showStructure
1092    */
1093   @Override
1094   public void showStructure(String pdbID, String fileType, AlignFrame alf)
1095   {
1096     if (alf == null)
1097       alf = getCurrentAlignFrame();
1098     PDBEntry pe = null;
1099     SequenceI[] seqs = null;
1100     if (pdbID == null)
1101     {
1102       seqs = alf.getViewport().getSequenceSelection();
1103       if (seqs.length == 0)
1104         seqs = alf.getViewport().getAlignment().getSequencesArray();
1105       for (int i = 0; i < seqs.length; i++)
1106       {
1107         Vector<PDBEntry> list = seqs[i].getAllPDBEntries();
1108         if (list.size() > 0)
1109         {
1110           pe = list.get(0);
1111           break;
1112         }
1113       }
1114     }
1115     if (pe == null)
1116     {
1117       if (pdbID == null)
1118         return;
1119       pe = new PDBEntry(pdbID, null, fileType);
1120       List<SequenceI> list = alf.getViewport().getAlignment()
1121               .getSequences();
1122       List<SequenceI> tmp = new ArrayList<SequenceI>();
1123       for (int i = 0; i < list.size(); i++)
1124       {
1125         SequenceI seq = list.get(i);
1126         if (seq.getPDBEntry(pdbID) != null)
1127         {
1128           tmp.add(seq);
1129         }
1130       }
1131       seqs = tmp.toArray(new SequenceI[tmp.size()]);
1132       alf.alignPanel.selectSequences(tmp);
1133     }
1134     StructureViewer.launchStructureViewer(alf.alignPanel, pe, seqs);
1135   }
1136
1137   // private or package-private methods
1138
1139   /**
1140    * form a complete URL given a path to a resource and a reference location on
1141    * the same server
1142    * 
1143    * @param targetPath
1144    *          - an absolute path on the same server as localref or a document
1145    *          located relative to localref
1146    * @param localref
1147    *          - a URL on the same server as url
1148    * @return a complete URL for the resource located by url
1149    */
1150   private static String resolveUrlForLocalOrAbsolute(String targetPath,
1151           URL localref)
1152   {
1153     String resolvedPath = "";
1154     if (targetPath.startsWith("/"))
1155     {
1156       String codebase = localref.toString();
1157       String localfile = localref.getFile();
1158       resolvedPath = codebase.substring(0,
1159               codebase.length() - localfile.length()) + targetPath;
1160       return resolvedPath;
1161     }
1162
1163     /*
1164      * get URL path and strip off any trailing file e.g.
1165      * www.jalview.org/examples/index.html#applets?a=b is trimmed to
1166      * www.jalview.org/examples/
1167      */
1168     String urlPath = localref.toString();
1169     String directoryPath = urlPath;
1170     int lastSeparator = directoryPath.lastIndexOf("/");
1171     if (lastSeparator > 0)
1172     {
1173       directoryPath = directoryPath.substring(0, lastSeparator + 1);
1174     }
1175
1176     if (targetPath.startsWith("/"))
1177     {
1178       /*
1179        * construct absolute URL to a file on the server - this is not allowed?
1180        */
1181       // String localfile = localref.getFile();
1182       // resolvedPath = urlPath.substring(0,
1183       // urlPath.length() - localfile.length())
1184       // + targetPath;
1185       resolvedPath = directoryPath + targetPath.substring(1);
1186     }
1187     else
1188     {
1189       resolvedPath = directoryPath + targetPath;
1190     }
1191     // if (debug)
1192     // {
1193     // System.err.println(
1194     // "resolveUrlForLocalOrAbsolute returning " + resolvedPath);
1195     // }
1196     return resolvedPath;
1197   }
1198
1199   /**
1200    * parse the string into a list
1201    * 
1202    * @param list
1203    * @param separator
1204    * @return elements separated by separator
1205    */
1206   private static String[] separatorListToArray(String list,
1207           String separator)
1208   {
1209     // TODO use StringUtils version (slightly different...)
1210     int seplen = separator.length();
1211     if (list == null || list.equals("") || list.equals(separator))
1212     {
1213       return null;
1214     }
1215     Vector<String> jv = new Vector<>();
1216     int cp = 0, pos;
1217     while ((pos = list.indexOf(separator, cp)) > cp)
1218     {
1219       jv.addElement(list.substring(cp, pos));
1220       cp = pos + seplen;
1221     }
1222     if (cp < list.length())
1223     {
1224       String c = list.substring(cp);
1225       if (!c.equals(separator))
1226       {
1227         jv.addElement(c);
1228       }
1229     }
1230     if (jv.size() > 0)
1231     {
1232       String[] v = new String[jv.size()];
1233       for (int i = 0; i < v.length; i++)
1234       {
1235         v[i] = jv.elementAt(i);
1236       }
1237       jv.removeAllElements();
1238       return v;
1239     }
1240     return null;
1241   }
1242
1243   /**
1244    * Discovers whether the given file is in the Applet Archive
1245    * 
1246    * @param f
1247    *          String
1248    * @return boolean
1249    */
1250   private static boolean inArchive(Class<?> c, String f)
1251   {
1252     // This might throw a security exception in certain browsers
1253     // Netscape Communicator for instance.
1254     try
1255     {
1256       boolean rtn = (c.getResourceAsStream("/" + f) != null);
1257       return rtn;
1258     } catch (Exception ex)
1259     {
1260       System.out.println("Exception checking resources: " + f + " " + ex);
1261       return false;
1262     }
1263   }
1264
1265   /**
1266    * Allowing for a JavaScript function here.
1267    */
1268   void callInitCallback()
1269   {
1270     Object initjscallback = getParameterAsObject("oninit");
1271     if (initjscallback != null)
1272     {
1273       SwingUtilities.invokeLater(new Runnable() {
1274
1275         @Override
1276         public void run()
1277         {
1278           try
1279           {
1280             doSendCallback(initjscallback, new Object[] {this});
1281           } catch (Exception e)
1282           {
1283             System.err.println("Exception when executing _oninit callback '"
1284                     + initjscallback + "'.");
1285             e.printStackTrace();
1286           }
1287         }
1288         
1289       });
1290     }
1291   }
1292
1293   /**
1294    * Pass the provided array prepended with Jalview.this
1295    * 
1296    * Appropriated from org.jmol.appletjs.Jmol
1297    * 
1298    * @param callback
1299    *          a window function or "alert"
1300    * @param data
1301    * @return String return from the callback method.
1302    */
1303   String doSendCallback(Object callback, Object[] data)
1304   {
1305     Jalview me = jalview;
1306
1307     if (me != null && callback != null)
1308     {
1309       /**
1310        * @j2sNative
1311        * 
1312        *            try{
1313        * 
1314        *            if (callback == "alert") { alert(data[0]); return ""; } var
1315        *            o; if (typeof callback == "function") { o = callback; } else
1316        *            { if (!callback)return; var tokens = callback.split("."); o
1317        *            = window[tokens[0]]; for (var i = 1; i < tokens.length; i++)
1318        *            o = o[tokens[i]]; } var a = [me]; for (var i = 0; i <
1319        *            data.length; i++) a.push(data[i] ? data[i].booleanValue &&
1320        *            (data[i] = data[i].booleanValue()) : data[i]); return
1321        *            o.apply(null,a) } catch (e) { System.out.println(callback +
1322        *            " failed " + e); }
1323        */
1324     }
1325     return "";
1326   }
1327
1328   /**
1329    * Initialize from Info.key/value pairs that match the old JalviewLite applet
1330    * parameters.
1331    * 
1332    * See http://www.jalview.org/old/v2_8/examples/appletParameters.html
1333    * 
1334    * Note that some of these parameters are handled as command-line arguments,
1335    * as determined in ArgsParser.
1336    * 
1337    * @param alf
1338    */
1339   void initFromParams(AlignFrame alf)
1340   {
1341     String sep = getParameter("separator");
1342     if (sep != null && sep.length() > 0)
1343     {
1344       separator = sep;
1345     }
1346     initTree(alf);
1347     initScoreFile(alf);
1348     initFeatures(alf);
1349     initAnnotations(alf);
1350     initJnetFile(alf);
1351     initPdbFiles(alf);
1352   }
1353
1354   /**
1355    * Load annotations if specified by parameter. Returns true if loaded, else
1356    * false.
1357    * 
1358    * 
1359    * @param alignFrame
1360    * @return
1361    */
1362   private boolean initAnnotations(AlignFrame alf)
1363   {
1364
1365     String param = getParameter("annotations");
1366     if (param == null)
1367       return false;
1368     ret[0] = param;
1369     DataSourceType protocol = resolveFileProtocol(ret);
1370     param = ret[0];
1371     if (!new AnnotationFile().annotateAlignmentView(alf.getViewport(),
1372             param, protocol))
1373     {
1374       System.err.println("Annotations were not added from annotation file '"
1375               + param + "'");
1376       return false;
1377     }
1378     updateForAnnotations();
1379     return true;
1380   }
1381
1382   /**
1383    * Load features file and view settings as specified by parameters. Returns
1384    * true if features were loaded, else false.
1385    * 
1386    * @param
1387    * 
1388    * @param alignFrame
1389    * @return
1390    */
1391   private boolean initFeatures(AlignFrame alf)
1392   {
1393
1394     // ///////////////////////////
1395     // modify display of features
1396     // we do this before any features have been loaded, ensuring any hidden
1397     // groups are hidden when features first displayed
1398     //
1399     // hide specific groups
1400     //
1401     String param = getParameter("hidefeaturegroups");
1402     if (param != null)
1403     {
1404       setFeatureGroupState(separatorListToArray(param, separator),
1405               false, alf);
1406       // setFeatureGroupStateOn(newAlignFrame, param, false);
1407     }
1408     // show specific groups
1409     param = getParameter("showfeaturegroups");
1410     if (param != null)
1411     {
1412       setFeatureGroupState(separatorListToArray(param, separator),
1413               true, alf);
1414       // setFeatureGroupStateOn(newAlignFrame, param, true);
1415     }
1416     // and now load features
1417     param = getParameter("features");
1418     if (param == null)
1419     {
1420       return false;
1421     }
1422     if (!parseFeaturesFile(param, alf))
1423       return false;
1424     param = getParameter("showFeatureSettings");
1425     if (param != null && param.equalsIgnoreCase("true"))
1426     {
1427       alf.showFeatureSettingsUI();
1428     }
1429     return true;
1430   }
1431
1432   /**
1433    * Load in a Jnetfile if specified by parameter. Returns true if loaded, else
1434    * false.
1435    * 
1436    * @param alignFrame
1437    * @return
1438    */
1439   private boolean initJnetFile(AlignFrame alf)
1440   {
1441
1442     String param = getParameter("jnetfile");
1443     if (param == null)
1444     {
1445       // jnet became jpred around 2016
1446       param = getParameter("jpredfile");
1447     }
1448     if (param != null)
1449     {
1450       try
1451       {
1452         ret[0] = param;
1453         DataSourceType protocol = resolveFileProtocol(ret);
1454         JPredFile predictions = new JPredFile(ret[0], protocol);
1455         JnetAnnotationMaker.add_annotation(predictions,
1456                 alf.getViewport().getAlignment(), 0, false);
1457         // false == do not add sequence profile from concise output
1458         alf.getViewport().getAlignment().setupJPredAlignment();
1459         updateForAnnotations();
1460       } catch (Exception ex)
1461       {
1462         ex.printStackTrace();
1463         return false;
1464       }
1465     }
1466     return true;
1467   }
1468
1469   /**
1470    * Load PDBFiles if any specified by parameter(s). Returns true if loaded,
1471    * else false.
1472    * 
1473    * @param loaderFrame
1474    * @return
1475    */
1476   private boolean initPdbFiles(AlignFrame alf)
1477   {
1478
1479     /*
1480      * <param name="alignpdbfiles" value="false/true"/> Undocumented for 2.6 -
1481      * related to JAL-434
1482      */
1483
1484     // not supported (as for JalviewLite)
1485     // boolean doAlign = false;//"true".equalsIgnoreCase("" +
1486     // getAppletParameter("alignpdbfiles", false));
1487     // setAlignPdbStructures(doAlign);
1488     /*
1489      * <param name="PDBfile" value="1gaq.txt PDB|1GAQ|1GAQ|A PDB|1GAQ|1GAQ|B
1490      * PDB|1GAQ|1GAQ|C">
1491      * 
1492      * <param name="PDBfile2" value="1gaq.txt A=SEQA B=SEQB C=SEQB">
1493      * 
1494      * <param name="PDBfile3" value="1q0o Q45135_9MICO">
1495      */
1496
1497     // Accumulate pdbs here if they are heading for the same view (if
1498     // alignPdbStructures is true)
1499     // ArrayList<Object[]> pdbs = new ArrayList<>();
1500     // init a lazy matcher if we're asked to
1501     boolean relaxed = "true"
1502             .equalsIgnoreCase(getParameter("relaxedidmatch"));
1503     jalview.analysis.SequenceIdMatcher matcher = relaxed
1504             ? new jalview.analysis.SequenceIdMatcher(
1505                     alf.getViewport().getAlignment().getSequencesArray())
1506             : null;
1507
1508     String param = getParameter("PDBFILE");
1509     int plast = (param == null ? 9 : 1);
1510     if (param == null && (param = getParameter("PDBFILE1")) == null)
1511     {
1512       return false;
1513     }
1514     for (int p = 1; p <= plast; p++)
1515     {
1516       if (p > 1)
1517       {
1518         param = getParameter("PDBFILE" + p);
1519         if (param == null)
1520           break;
1521       }
1522       PDBEntry pdb = new PDBEntry();
1523
1524       String seqstring;
1525       SequenceI[] seqs = null;
1526       String[] chains = null;
1527
1528       StringTokenizer st = new StringTokenizer(param, " ");
1529
1530       if (st.countTokens() < 2)
1531       {
1532         String sequence = getParameter("PDBSEQ");
1533         if (sequence != null)
1534         {
1535           seqs = new SequenceI[] { matcher == null
1536                   ? (Sequence) alf.getViewport().getAlignment()
1537                           .findName(sequence)
1538                   : matcher.findIdMatch(sequence) };
1539         }
1540
1541       }
1542       else
1543       {
1544         param = st.nextToken();
1545         List<SequenceI> tmp = new ArrayList<>();
1546         List<String> tmp2 = new ArrayList<>();
1547
1548         while (st.hasMoreTokens())
1549         {
1550           seqstring = st.nextToken();
1551           StringTokenizer st2 = new StringTokenizer(seqstring, "=");
1552           if (st2.countTokens() > 1)
1553           {
1554             // This is the chain
1555             tmp2.add(st2.nextToken());
1556             seqstring = st2.nextToken();
1557           }
1558           tmp.add(matcher == null
1559                   ? (Sequence) alf.getViewport().getAlignment()
1560                           .findName(seqstring)
1561                   : matcher.findIdMatch(seqstring));
1562         }
1563
1564         seqs = tmp.toArray(new SequenceI[tmp.size()]);
1565         if (tmp2.size() == tmp.size())
1566         {
1567           chains = tmp2.toArray(new String[tmp2.size()]);
1568         }
1569       }
1570       pdb.setId(param);
1571       ret[0] = param;
1572       DataSourceType protocol = resolveFileProtocol(ret);
1573       // TODO check JAL-357 for files in a jar (CLASSLOADER)
1574       pdb.setFile(ret[0]);
1575
1576       if (seqs != null)
1577       {
1578         for (int i = 0; i < seqs.length; i++)
1579         {
1580           if (seqs[i] != null)
1581           {
1582             ((Sequence) seqs[i]).addPDBId(pdb);
1583             StructureSelectionManager
1584                     .getStructureSelectionManager(
1585                             (StructureSelectionManagerProvider) this)
1586                     .registerPDBEntry(pdb);
1587           }
1588         }
1589
1590         // if (doAlign)
1591         // {
1592         // pdbs.add(new Object[] { pdb, seqs, chains, protocol });
1593         // }
1594         // else
1595         {
1596           StructureViewer.launchStructureViewer(
1597                   (alf == null ? getCurrentAlignFrame() : alf).alignPanel,
1598                   pdb, seqs);
1599         }
1600       }
1601     }
1602     //
1603     // if (doAlign && pdbs.size() > 0)
1604     // {
1605     // SequenceI[][] seqs = new SequenceI[pdbs.size()][];
1606     // PDBEntry[] pdb = new PDBEntry[pdbs.size()];
1607     // String[][] chains = new String[pdbs.size()][];
1608     // String[] protocols = new String[pdbs.size()];
1609     // for (int pdbsi = 0, pdbsiSize = pdbs
1610     // .size(); pdbsi < pdbsiSize; pdbsi++)
1611     // {
1612     // Object[] o = pdbs.get(pdbsi);
1613     // pdb[pdbsi] = (PDBEntry) o[0];
1614     // seqs[pdbsi] = (SequenceI[]) o[1];
1615     // chains[pdbsi] = (String[]) o[2];
1616     // protocols[pdbsi] = (String) o[3];
1617     // }
1618     //// alignedStructureView(pdb, seqs, chains, protocols);
1619     // result = true;
1620     // }
1621     return true;
1622   }
1623
1624   /**
1625    * Load a score file if specified by parameter. Returns true if file was
1626    * loaded, else false.
1627    * 
1628    * @param loaderFrame
1629    */
1630   private boolean initScoreFile(AlignFrame alf)
1631   {
1632
1633     String sScoreFile = getParameter("scoreFile");
1634     if (sScoreFile != null && !"".equals(sScoreFile))
1635     {
1636       try
1637       {
1638         if (loadScoreFile(sScoreFile, alf))
1639         {
1640           return true;
1641         }
1642         System.err.println(
1643                 "Failed to parse T-COFFEE parameter as a valid score file ('"
1644                         + sScoreFile + "')");
1645       } catch (Exception e)
1646       {
1647         System.err.printf("Cannot read score file: '%s'. Cause: %s \n",
1648                 sScoreFile, e.getMessage());
1649       }
1650     }
1651     return false;
1652   }
1653
1654   /**
1655    * Load a tree for the alignment if specified by parameter. Returns true if a
1656    * tree was loaded, else false.
1657    * 
1658    * @return
1659    */
1660   private boolean initTree(AlignFrame alf)
1661   {
1662     String treeFile;
1663     if ((treeFile = getParameter("tree")) == null
1664             && (treeFile = getParameter("treefile")) == null)
1665       return false;
1666     if (alf == null)
1667       alf = getCurrentAlignFrame();
1668     try
1669     {
1670       ret[0] = treeFile;
1671       NewickFile nf = new NewickFile(treeFile, resolveFileProtocol(ret));
1672       nf.parse();
1673       if (nf.getTree() != null)
1674       {
1675         treeFile = ret[0];
1676         alf.getViewport()
1677                 .setCurrentTree(alf.showNewickTree(nf, treeFile).getTree());
1678         return true;
1679       }
1680     } catch (Exception ex)
1681     {
1682       ex.printStackTrace();
1683     }
1684     return false;
1685   }
1686
1687   private void updateForAnnotations()
1688   {
1689     getCurrentAlignFrame().updateForAnnotations();
1690   }
1691 }