Merge branch 'develop' into alpha/JAL-3362_Jalview_212_alpha
[jalview.git] / src / jalview / appletgui / AlignFrame.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.appletgui;
22
23 import jalview.analysis.AlignmentSorter;
24 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
25 import jalview.analysis.TreeBuilder;
26 import jalview.analysis.scoremodels.PIDModel;
27 import jalview.analysis.scoremodels.ScoreModels;
28 import jalview.api.AlignViewControllerGuiI;
29 import jalview.api.AlignViewControllerI;
30 import jalview.api.AlignViewportI;
31 import jalview.api.FeatureColourI;
32 import jalview.api.FeatureRenderer;
33 import jalview.api.FeatureSettingsControllerI;
34 import jalview.api.SequenceStructureBinding;
35 import jalview.bin.JalviewLite;
36 import jalview.commands.CommandI;
37 import jalview.commands.EditCommand;
38 import jalview.commands.EditCommand.Action;
39 import jalview.commands.OrderCommand;
40 import jalview.commands.RemoveGapColCommand;
41 import jalview.commands.RemoveGapsCommand;
42 import jalview.commands.SlideSequencesCommand;
43 import jalview.commands.TrimRegionCommand;
44 import jalview.datamodel.Alignment;
45 import jalview.datamodel.AlignmentAnnotation;
46 import jalview.datamodel.AlignmentI;
47 import jalview.datamodel.AlignmentOrder;
48 import jalview.datamodel.ColumnSelection;
49 import jalview.datamodel.HiddenColumns;
50 import jalview.datamodel.PDBEntry;
51 import jalview.datamodel.Sequence;
52 import jalview.datamodel.SequenceGroup;
53 import jalview.datamodel.SequenceI;
54 import jalview.io.AnnotationFile;
55 import jalview.io.AppletFormatAdapter;
56 import jalview.io.DataSourceType;
57 import jalview.io.FeaturesFile;
58 import jalview.io.FileFormat;
59 import jalview.io.FileFormatI;
60 import jalview.io.FileFormats;
61 import jalview.io.TCoffeeScoreFile;
62 import jalview.schemes.Blosum62ColourScheme;
63 import jalview.schemes.BuriedColourScheme;
64 import jalview.schemes.ClustalxColourScheme;
65 import jalview.schemes.ColourSchemeI;
66 import jalview.schemes.HelixColourScheme;
67 import jalview.schemes.HydrophobicColourScheme;
68 import jalview.schemes.NucleotideColourScheme;
69 import jalview.schemes.PIDColourScheme;
70 import jalview.schemes.PurinePyrimidineColourScheme;
71 import jalview.schemes.RNAHelicesColour;
72 import jalview.schemes.StrandColourScheme;
73 import jalview.schemes.TCoffeeColourScheme;
74 import jalview.schemes.TaylorColourScheme;
75 import jalview.schemes.TurnColourScheme;
76 import jalview.schemes.ZappoColourScheme;
77 import jalview.structure.StructureSelectionManager;
78 import jalview.structures.models.AAStructureBindingModel;
79 import jalview.util.MappingUtils;
80 import jalview.util.MessageManager;
81 import jalview.viewmodel.AlignmentViewport;
82 import jalview.viewmodel.ViewportRanges;
83
84 import java.awt.BorderLayout;
85 import java.awt.Canvas;
86 import java.awt.CheckboxMenuItem;
87 import java.awt.Color;
88 import java.awt.FlowLayout;
89 import java.awt.Font;
90 import java.awt.FontMetrics;
91 import java.awt.Frame;
92 import java.awt.Graphics;
93 import java.awt.Label;
94 import java.awt.Menu;
95 import java.awt.MenuBar;
96 import java.awt.MenuItem;
97 import java.awt.Panel;
98 import java.awt.Rectangle;
99 import java.awt.event.ActionEvent;
100 import java.awt.event.ActionListener;
101 import java.awt.event.FocusEvent;
102 import java.awt.event.FocusListener;
103 import java.awt.event.ItemEvent;
104 import java.awt.event.ItemListener;
105 import java.awt.event.KeyEvent;
106 import java.awt.event.KeyListener;
107 import java.awt.event.WindowAdapter;
108 import java.awt.event.WindowEvent;
109 import java.io.IOException;
110 import java.io.UnsupportedEncodingException;
111 import java.net.URL;
112 import java.net.URLEncoder;
113 import java.util.Arrays;
114 import java.util.Deque;
115 import java.util.HashMap;
116 import java.util.List;
117 import java.util.Map;
118 import java.util.StringTokenizer;
119 import java.util.Vector;
120
121 import org.jmol.viewer.Viewer;
122
123 public class AlignFrame extends EmbmenuFrame implements ActionListener,
124         ItemListener, KeyListener, AlignViewControllerGuiI
125 {
126   public AlignViewControllerI avc;
127
128   public AlignmentPanel alignPanel;
129
130   public AlignViewport viewport;
131
132   // width and height may be overridden by applet parameters
133   int frameWidth = 700;
134
135   int frameHeight = 500;
136
137   String jalviewServletURL;
138
139   /*
140    * Flag for showing autocalculated consensus above or below other consensus
141    * rows
142    */
143   private boolean showAutoCalculatedAbove;
144
145   private SequenceAnnotationOrder annotationSortOrder;
146
147   /**
148    * Constructor that creates the frame and adds it to the display.
149    * 
150    * @param al
151    * @param applet
152    * @param title
153    * @param embedded
154    */
155   public AlignFrame(AlignmentI al, JalviewLite applet, String title,
156           boolean embedded)
157   {
158     this(al, applet, title, embedded, true);
159   }
160
161   /**
162    * Constructor that optionally allows the frame to be displayed or only
163    * created.
164    * 
165    * @param al
166    * @param applet
167    * @param title
168    * @param embedded
169    * @param addToDisplay
170    */
171   public AlignFrame(AlignmentI al, JalviewLite applet, String title,
172           boolean embedded, boolean addToDisplay)
173   {
174     this(al, null, null, applet, title, embedded, addToDisplay);
175   }
176
177   public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
178           HiddenColumns hidden, JalviewLite applet, String title,
179           boolean embedded)
180   {
181     this(al, hiddenSeqs, hidden, applet, title, embedded, true);
182   }
183
184   public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
185           HiddenColumns hidden, JalviewLite applet, String title,
186           boolean embedded, boolean addToDisplay)
187   {
188     if (applet != null)
189     {
190       jalviewServletURL = applet.getParameter("APPLICATION_URL");
191     }
192
193     try
194     {
195       jbInit();
196     } catch (Exception ex)
197     {
198       ex.printStackTrace();
199     }
200     // need to get window geometry before we calculate alignment layout
201     if (applet != null)
202     {
203       String param;
204       try
205       {
206         param = applet.getParameter("windowWidth");
207         if (param != null)
208         {
209           int width = Integer.parseInt(param);
210           frameWidth = width;
211         }
212         param = applet.getParameter("windowHeight");
213         if (param != null)
214         {
215           int height = Integer.parseInt(param);
216           frameHeight = height;
217         }
218       } catch (Exception ex)
219       {
220       }
221     }
222     viewport = new AlignViewport(al, applet);
223
224     if (hiddenSeqs != null && hiddenSeqs.length > 0)
225     {
226       viewport.hideSequence(hiddenSeqs);
227     }
228     if (hidden != null)
229     {
230       viewport.getAlignment().setHiddenColumns(hidden);
231     }
232     viewport.setScaleAboveWrapped(scaleAbove.getState());
233
234     alignPanel = new AlignmentPanel(this, viewport);
235     avc = new jalview.controller.AlignViewController(this, viewport,
236             alignPanel);
237     viewport.updateConservation(alignPanel);
238     viewport.updateConsensus(alignPanel);
239     viewport.initInformationWorker(alignPanel);
240
241     displayNonconservedMenuItem.setState(viewport.getShowUnconserved());
242     followMouseOverFlag.setState(viewport.isFollowHighlight());
243     showGroupConsensus.setState(viewport.isShowGroupConsensus());
244     showGroupConservation.setState(viewport.isShowGroupConservation());
245     showConsensusHistogram.setState(viewport.isShowConsensusHistogram());
246     showSequenceLogo.setState(viewport.isShowSequenceLogo());
247     normSequenceLogo.setState(viewport.isNormaliseSequenceLogo());
248     applyToAllGroups.setState(viewport.getColourAppliesToAllGroups());
249     annotationPanelMenuItem.setState(viewport.isShowAnnotation());
250     showAlignmentAnnotations.setEnabled(annotationPanelMenuItem.getState());
251     showSequenceAnnotations.setEnabled(annotationPanelMenuItem.getState());
252     showAlignmentAnnotations.setState(true);
253     showSequenceAnnotations.setState(false);
254
255     seqLimits.setState(viewport.getShowJVSuffix());
256
257     if (applet != null)
258     {
259       String param = applet.getParameter("sortBy");
260       if (param != null)
261       {
262         if (param.equalsIgnoreCase("Id"))
263         {
264           sortIDMenuItem_actionPerformed();
265         }
266         else if (param.equalsIgnoreCase("Pairwise Identity"))
267         {
268           sortPairwiseMenuItem_actionPerformed();
269         }
270         else if (param.equalsIgnoreCase("Length"))
271         {
272           sortLengthMenuItem_actionPerformed();
273         }
274       }
275
276       param = applet.getParameter("wrap");
277       if (param != null)
278       {
279         if (param.equalsIgnoreCase("true"))
280         {
281           wrapMenuItem.setState(true);
282           wrapMenuItem_actionPerformed();
283         }
284       }
285       param = applet.getParameter("centrecolumnlabels");
286       if (param != null)
287       {
288         centreColumnLabelFlag.setState(true);
289         centreColumnLabelFlag_stateChanged();
290       }
291
292     }
293     if (viewport.getAlignment().isNucleotide())
294     {
295       conservationMenuItem.setEnabled(false);
296       clustalColour.setEnabled(false);
297       BLOSUM62Colour.setEnabled(false);
298       zappoColour.setEnabled(false);
299       taylorColour.setEnabled(false);
300       hydrophobicityColour.setEnabled(false);
301       helixColour.setEnabled(false);
302       strandColour.setEnabled(false);
303       turnColour.setEnabled(false);
304       buriedColour.setEnabled(false);
305       viewport.updateStrucConsensus(alignPanel);
306       if (viewport.getAlignment().hasRNAStructure())
307       {
308         RNAHelixColour.setEnabled(true);
309       }
310       else
311       {
312         RNAHelixColour.setEnabled(false);
313       }
314     }
315     else
316     {
317       RNAHelixColour.setEnabled(false);
318       purinePyrimidineColour.setEnabled(false);
319       nucleotideColour.setEnabled(false);
320     }
321     // Some JVMS send keyevents to Top frame or lowest panel,
322     // Havent worked out why yet. So add to both this frame and seqCanvas for
323     // now
324     this.addKeyListener(this);
325     alignPanel.seqPanel.seqCanvas.addKeyListener(this);
326     alignPanel.idPanel.idCanvas.addKeyListener(this);
327     alignPanel.scalePanel.addKeyListener(this);
328     alignPanel.annotationPanel.addKeyListener(this);
329     alignPanel.annotationPanelHolder.addKeyListener(this);
330     alignPanel.annotationSpaceFillerHolder.addKeyListener(this);
331     alignPanel.alabels.addKeyListener(this);
332
333     setAnnotationsVisibility();
334
335     if (addToDisplay)
336     {
337       addToDisplay(embedded);
338     }
339   }
340
341   /**
342    * @param embedded
343    */
344   public void addToDisplay(boolean embedded)
345   {
346     createAlignFrameWindow(embedded);
347     validate();
348     alignPanel.adjustAnnotationHeight();
349     alignPanel.paintAlignment(true, true);
350   }
351
352   public AlignViewport getAlignViewport()
353   {
354     return viewport;
355   }
356
357   public SeqCanvas getSeqcanvas()
358   {
359     return alignPanel.seqPanel.seqCanvas;
360   }
361
362   /**
363    * Load a features file onto the alignment
364    * 
365    * @param file
366    *          file URL, content, or other resolvable path
367    * @param type
368    *          is protocol for accessing data referred to by file
369    */
370
371   public boolean parseFeaturesFile(String file, DataSourceType type)
372   {
373     return parseFeaturesFile(file, type, true);
374   }
375
376   /**
377    * Load a features file onto the alignment
378    * 
379    * @param file
380    *          file URL, content, or other resolvable path
381    * @param sourceType
382    *          is protocol for accessing data referred to by file
383    * @param autoenabledisplay
384    *          when true, display features flag will be automatically enabled if
385    *          features are loaded
386    * @return true if data parsed as a features file
387    */
388   public boolean parseFeaturesFile(String file, DataSourceType sourceType,
389           boolean autoenabledisplay)
390   {
391     boolean featuresFile = false;
392     try
393     {
394       Map<String, FeatureColourI> colours = alignPanel.seqPanel.seqCanvas
395               .getFeatureRenderer().getFeatureColours();
396       boolean relaxedIdMatching = viewport.applet
397               .getDefaultParameter("relaxedidmatch", false);
398       featuresFile = new FeaturesFile(file, sourceType).parse(
399               viewport.getAlignment(), colours, true, relaxedIdMatching);
400     } catch (Exception ex)
401     {
402       ex.printStackTrace();
403     }
404
405     if (featuresFile)
406     {
407       if (autoenabledisplay)
408       {
409         viewport.setShowSequenceFeatures(true);
410         sequenceFeatures.setState(true);
411       }
412       if (alignPanel.seqPanel.seqCanvas.fr != null)
413       {
414         // update the min/max ranges where necessary
415         alignPanel.seqPanel.seqCanvas.fr.findAllFeatures(true);
416       }
417       if (viewport.featureSettings != null)
418       {
419         viewport.featureSettings.refreshTable();
420       }
421       alignPanel.paintAlignment(true, true);
422       statusBar.setText(MessageManager
423               .getString("label.successfully_added_features_alignment"));
424     }
425     return featuresFile;
426   }
427
428   @Override
429   public void keyPressed(KeyEvent evt)
430   {
431     ViewportRanges ranges = viewport.getRanges();
432
433     if (viewport.cursorMode
434             && ((evt.getKeyCode() >= KeyEvent.VK_0
435                     && evt.getKeyCode() <= KeyEvent.VK_9)
436                     || (evt.getKeyCode() >= KeyEvent.VK_NUMPAD0
437                             && evt.getKeyCode() <= KeyEvent.VK_NUMPAD9))
438             && Character.isDigit(evt.getKeyChar()))
439     {
440       alignPanel.seqPanel.numberPressed(evt.getKeyChar());
441     }
442
443     switch (evt.getKeyCode())
444     {
445     case 27: // escape key
446       deselectAllSequenceMenuItem_actionPerformed();
447
448       alignPanel.alabels.cancelDrag();
449       break;
450     case KeyEvent.VK_X:
451       if (evt.isControlDown() || evt.isMetaDown())
452       {
453         cut_actionPerformed();
454       }
455       break;
456     case KeyEvent.VK_C:
457       if (viewport.cursorMode && !evt.isControlDown())
458       {
459         alignPanel.seqPanel.setCursorColumn();
460       }
461       if (evt.isControlDown() || evt.isMetaDown())
462       {
463         copy_actionPerformed();
464       }
465       break;
466     case KeyEvent.VK_V:
467       if (evt.isControlDown())
468       {
469         paste(evt.isShiftDown());
470       }
471       break;
472     case KeyEvent.VK_A:
473       if (evt.isControlDown() || evt.isMetaDown())
474       {
475         selectAllSequenceMenuItem_actionPerformed();
476       }
477       break;
478     case KeyEvent.VK_DOWN:
479       if (viewport.cursorMode)
480       {
481         alignPanel.seqPanel.moveCursor(0, 1);
482       }
483       else
484       {
485         moveSelectedSequences(false);
486       }
487       break;
488
489     case KeyEvent.VK_UP:
490       if (viewport.cursorMode)
491       {
492         alignPanel.seqPanel.moveCursor(0, -1);
493       }
494       else
495       {
496         moveSelectedSequences(true);
497       }
498       break;
499
500     case KeyEvent.VK_LEFT:
501       if (evt.isAltDown() || !viewport.cursorMode)
502       {
503         slideSequences(false, alignPanel.seqPanel.getKeyboardNo1());
504       }
505       else
506       {
507         alignPanel.seqPanel.moveCursor(-1, 0);
508       }
509       break;
510
511     case KeyEvent.VK_RIGHT:
512       if (evt.isAltDown() || !viewport.cursorMode)
513       {
514         slideSequences(true, alignPanel.seqPanel.getKeyboardNo1());
515       }
516       else
517       {
518         alignPanel.seqPanel.moveCursor(1, 0);
519       }
520       break;
521
522     case KeyEvent.VK_SPACE:
523       if (viewport.cursorMode)
524       {
525         alignPanel.seqPanel.insertGapAtCursor(evt.isControlDown()
526                 || evt.isShiftDown() || evt.isAltDown());
527       }
528       break;
529
530     case KeyEvent.VK_DELETE:
531     case KeyEvent.VK_BACK_SPACE:
532       if (viewport.cursorMode)
533       {
534         alignPanel.seqPanel.deleteGapAtCursor(evt.isControlDown()
535                 || evt.isShiftDown() || evt.isAltDown());
536       }
537       else
538       {
539         cut_actionPerformed();
540         alignPanel.seqPanel.seqCanvas.repaint();
541       }
542       break;
543
544     case KeyEvent.VK_S:
545       if (viewport.cursorMode)
546       {
547         alignPanel.seqPanel.setCursorRow();
548       }
549       break;
550     case KeyEvent.VK_P:
551       if (viewport.cursorMode)
552       {
553         alignPanel.seqPanel.setCursorPosition();
554       }
555       break;
556
557     case KeyEvent.VK_ENTER:
558     case KeyEvent.VK_COMMA:
559       if (viewport.cursorMode)
560       {
561         alignPanel.seqPanel.setCursorRowAndColumn();
562       }
563       break;
564
565     case KeyEvent.VK_Q:
566       if (viewport.cursorMode)
567       {
568         alignPanel.seqPanel.setSelectionAreaAtCursor(true);
569       }
570       break;
571     case KeyEvent.VK_M:
572       if (viewport.cursorMode)
573       {
574         alignPanel.seqPanel.setSelectionAreaAtCursor(false);
575       }
576       break;
577
578     case KeyEvent.VK_F2:
579       viewport.cursorMode = !viewport.cursorMode;
580       statusBar.setText(MessageManager
581               .formatMessage("label.keyboard_editing_mode", new String[]
582               { (viewport.cursorMode ? "on" : "off") }));
583       if (viewport.cursorMode)
584       {
585         alignPanel.seqPanel.seqCanvas.cursorX = ranges.getStartRes();
586         alignPanel.seqPanel.seqCanvas.cursorY = ranges.getStartSeq();
587       }
588       break;
589
590     case KeyEvent.VK_F:
591       if (evt.isControlDown())
592       {
593         findMenuItem_actionPerformed();
594       }
595       break;
596
597     case KeyEvent.VK_H:
598     {
599       boolean toggleSeqs = !evt.isControlDown();
600       boolean toggleCols = !evt.isShiftDown();
601       toggleHiddenRegions(toggleSeqs, toggleCols);
602       break;
603     }
604
605     case KeyEvent.VK_PAGE_UP:
606       ranges.pageUp();
607       break;
608
609     case KeyEvent.VK_PAGE_DOWN:
610       ranges.pageDown();
611       break;
612
613     case KeyEvent.VK_Z:
614       if (evt.isControlDown())
615       {
616         undoMenuItem_actionPerformed();
617       }
618       break;
619
620     case KeyEvent.VK_Y:
621       if (evt.isControlDown())
622       {
623         redoMenuItem_actionPerformed();
624       }
625       break;
626
627     case KeyEvent.VK_L:
628       if (evt.isControlDown())
629       {
630         trimAlignment(true);
631       }
632       break;
633
634     case KeyEvent.VK_R:
635       if (evt.isControlDown())
636       {
637         trimAlignment(false);
638       }
639       break;
640
641     case KeyEvent.VK_E:
642       if (evt.isControlDown())
643       {
644         if (evt.isShiftDown())
645         {
646           this.removeAllGapsMenuItem_actionPerformed();
647         }
648         else
649         {
650           removeGappedColumnMenuItem_actionPerformed();
651         }
652       }
653       break;
654     case KeyEvent.VK_I:
655       if (evt.isControlDown())
656       {
657         if (evt.isAltDown())
658         {
659           invertColSel_actionPerformed();
660         }
661         else
662         {
663           invertSequenceMenuItem_actionPerformed();
664         }
665       }
666       break;
667
668     case KeyEvent.VK_G:
669       if (evt.isControlDown())
670       {
671         if (evt.isShiftDown())
672         {
673           this.unGroup_actionPerformed();
674         }
675         else
676         {
677           this.createGroup_actionPerformed();
678         }
679       }
680       break;
681
682     case KeyEvent.VK_U:
683       if (evt.isControlDown())
684       {
685         this.deleteGroups_actionPerformed();
686       }
687       break;
688
689     case KeyEvent.VK_T:
690       if (evt.isControlDown())
691       {
692         newView(null);
693       }
694       break;
695
696     }
697     // TODO: repaint flags set only if the keystroke warrants it
698     alignPanel.paintAlignment(true, true);
699   }
700
701   /**
702    * called by key handler and the hide all/show all menu items
703    * 
704    * @param toggleSeqs
705    * @param toggleCols
706    */
707   private void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
708   {
709     boolean hide = false;
710     SequenceGroup sg = viewport.getSelectionGroup();
711     if (!toggleSeqs && !toggleCols)
712     {
713       // Hide everything by the current selection - this is a hack - we do the
714       // invert and then hide
715       // first check that there will be visible columns after the invert.
716       if (viewport.hasSelectedColumns() || (sg != null && sg.getSize() > 0
717               && sg.getStartRes() <= sg.getEndRes()))
718       {
719         // now invert the sequence set, if required - empty selection implies
720         // that no hiding is required.
721         if (sg != null)
722         {
723           invertSequenceMenuItem_actionPerformed();
724           sg = viewport.getSelectionGroup();
725           toggleSeqs = true;
726
727         }
728         viewport.expandColSelection(sg, true);
729         // finally invert the column selection and get the new sequence
730         // selection and indicate it should be hidden.
731         invertColSel_actionPerformed();
732         toggleCols = true;
733       }
734     }
735
736     if (toggleSeqs)
737     {
738       if (sg != null && sg.getSize() != viewport.getAlignment().getHeight())
739       {
740         hide = true;
741         viewport.hideAllSelectedSeqs();
742       }
743       else if (!(toggleCols && viewport.hasSelectedColumns()))
744       {
745         viewport.showAllHiddenSeqs();
746       }
747     }
748
749     if (toggleCols)
750     {
751       if (viewport.hasSelectedColumns())
752       {
753         viewport.hideSelectedColumns();
754         if (!toggleSeqs)
755         {
756           viewport.setSelectionGroup(sg);
757         }
758       }
759       else if (!hide)
760       {
761         viewport.showAllHiddenColumns();
762       }
763       viewport.sendSelection();
764     }
765   }
766
767   @Override
768   public void keyReleased(KeyEvent evt)
769   {
770   }
771
772   @Override
773   public void keyTyped(KeyEvent evt)
774   {
775   }
776
777   @Override
778   public void itemStateChanged(ItemEvent evt)
779   {
780     final Object source = evt.getSource();
781     if (source == displayNonconservedMenuItem)
782     {
783       displayNonconservedMenuItem_actionPerformed();
784     }
785     else if (source == colourTextMenuItem)
786     {
787       colourTextMenuItem_actionPerformed();
788     }
789     else if (source == wrapMenuItem)
790     {
791       wrapMenuItem_actionPerformed();
792     }
793     else if (source == scaleAbove)
794     {
795       viewport.setScaleAboveWrapped(scaleAbove.getState());
796     }
797     else if (source == scaleLeft)
798     {
799       viewport.setScaleLeftWrapped(scaleLeft.getState());
800     }
801     else if (source == scaleRight)
802     {
803       viewport.setScaleRightWrapped(scaleRight.getState());
804     }
805     else if (source == seqLimits)
806     {
807       seqLimits_itemStateChanged();
808     }
809     else if (source == viewBoxesMenuItem)
810     {
811       viewport.setShowBoxes(viewBoxesMenuItem.getState());
812     }
813     else if (source == viewTextMenuItem)
814     {
815       viewport.setShowText(viewTextMenuItem.getState());
816     }
817     else if (source == renderGapsMenuItem)
818     {
819       viewport.setRenderGaps(renderGapsMenuItem.getState());
820     }
821     else if (source == annotationPanelMenuItem)
822     {
823       boolean showAnnotations = annotationPanelMenuItem.getState();
824       showAlignmentAnnotations.setEnabled(showAnnotations);
825       showSequenceAnnotations.setEnabled(showAnnotations);
826       viewport.setShowAnnotation(showAnnotations);
827       alignPanel.setAnnotationVisible(showAnnotations);
828     }
829     else if (source == sequenceFeatures)
830     {
831       viewport.setShowSequenceFeatures(sequenceFeatures.getState());
832       alignPanel.seqPanel.seqCanvas.repaint();
833     }
834     else if (source == showAlignmentAnnotations)
835     {
836       setAnnotationsVisibility();
837     }
838     else if (source == showSequenceAnnotations)
839     {
840       setAnnotationsVisibility();
841     }
842     else if (source == sortAnnBySequence)
843     {
844       boolean newState = sortAnnBySequence.getState();
845       sortAnnByLabel.setState(false);
846       setAnnotationSortOrder(
847               newState ? SequenceAnnotationOrder.SEQUENCE_AND_LABEL
848                       : SequenceAnnotationOrder.NONE);
849       setViewportAnnotationOrder();
850     }
851     else if (source == sortAnnByLabel)
852     {
853       boolean newState = sortAnnByLabel.getState();
854       sortAnnBySequence.setState(false);
855       setAnnotationSortOrder(
856               newState ? SequenceAnnotationOrder.LABEL_AND_SEQUENCE
857                       : SequenceAnnotationOrder.NONE);
858       setViewportAnnotationOrder();
859     }
860     else if (source == showAutoFirst)
861     {
862       showAutoLast.setState(!showAutoFirst.getState());
863       setShowAutoCalculatedAbove(showAutoFirst.getState());
864       setViewportAnnotationOrder();
865     }
866     else if (source == showAutoLast)
867     {
868       showAutoFirst.setState(!showAutoLast.getState());
869       setShowAutoCalculatedAbove(showAutoFirst.getState());
870       setViewportAnnotationOrder();
871     }
872     else if (source == conservationMenuItem)
873     {
874       conservationMenuItem_actionPerformed();
875     }
876     else if (source == abovePIDThreshold)
877     {
878       abovePIDThreshold_actionPerformed();
879     }
880     else if (source == applyToAllGroups)
881     {
882       viewport.setColourAppliesToAllGroups(applyToAllGroups.getState());
883     }
884     else if (source == autoCalculate)
885     {
886       viewport.autoCalculateConsensus = autoCalculate.getState();
887     }
888     else if (source == sortByTree)
889     {
890       viewport.sortByTree = sortByTree.getState();
891     }
892     else if (source == this.centreColumnLabelFlag)
893     {
894       centreColumnLabelFlag_stateChanged();
895     }
896     else if (source == this.followMouseOverFlag)
897     {
898       mouseOverFlag_stateChanged();
899     }
900     else if (source == showGroupConsensus)
901     {
902       showGroupConsensus_actionPerformed();
903     }
904     else if (source == showGroupConservation)
905     {
906       showGroupConservation_actionPerformed();
907     }
908     else if (source == showSequenceLogo)
909     {
910       showSequenceLogo_actionPerformed();
911     }
912     else if (source == normSequenceLogo)
913     {
914       normSequenceLogo_actionPerformed();
915     }
916     else if (source == showConsensusHistogram)
917     {
918       showConsensusHistogram_actionPerformed();
919     }
920     else if (source == applyAutoAnnotationSettings)
921     {
922       applyAutoAnnotationSettings_actionPerformed();
923     }
924     // TODO: repaint flags set only if warranted
925     alignPanel.paintAlignment(true, true);
926   }
927
928   /**
929    * Set the visibility state of sequence-related and/or alignment-related
930    * annotations depending on checkbox selections, and repaint.
931    * 
932    * @param visible
933    */
934   private void setAnnotationsVisibility()
935   {
936     boolean showForAlignment = showAlignmentAnnotations.getState();
937     boolean showForSequences = showSequenceAnnotations.getState();
938     if (alignPanel.getAlignment().getAlignmentAnnotation() != null)
939     {
940       for (AlignmentAnnotation aa : alignPanel.getAlignment()
941               .getAlignmentAnnotation())
942       {
943         boolean visible = (aa.sequenceRef == null ? showForAlignment
944                 : showForSequences);
945         aa.visible = visible;
946       }
947     }
948     alignPanel.validateAnnotationDimensions(true);
949     validate();
950     repaint();
951   }
952
953   private void setAnnotationSortOrder(SequenceAnnotationOrder order)
954   {
955     this.annotationSortOrder = order;
956   }
957
958   /**
959    * Set flags on the viewport that control annotation ordering
960    */
961   private void setViewportAnnotationOrder()
962   {
963     this.alignPanel.av.setSortAnnotationsBy(this.annotationSortOrder);
964     this.alignPanel.av
965             .setShowAutocalculatedAbove(this.showAutoCalculatedAbove);
966   }
967
968   private void setShowAutoCalculatedAbove(boolean showAbove)
969   {
970     this.showAutoCalculatedAbove = showAbove;
971   }
972
973   private void mouseOverFlag_stateChanged()
974   {
975     viewport.setFollowHighlight(followMouseOverFlag.getState());
976     // TODO: could kick the scrollTo mechanism to reset view for current
977     // searchresults.
978   }
979
980   private void centreColumnLabelFlag_stateChanged()
981   {
982     viewport.centreColumnLabels = centreColumnLabelFlag.getState();
983     this.alignPanel.annotationPanel.repaint();
984   }
985
986   @Override
987   public void actionPerformed(ActionEvent evt)
988   {
989     viewport.applet.currentAlignFrame = this;
990
991     Object source = evt.getSource();
992
993     if (source == inputText)
994     {
995       inputText_actionPerformed();
996     }
997     else if (source == loadTree)
998     {
999       loadTree_actionPerformed();
1000     }
1001     else if (source == loadApplication)
1002     {
1003       launchFullApplication();
1004     }
1005     else if (source == loadAnnotations)
1006     {
1007       loadAnnotations();
1008     }
1009     else if (source == outputAnnotations)
1010     {
1011       outputAnnotations(true);
1012     }
1013     else if (source == outputFeatures)
1014     {
1015       outputFeatures(true, "Jalview");
1016     }
1017     else if (source == closeMenuItem)
1018     {
1019       closeMenuItem_actionPerformed();
1020     }
1021     else if (source == copy)
1022     {
1023       copy_actionPerformed();
1024     }
1025     else if (source == undoMenuItem)
1026     {
1027       undoMenuItem_actionPerformed();
1028     }
1029     else if (source == redoMenuItem)
1030     {
1031       redoMenuItem_actionPerformed();
1032     }
1033     else if (source == inputText)
1034     {
1035       inputText_actionPerformed();
1036     }
1037     else if (source == closeMenuItem)
1038     {
1039       closeMenuItem_actionPerformed();
1040     }
1041     else if (source == undoMenuItem)
1042     {
1043       undoMenuItem_actionPerformed();
1044     }
1045     else if (source == redoMenuItem)
1046     {
1047       redoMenuItem_actionPerformed();
1048     }
1049     else if (source == copy)
1050     {
1051       copy_actionPerformed();
1052     }
1053     else if (source == pasteNew)
1054     {
1055       pasteNew_actionPerformed();
1056     }
1057     else if (source == pasteThis)
1058     {
1059       pasteThis_actionPerformed();
1060     }
1061     else if (source == cut)
1062     {
1063       cut_actionPerformed();
1064     }
1065     else if (source == delete)
1066     {
1067       delete_actionPerformed();
1068     }
1069     else if (source == createGroup)
1070     {
1071       createGroup_actionPerformed();
1072     }
1073     else if (source == unGroup)
1074     {
1075       unGroup_actionPerformed();
1076     }
1077     else if (source == grpsFromSelection)
1078     {
1079       makeGrpsFromSelection_actionPerformed();
1080     }
1081     else if (source == deleteGroups)
1082     {
1083       deleteGroups_actionPerformed();
1084     }
1085     else if (source == selectAllSequenceMenuItem)
1086     {
1087       selectAllSequenceMenuItem_actionPerformed();
1088     }
1089     else if (source == deselectAllSequenceMenuItem)
1090     {
1091       deselectAllSequenceMenuItem_actionPerformed();
1092     }
1093     else if (source == invertSequenceMenuItem)
1094     {
1095       invertSequenceMenuItem_actionPerformed();
1096       // uncomment to slave sequence selections in split frame
1097       // viewport.sendSelection();
1098     }
1099     else if (source == invertColSel)
1100     {
1101       viewport.invertColumnSelection();
1102       alignPanel.paintAlignment(false, false);
1103       viewport.sendSelection();
1104     }
1105     else if (source == remove2LeftMenuItem)
1106     {
1107       trimAlignment(true);
1108     }
1109     else if (source == remove2RightMenuItem)
1110     {
1111       trimAlignment(false);
1112     }
1113     else if (source == removeGappedColumnMenuItem)
1114     {
1115       removeGappedColumnMenuItem_actionPerformed();
1116     }
1117     else if (source == removeAllGapsMenuItem)
1118     {
1119       removeAllGapsMenuItem_actionPerformed();
1120     }
1121     else if (source == findMenuItem)
1122     {
1123       findMenuItem_actionPerformed();
1124     }
1125     else if (source == font)
1126     {
1127       new FontChooser(alignPanel);
1128     }
1129     else if (source == newView)
1130     {
1131       newView(null);
1132     }
1133     else if (source == showColumns)
1134     {
1135       viewport.showAllHiddenColumns();
1136       alignPanel.paintAlignment(true, true);
1137       viewport.sendSelection();
1138     }
1139     else if (source == showSeqs)
1140     {
1141       viewport.showAllHiddenSeqs();
1142       alignPanel.paintAlignment(true, true);
1143       // uncomment if we want to slave sequence selections in split frame
1144       // viewport.sendSelection();
1145     }
1146     else if (source == hideColumns)
1147     {
1148       viewport.hideSelectedColumns();
1149       alignPanel.paintAlignment(true, true);
1150       viewport.sendSelection();
1151     }
1152     else if (source == hideSequences
1153             && viewport.getSelectionGroup() != null)
1154     {
1155       viewport.hideAllSelectedSeqs();
1156       alignPanel.paintAlignment(true, true);
1157       // uncomment if we want to slave sequence selections in split frame
1158       // viewport.sendSelection();
1159     }
1160     else if (source == hideAllButSelection)
1161     {
1162       toggleHiddenRegions(false, false);
1163       alignPanel.paintAlignment(true, true);
1164       viewport.sendSelection();
1165     }
1166     else if (source == hideAllSelection)
1167     {
1168       SequenceGroup sg = viewport.getSelectionGroup();
1169       viewport.expandColSelection(sg, false);
1170       viewport.hideAllSelectedSeqs();
1171       viewport.hideSelectedColumns();
1172       alignPanel.paintAlignment(true, true);
1173       viewport.sendSelection();
1174     }
1175     else if (source == showAllHidden)
1176     {
1177       viewport.showAllHiddenColumns();
1178       viewport.showAllHiddenSeqs();
1179       alignPanel.paintAlignment(true, true);
1180       viewport.sendSelection();
1181     }
1182     else if (source == showGroupConsensus)
1183     {
1184       showGroupConsensus_actionPerformed();
1185     }
1186     else if (source == showGroupConservation)
1187     {
1188       showGroupConservation_actionPerformed();
1189     }
1190     else if (source == showSequenceLogo)
1191     {
1192       showSequenceLogo_actionPerformed();
1193     }
1194     else if (source == normSequenceLogo)
1195     {
1196       normSequenceLogo_actionPerformed();
1197     }
1198     else if (source == showConsensusHistogram)
1199     {
1200       showConsensusHistogram_actionPerformed();
1201     }
1202     else if (source == applyAutoAnnotationSettings)
1203     {
1204       applyAutoAnnotationSettings_actionPerformed();
1205     }
1206     else if (source == featureSettings)
1207     {
1208       showFeatureSettingsUI();
1209     }
1210     else if (source == alProperties)
1211     {
1212       StringBuffer contents = new jalview.io.AlignmentProperties(
1213               viewport.getAlignment()).formatAsString();
1214       CutAndPasteTransfer cap = new CutAndPasteTransfer(false, this);
1215       cap.setText(contents.toString());
1216       Frame frame = new Frame();
1217       frame.add(cap);
1218       jalview.bin.JalviewLite.addFrame(frame, MessageManager
1219               .formatMessage("label.alignment_properties", new String[]
1220               { getTitle() }), 400, 250);
1221     }
1222     else if (source == overviewMenuItem)
1223     {
1224       overviewMenuItem_actionPerformed();
1225     }
1226     else if (source == noColourmenuItem)
1227     {
1228       changeColour(null);
1229     }
1230     else if (source == clustalColour)
1231     {
1232       abovePIDThreshold.setState(false);
1233       changeColour(new ClustalxColourScheme(viewport.getAlignment(), null));
1234     }
1235     else if (source == zappoColour)
1236     {
1237       changeColour(new ZappoColourScheme());
1238     }
1239     else if (source == taylorColour)
1240     {
1241       changeColour(new TaylorColourScheme());
1242     }
1243     else if (source == hydrophobicityColour)
1244     {
1245       changeColour(new HydrophobicColourScheme());
1246     }
1247     else if (source == helixColour)
1248     {
1249       changeColour(new HelixColourScheme());
1250     }
1251     else if (source == strandColour)
1252     {
1253       changeColour(new StrandColourScheme());
1254     }
1255     else if (source == turnColour)
1256     {
1257       changeColour(new TurnColourScheme());
1258     }
1259     else if (source == buriedColour)
1260     {
1261       changeColour(new BuriedColourScheme());
1262     }
1263     else if (source == nucleotideColour)
1264     {
1265       changeColour(new NucleotideColourScheme());
1266     }
1267     else if (source == purinePyrimidineColour)
1268     {
1269       changeColour(new PurinePyrimidineColourScheme());
1270     }
1271     // else if (source == RNAInteractionColour)
1272     // {
1273     // changeColour(new RNAInteractionColourScheme());
1274     // }
1275     else if (source == RNAHelixColour)
1276     {
1277       changeColour(new RNAHelicesColour(viewport.getAlignment()));
1278       // new RNAHelicesColourChooser(viewport, alignPanel);
1279     }
1280     else if (source == modifyPID)
1281     {
1282       modifyPID_actionPerformed();
1283     }
1284     else if (source == modifyConservation)
1285     {
1286       modifyConservation_actionPerformed();
1287     }
1288     else if (source == userDefinedColour)
1289     {
1290       new UserDefinedColours(alignPanel, null);
1291     }
1292     else if (source == PIDColour)
1293     {
1294       changeColour(new PIDColourScheme());
1295     }
1296     else if (source == BLOSUM62Colour)
1297     {
1298       changeColour(new Blosum62ColourScheme());
1299     }
1300     else if (source == tcoffeeColour)
1301     {
1302       changeColour(new TCoffeeColourScheme(alignPanel.getAlignment()));
1303     }
1304     else if (source == annotationColour)
1305     {
1306       new AnnotationColourChooser(viewport, alignPanel);
1307     }
1308     else if (source == annotationColumnSelection)
1309     {
1310       new AnnotationColumnChooser(viewport, alignPanel);
1311     }
1312     else if (source == sortPairwiseMenuItem)
1313     {
1314       sortPairwiseMenuItem_actionPerformed();
1315     }
1316     else if (source == sortIDMenuItem)
1317     {
1318       sortIDMenuItem_actionPerformed();
1319     }
1320     else if (source == sortLengthMenuItem)
1321     {
1322       sortLengthMenuItem_actionPerformed();
1323     }
1324     else if (source == sortGroupMenuItem)
1325     {
1326       sortGroupMenuItem_actionPerformed();
1327     }
1328     else if (source == sortEValueMenuItem)
1329     {
1330       sortEValueMenuItem_actionPerformed();
1331     }
1332     else if (source == sortBitScoreMenuItem)
1333     {
1334       sortBitScoreMenuItem_actionPerformed();
1335     }
1336     else if (source == removeRedundancyMenuItem)
1337     {
1338       removeRedundancyMenuItem_actionPerformed();
1339     }
1340     else if (source == pairwiseAlignmentMenuItem)
1341     {
1342       pairwiseAlignmentMenuItem_actionPerformed();
1343     }
1344     else if (source == PCAMenuItem)
1345     {
1346       PCAMenuItem_actionPerformed();
1347     }
1348     else if (source == averageDistanceTreeMenuItem)
1349     {
1350       averageDistanceTreeMenuItem_actionPerformed();
1351     }
1352     else if (source == neighbourTreeMenuItem)
1353     {
1354       neighbourTreeMenuItem_actionPerformed();
1355     }
1356     else if (source == njTreeBlosumMenuItem)
1357     {
1358       njTreeBlosumMenuItem_actionPerformed();
1359     }
1360     else if (source == avDistanceTreeBlosumMenuItem)
1361     {
1362       avTreeBlosumMenuItem_actionPerformed();
1363     }
1364     else if (source == documentation)
1365     {
1366       documentation_actionPerformed();
1367     }
1368     else if (source == about)
1369     {
1370       about_actionPerformed();
1371     }
1372
1373   }
1374
1375   public void inputText_actionPerformed()
1376   {
1377     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, this);
1378     Frame frame = new Frame();
1379     frame.add(cap);
1380     jalview.bin.JalviewLite.addFrame(frame,
1381             MessageManager.getString("label.input_cut_paste"), 500, 500);
1382   }
1383
1384   protected void outputText_actionPerformed(ActionEvent e)
1385   {
1386     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, this);
1387     Frame frame = new Frame();
1388     frame.add(cap);
1389     JalviewLite.addFrame(frame, MessageManager
1390             .formatMessage("label.alignment_output_command", new Object[]
1391             { e.getActionCommand() }), 600, 500);
1392
1393     FileFormatI fileFormat = FileFormats.getInstance()
1394             .forName(e.getActionCommand());
1395     cap.setText(
1396             new AppletFormatAdapter(alignPanel).formatSequences(fileFormat,
1397                     viewport.getAlignment(), viewport.getShowJVSuffix()));
1398   }
1399
1400   public void loadAnnotations()
1401   {
1402     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, this);
1403     cap.setText(MessageManager
1404             .getString("label.paste_features_annotations_Tcoffee_here"));
1405     cap.setAnnotationImport();
1406     Frame frame = new Frame();
1407     frame.add(cap);
1408     jalview.bin.JalviewLite.addFrame(frame,
1409             MessageManager.getString("action.paste_annotations"), 400, 300);
1410
1411   }
1412
1413   public String outputAnnotations(boolean displayTextbox)
1414   {
1415     String annotation = new AnnotationFile()
1416             .printAnnotationsForView(viewport);
1417
1418     if (displayTextbox)
1419     {
1420       CutAndPasteTransfer cap = new CutAndPasteTransfer(false, this);
1421       Frame frame = new Frame();
1422       frame.add(cap);
1423       jalview.bin.JalviewLite.addFrame(frame,
1424               MessageManager.getString("label.annotations"), 600, 500);
1425       cap.setText(annotation);
1426     }
1427
1428     return annotation;
1429   }
1430
1431   private Map<String, FeatureColourI> getDisplayedFeatureCols()
1432   {
1433     if (alignPanel.getFeatureRenderer() != null
1434             && viewport.getFeaturesDisplayed() != null)
1435     {
1436       return alignPanel.getFeatureRenderer().getDisplayedFeatureCols();
1437
1438     }
1439     return null;
1440   }
1441
1442   private List<String> getDisplayedFeatureGroups()
1443   {
1444     if (alignPanel.getFeatureRenderer() != null
1445             && viewport.getFeaturesDisplayed() != null)
1446     {
1447       return alignPanel.getFeatureRenderer().getDisplayedFeatureGroups();
1448
1449     }
1450     return null;
1451   }
1452
1453   public String outputFeatures(boolean displayTextbox, String format)
1454   {
1455     String features;
1456     FeaturesFile formatter = new FeaturesFile();
1457     if (format.equalsIgnoreCase("Jalview"))
1458     {
1459       features = formatter.printJalviewFormat(
1460               viewport.getAlignment().getSequencesArray(),
1461               alignPanel.getFeatureRenderer(), true, false);
1462     }
1463     else
1464     {
1465       features = formatter.printGffFormat(viewport.getAlignment()
1466               .getSequencesArray(), alignPanel.getFeatureRenderer(), true,
1467               false);
1468     }
1469
1470     if (displayTextbox)
1471     {
1472       boolean frimport = false;
1473       if (features == null || features.equals("No Features Visible"))
1474       {
1475         features = "# No features visible - paste some and import them here.";
1476         frimport = true;
1477       }
1478
1479       CutAndPasteTransfer cap = new CutAndPasteTransfer(frimport, this);
1480       if (frimport)
1481       {
1482         cap.setAnnotationImport();
1483       }
1484       Frame frame = new Frame();
1485       frame.add(cap);
1486       jalview.bin.JalviewLite.addFrame(frame,
1487               MessageManager.getString("label.features"), 600, 500);
1488       cap.setText(features);
1489     }
1490     else
1491     {
1492       if (features == null)
1493       {
1494         features = "";
1495       }
1496     }
1497
1498     return features;
1499   }
1500
1501   void launchFullApplication()
1502   {
1503     StringBuffer url = new StringBuffer(jalviewServletURL);
1504
1505     // allow servlet parameters to be passed in applet parameter
1506     String firstSep = url.lastIndexOf("?") > url.lastIndexOf("/") ? "&"
1507             : "?";
1508     url.append(firstSep);
1509
1510     url.append(
1511             "open=" + appendProtocol(viewport.applet.getParameter("file")));
1512
1513     if (viewport.applet.getParameter("features") != null)
1514     {
1515       url.append("&features=");
1516       url.append(appendProtocol(viewport.applet.getParameter("features")));
1517     }
1518
1519     if (viewport.applet.getParameter("annotations") != null)
1520     {
1521       url.append("&annotations=");
1522       url.append(
1523               appendProtocol(viewport.applet.getParameter("annotations")));
1524     }
1525
1526     if (viewport.applet.getParameter("jnetfile") != null
1527             || viewport.applet.getParameter("jpredfile") != null)
1528     {
1529       url.append("&annotations=");
1530       url.append(appendProtocol(
1531               viewport.applet.getParameter("jnetfile") != null
1532                       ? viewport.applet.getParameter("jnetfile")
1533                       : viewport.applet.getParameter("jpredfile")));
1534     }
1535
1536     if (viewport.applet.getParameter("defaultColour") != null)
1537     {
1538       url.append("&colour=" + removeWhiteSpace(
1539               viewport.applet.getParameter("defaultColour")));
1540     }
1541
1542     if (viewport.applet.getParameter("userDefinedColour") != null)
1543     {
1544       url.append("&colour=" + removeWhiteSpace(
1545               viewport.applet.getParameter("userDefinedColour")));
1546     }
1547     if (viewport.applet.getParameter("tree") != null)
1548     {
1549       url.append("&tree="
1550               + appendProtocol(viewport.applet.getParameter("tree")));
1551     }
1552     if (viewport.applet.getParameter("treeFile") != null)
1553     {
1554       url.append("&tree="
1555               + appendProtocol(viewport.applet.getParameter("treeFile")));
1556     }
1557
1558     showURL(url.toString(), "FULL_APP");
1559   }
1560
1561   String removeWhiteSpace(String colour)
1562   {
1563     StringBuffer sb = new StringBuffer();
1564     for (int i = 0; i < colour.length(); i++)
1565     {
1566       if (Character.isWhitespace(colour.charAt(i)))
1567       {
1568         sb.append("%20");
1569       }
1570       else
1571       {
1572         sb.append(colour.charAt(i));
1573       }
1574     }
1575
1576     return sb.toString();
1577   }
1578
1579   String appendProtocol(String url)
1580   {
1581     try
1582     {
1583       new URL(url);
1584       url = URLEncoder.encode(url, "UTF-8");
1585     }
1586     /*
1587      * When we finally deprecate 1.1 compatibility, we can start to use
1588      * URLEncoder.encode(url,"UTF-8") and then we'll need this catch: catch
1589      * (UnsupportedEncodingException ex) { System.err.println("WARNING -
1590      * IMPLEMENTATION ERROR - UNSUPPORTED ENCODING EXCEPTION FOR "+url);
1591      * ex.printStackTrace(); }
1592      */
1593     catch (java.net.MalformedURLException ex)
1594     {
1595       url = viewport.applet.getCodeBase() + url;
1596     }
1597     catch (UnsupportedEncodingException ex)
1598     {
1599       System.err.println(
1600               "WARNING = IMPLEMENTATION ERROR - UNSUPPORTED ENCODING EXCEPTION FOR "
1601                       + url);
1602       ex.printStackTrace();
1603     }
1604     return url;
1605   }
1606
1607   public void closeMenuItem_actionPerformed()
1608   {
1609     PaintRefresher.RemoveComponent(alignPanel);
1610     if (alignPanel.seqPanel != null
1611             && alignPanel.seqPanel.seqCanvas != null)
1612     {
1613       PaintRefresher.RemoveComponent(alignPanel.seqPanel.seqCanvas);
1614     }
1615     if (alignPanel.idPanel != null && alignPanel.idPanel.idCanvas != null)
1616     {
1617       PaintRefresher.RemoveComponent(alignPanel.idPanel.idCanvas);
1618     }
1619
1620     if (PaintRefresher.components.size() == 0 && viewport.applet == null)
1621     {
1622       System.exit(0);
1623     }
1624
1625     viewport = null;
1626     if (alignPanel != null && alignPanel.overviewPanel != null)
1627     {
1628       alignPanel.overviewPanel.dispose();
1629     }
1630     alignPanel = null;
1631     this.dispose();
1632   }
1633
1634   /**
1635    * TODO: JAL-1104
1636    */
1637   void updateEditMenuBar()
1638   {
1639
1640     if (viewport.getHistoryList().size() > 0)
1641     {
1642       undoMenuItem.setEnabled(true);
1643       CommandI command = viewport.getHistoryList().peek();
1644       undoMenuItem.setLabel(MessageManager
1645               .formatMessage("label.undo_command", new Object[]
1646               { command.getDescription() }));
1647     }
1648     else
1649     {
1650       undoMenuItem.setEnabled(false);
1651       undoMenuItem.setLabel(MessageManager.getString("action.undo"));
1652     }
1653
1654     if (viewport.getRedoList().size() > 0)
1655     {
1656       redoMenuItem.setEnabled(true);
1657
1658       CommandI command = viewport.getRedoList().peek();
1659       redoMenuItem.setLabel(MessageManager
1660               .formatMessage("label.redo_command", new Object[]
1661               { command.getDescription() }));
1662     }
1663     else
1664     {
1665       redoMenuItem.setEnabled(false);
1666       redoMenuItem.setLabel(MessageManager.getString("action.redo"));
1667     }
1668   }
1669
1670   /**
1671    * TODO: JAL-1104
1672    */
1673   @Override
1674   public void addHistoryItem(CommandI command)
1675   {
1676     if (command.getSize() > 0)
1677     {
1678       viewport.addToHistoryList(command);
1679       viewport.clearRedoList();
1680       updateEditMenuBar();
1681       viewport.updateHiddenColumns();
1682     }
1683   }
1684
1685   /**
1686    * TODO: JAL-1104 DOCUMENT ME!
1687    * 
1688    * @param e
1689    *          DOCUMENT ME!
1690    */
1691   protected void undoMenuItem_actionPerformed()
1692   {
1693     if (viewport.getHistoryList().isEmpty())
1694     {
1695       return;
1696     }
1697
1698     CommandI command = viewport.getHistoryList().pop();
1699     viewport.addToRedoList(command);
1700     command.undoCommand(null);
1701
1702     AlignmentViewport originalSource = getOriginatingSource(command);
1703     // JBPNote Test
1704     if (originalSource != viewport)
1705     {
1706       System.err
1707               .println("Warning: Viewport object mismatch whilst undoing");
1708     }
1709     originalSource.updateHiddenColumns(); // originalSource.hasHiddenColumns =
1710                                           // viewport.getColumnSelection().getHiddenColumns()
1711                                           // != null;
1712     updateEditMenuBar();
1713     originalSource.firePropertyChange("alignment", null,
1714             originalSource.getAlignment().getSequences());
1715   }
1716
1717   /**
1718    * TODO: JAL-1104 DOCUMENT ME!
1719    * 
1720    * @param e
1721    *          DOCUMENT ME!
1722    */
1723   protected void redoMenuItem_actionPerformed()
1724   {
1725     if (viewport.getRedoList().isEmpty())
1726     {
1727       return;
1728     }
1729
1730     CommandI command = viewport.getRedoList().pop();
1731     viewport.addToHistoryList(command);
1732     command.doCommand(null);
1733
1734     AlignmentViewport originalSource = getOriginatingSource(command);
1735     // JBPNote Test
1736     if (originalSource != viewport)
1737     {
1738       System.err
1739               .println("Warning: Viewport object mismatch whilst re-doing");
1740     }
1741     originalSource.updateHiddenColumns(); // sethasHiddenColumns(); =
1742                                           // viewport.getColumnSelection().getHiddenColumns()
1743                                           // != null;
1744
1745     updateEditMenuBar();
1746     originalSource.firePropertyChange("alignment", null,
1747             originalSource.getAlignment().getSequences());
1748   }
1749
1750   AlignmentViewport getOriginatingSource(CommandI command)
1751   {
1752     AlignmentViewport originalSource = null;
1753     // For sequence removal and addition, we need to fire
1754     // the property change event FROM the viewport where the
1755     // original alignment was altered
1756     AlignmentI al = null;
1757     if (command instanceof EditCommand)
1758     {
1759       EditCommand editCommand = (EditCommand) command;
1760       al = editCommand.getAlignment();
1761       Vector comps = PaintRefresher.components
1762               .get(viewport.getSequenceSetId());
1763       for (int i = 0; i < comps.size(); i++)
1764       {
1765         if (comps.elementAt(i) instanceof AlignmentPanel)
1766         {
1767           if (al == ((AlignmentPanel) comps.elementAt(i)).av.getAlignment())
1768           {
1769             originalSource = ((AlignmentPanel) comps.elementAt(i)).av;
1770             break;
1771           }
1772         }
1773       }
1774     }
1775
1776     if (originalSource == null)
1777     {
1778       // The original view is closed, we must validate
1779       // the current view against the closed view first
1780       if (al != null)
1781       {
1782         PaintRefresher.validateSequences(al, viewport.getAlignment());
1783       }
1784
1785       originalSource = viewport;
1786     }
1787
1788     return originalSource;
1789   }
1790
1791   /**
1792    * Move the currently selected sequences up or down one position in the
1793    * alignment
1794    * 
1795    * @param up
1796    */
1797   public void moveSelectedSequences(boolean up)
1798   {
1799     SequenceGroup sg = viewport.getSelectionGroup();
1800     if (sg == null)
1801     {
1802       return;
1803     }
1804     viewport.getAlignment().moveSelectedSequencesByOne(sg,
1805             up ? null : viewport.getHiddenRepSequences(), up);
1806     alignPanel.paintAlignment(true, false);
1807
1808     /*
1809      * Also move cDNA/protein complement sequences
1810      */
1811     AlignViewportI complement = viewport.getCodingComplement();
1812     if (complement != null)
1813     {
1814       SequenceGroup mappedSelection = MappingUtils.mapSequenceGroup(sg,
1815               viewport, complement);
1816       complement.getAlignment().moveSelectedSequencesByOne(mappedSelection,
1817               up ? null : complement.getHiddenRepSequences(), up);
1818       getSplitFrame().getComplement(this).alignPanel.paintAlignment(true,
1819               false);
1820     }
1821   }
1822
1823   synchronized void slideSequences(boolean right, int size)
1824   {
1825     List<SequenceI> sg = new Vector<>();
1826     if (viewport.cursorMode)
1827     {
1828       sg.add(viewport.getAlignment()
1829               .getSequenceAt(alignPanel.seqPanel.seqCanvas.cursorY));
1830     }
1831     else if (viewport.getSelectionGroup() != null
1832             && viewport.getSelectionGroup().getSize() != viewport
1833                     .getAlignment().getHeight())
1834     {
1835       sg = viewport.getSelectionGroup()
1836               .getSequences(viewport.getHiddenRepSequences());
1837     }
1838
1839     if (sg.size() < 1)
1840     {
1841       return;
1842     }
1843
1844     Vector<SequenceI> invertGroup = new Vector();
1845
1846     for (int i = 0; i < viewport.getAlignment().getHeight(); i++)
1847     {
1848       if (!sg.contains(viewport.getAlignment().getSequenceAt(i)))
1849       {
1850         invertGroup.addElement(viewport.getAlignment().getSequenceAt(i));
1851       }
1852     }
1853
1854     SequenceI[] seqs1 = sg.toArray(new SequenceI[sg.size()]);
1855
1856     SequenceI[] seqs2 = invertGroup
1857             .toArray(new SequenceI[invertGroup.size()]);
1858     for (int i = 0; i < invertGroup.size(); i++)
1859     {
1860       seqs2[i] = invertGroup.elementAt(i);
1861     }
1862
1863     SlideSequencesCommand ssc;
1864     if (right)
1865     {
1866       ssc = new SlideSequencesCommand("Slide Sequences", seqs2, seqs1, size,
1867               viewport.getGapCharacter());
1868     }
1869     else
1870     {
1871       ssc = new SlideSequencesCommand("Slide Sequences", seqs1, seqs2, size,
1872               viewport.getGapCharacter());
1873     }
1874
1875     int groupAdjustment = 0;
1876     if (ssc.getGapsInsertedBegin() && right)
1877     {
1878       if (viewport.cursorMode)
1879       {
1880         alignPanel.seqPanel.moveCursor(size, 0);
1881       }
1882       else
1883       {
1884         groupAdjustment = size;
1885       }
1886     }
1887     else if (!ssc.getGapsInsertedBegin() && !right)
1888     {
1889       if (viewport.cursorMode)
1890       {
1891         alignPanel.seqPanel.moveCursor(-size, 0);
1892       }
1893       else
1894       {
1895         groupAdjustment = -size;
1896       }
1897     }
1898
1899     if (groupAdjustment != 0)
1900     {
1901       viewport.getSelectionGroup().setStartRes(
1902               viewport.getSelectionGroup().getStartRes() + groupAdjustment);
1903       viewport.getSelectionGroup().setEndRes(
1904               viewport.getSelectionGroup().getEndRes() + groupAdjustment);
1905     }
1906
1907     boolean appendHistoryItem = false;
1908     Deque<CommandI> historyList = viewport.getHistoryList();
1909     if (historyList != null && historyList.size() > 0
1910             && historyList.peek() instanceof SlideSequencesCommand)
1911     {
1912       appendHistoryItem = ssc.appendSlideCommand(
1913               (SlideSequencesCommand) historyList.peek());
1914     }
1915
1916     if (!appendHistoryItem)
1917     {
1918       addHistoryItem(ssc);
1919     }
1920
1921     repaint();
1922   }
1923
1924   static StringBuffer copiedSequences;
1925
1926   static HiddenColumns copiedHiddenColumns;
1927
1928   protected void copy_actionPerformed()
1929   {
1930     if (viewport.getSelectionGroup() == null)
1931     {
1932       return;
1933     }
1934
1935     SequenceGroup sg = viewport.getSelectionGroup();
1936     copiedSequences = new StringBuffer();
1937     Map<Integer, SequenceI> orderedSeqs = new HashMap<>();
1938     for (int i = 0; i < sg.getSize(); i++)
1939     {
1940       SequenceI seq = sg.getSequenceAt(i);
1941       int index = viewport.getAlignment().findIndex(seq);
1942       orderedSeqs.put(index, seq);
1943     }
1944
1945     int index = 0, startRes, endRes;
1946     char ch;
1947
1948     if (viewport.hasHiddenColumns() && viewport.getSelectionGroup() != null)
1949     {
1950       int hiddenOffset = viewport.getSelectionGroup().getStartRes();
1951       int hiddenCutoff = viewport.getSelectionGroup().getEndRes();
1952
1953       // create new HiddenColumns object with copy of hidden regions
1954       // between startRes and endRes, offset by startRes
1955       copiedHiddenColumns = new HiddenColumns(
1956               viewport.getAlignment().getHiddenColumns(), hiddenOffset,
1957               hiddenCutoff, hiddenOffset);
1958     }
1959     else
1960     {
1961       copiedHiddenColumns = null;
1962     }
1963
1964     for (int i = 0; i < sg.getSize(); i++)
1965     {
1966       SequenceI seq = null;
1967
1968       while (seq == null)
1969       {
1970         if (orderedSeqs.containsKey(index))
1971         {
1972           seq = orderedSeqs.get(index);
1973           index++;
1974           break;
1975         }
1976         else
1977         {
1978           index++;
1979         }
1980       }
1981
1982       // FIND START RES
1983       // Returns residue following index if gap
1984       startRes = seq.findPosition(sg.getStartRes());
1985
1986       // FIND END RES
1987       // Need to find the residue preceeding index if gap
1988       endRes = 0;
1989
1990       for (int j = 0; j < sg.getEndRes() + 1 && j < seq.getLength(); j++)
1991       {
1992         ch = seq.getCharAt(j);
1993         if (!jalview.util.Comparison.isGap((ch)))
1994         {
1995           endRes++;
1996         }
1997       }
1998
1999       if (endRes > 0)
2000       {
2001         endRes += seq.getStart() - 1;
2002       }
2003
2004       copiedSequences.append(seq.getName() + "\t" + startRes + "\t" + endRes
2005               + "\t" + seq.getSequenceAsString(sg.getStartRes(),
2006                       sg.getEndRes() + 1)
2007               + "\n");
2008     }
2009
2010   }
2011
2012   protected void pasteNew_actionPerformed()
2013   {
2014     paste(true);
2015   }
2016
2017   protected void pasteThis_actionPerformed()
2018   {
2019     paste(false);
2020   }
2021
2022   void paste(boolean newAlignment)
2023   {
2024     try
2025     {
2026       if (copiedSequences == null)
2027       {
2028         return;
2029       }
2030
2031       StringTokenizer st = new StringTokenizer(copiedSequences.toString(),
2032               "\t");
2033       Vector seqs = new Vector();
2034       while (st.hasMoreElements())
2035       {
2036         String name = st.nextToken();
2037         int start = Integer.parseInt(st.nextToken());
2038         int end = Integer.parseInt(st.nextToken());
2039         seqs.addElement(new Sequence(name, st.nextToken(), start, end));
2040       }
2041       SequenceI[] newSeqs = new SequenceI[seqs.size()];
2042       for (int i = 0; i < seqs.size(); i++)
2043       {
2044         newSeqs[i] = (SequenceI) seqs.elementAt(i);
2045       }
2046
2047       if (newAlignment)
2048       {
2049         String newtitle = MessageManager
2050                 .getString("label.copied_sequences");
2051         if (getTitle().startsWith(
2052                 MessageManager.getString("label.copied_sequences")))
2053         {
2054           newtitle = getTitle();
2055         }
2056         else
2057         {
2058           newtitle = newtitle.concat(MessageManager
2059                   .formatMessage("label.from_msname", new String[]
2060                   { getTitle() }));
2061         }
2062         AlignFrame af = new AlignFrame(new Alignment(newSeqs),
2063                 viewport.applet, newtitle, false);
2064         af.viewport.setHiddenColumns(copiedHiddenColumns);
2065
2066         jalview.bin.JalviewLite.addFrame(af, newtitle, frameWidth,
2067                 frameHeight);
2068       }
2069       else
2070       {
2071         addSequences(newSeqs);
2072       }
2073
2074     } catch (Exception ex)
2075     {
2076     } // could be anything being pasted in here
2077
2078   }
2079
2080   void addSequences(SequenceI[] seqs)
2081   {
2082     for (int i = 0; i < seqs.length; i++)
2083     {
2084       viewport.getAlignment().addSequence(seqs[i]);
2085     }
2086
2087     // !newAlignment
2088     addHistoryItem(new EditCommand(
2089             MessageManager.getString("label.add_sequences"), Action.PASTE,
2090             seqs, 0, viewport.getAlignment().getWidth(),
2091             viewport.getAlignment()));
2092
2093     viewport.getRanges().setEndSeq(viewport.getAlignment().getHeight());
2094     viewport.getAlignment().getWidth();
2095     viewport.firePropertyChange("alignment", null,
2096             viewport.getAlignment().getSequences());
2097
2098   }
2099
2100   protected void cut_actionPerformed()
2101   {
2102     copy_actionPerformed();
2103     delete_actionPerformed();
2104   }
2105
2106   protected void delete_actionPerformed()
2107   {
2108
2109     SequenceGroup sg = viewport.getSelectionGroup();
2110     if (sg == null)
2111     {
2112       return;
2113     }
2114
2115     Vector seqs = new Vector();
2116     SequenceI seq;
2117     for (int i = 0; i < sg.getSize(); i++)
2118     {
2119       seq = sg.getSequenceAt(i);
2120       seqs.addElement(seq);
2121     }
2122
2123     /*
2124      * If the cut affects all sequences, warn, remove highlighted columns
2125      */
2126     if (sg.getSize() == viewport.getAlignment().getHeight())
2127     {
2128       boolean isEntireAlignWidth = (((sg.getEndRes() - sg.getStartRes())
2129               + 1) == viewport.getAlignment().getWidth()) ? true : false;
2130       if (isEntireAlignWidth)
2131       {
2132         String title = MessageManager.getString("label.delete_all");
2133         Panel infoPanel = new Panel();
2134         infoPanel.setLayout(new FlowLayout());
2135         infoPanel.add(
2136                 new Label(MessageManager.getString("warn.delete_all")));
2137
2138         final JVDialog dialog = new JVDialog(this, title, true, 400, 200);
2139         dialog.setMainPanel(infoPanel);
2140         dialog.ok.setLabel(MessageManager.getString("action.ok"));
2141         dialog.cancel.setLabel(MessageManager.getString("action.cancel"));
2142         dialog.setVisible(true);
2143
2144         if (!dialog.accept)
2145         {
2146           return;
2147         }
2148       }
2149       viewport.getColumnSelection().removeElements(sg.getStartRes(),
2150               sg.getEndRes() + 1);
2151     }
2152
2153     SequenceI[] cut = new SequenceI[seqs.size()];
2154     for (int i = 0; i < seqs.size(); i++)
2155     {
2156       cut[i] = (SequenceI) seqs.elementAt(i);
2157     }
2158
2159     /*
2160      * //ADD HISTORY ITEM
2161      */
2162     addHistoryItem(new EditCommand(
2163             MessageManager.getString("label.cut_sequences"), Action.CUT,
2164             cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
2165             viewport.getAlignment()));
2166
2167     viewport.setSelectionGroup(null);
2168     viewport.getAlignment().deleteGroup(sg);
2169
2170     viewport.firePropertyChange("alignment", null,
2171             viewport.getAlignment().getSequences());
2172
2173     if (viewport.getAlignment().getHeight() < 1)
2174     {
2175       this.setVisible(false);
2176     }
2177     viewport.sendSelection();
2178   }
2179
2180   /**
2181    * group consensus toggled
2182    * 
2183    */
2184   protected void showGroupConsensus_actionPerformed()
2185   {
2186     viewport.setShowGroupConsensus(showGroupConsensus.getState());
2187     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2188
2189   }
2190
2191   /**
2192    * group conservation toggled.
2193    */
2194   protected void showGroupConservation_actionPerformed()
2195   {
2196     viewport.setShowGroupConservation(showGroupConservation.getState());
2197     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2198   }
2199
2200   /*
2201    * (non-Javadoc)
2202    * 
2203    * @see
2204    * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt
2205    * .event.ActionEvent)
2206    */
2207   protected void showConsensusHistogram_actionPerformed()
2208   {
2209     viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
2210     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2211   }
2212
2213   /*
2214    * (non-Javadoc)
2215    * 
2216    * @see
2217    * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt
2218    * .event.ActionEvent)
2219    */
2220   protected void showSequenceLogo_actionPerformed()
2221   {
2222     viewport.setShowSequenceLogo(showSequenceLogo.getState());
2223     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2224   }
2225
2226   protected void normSequenceLogo_actionPerformed()
2227   {
2228     showSequenceLogo.setState(true);
2229     viewport.setShowSequenceLogo(true);
2230     viewport.setNormaliseSequenceLogo(normSequenceLogo.getState());
2231     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2232   }
2233
2234   protected void applyAutoAnnotationSettings_actionPerformed()
2235   {
2236     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2237   }
2238
2239   protected void makeGrpsFromSelection_actionPerformed()
2240   {
2241     if (avc.makeGroupsFromSelection())
2242     {
2243       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
2244       alignPanel.updateAnnotation();
2245       alignPanel.paintAlignment(true, true);
2246     }
2247   }
2248
2249   protected void createGroup_actionPerformed()
2250   {
2251     avc.createGroup();
2252   }
2253
2254   protected void unGroup_actionPerformed()
2255   {
2256     if (avc.unGroup())
2257     {
2258       alignPanel.alignmentChanged();
2259     }
2260   }
2261
2262   protected void deleteGroups_actionPerformed()
2263   {
2264     if (avc.deleteGroups())
2265     {
2266       alignPanel.alignmentChanged();
2267     }
2268   }
2269
2270   public void selectAllSequenceMenuItem_actionPerformed()
2271   {
2272     SequenceGroup sg = new SequenceGroup();
2273     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2274     {
2275       sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
2276     }
2277     sg.setEndRes(viewport.getAlignment().getWidth() - 1);
2278     viewport.setSelectionGroup(sg);
2279     // JAL-2034 - should delegate to
2280     // alignPanel to decide if overview needs
2281     // updating.
2282     alignPanel.paintAlignment(false, false);
2283     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2284     viewport.sendSelection();
2285   }
2286
2287   public void deselectAllSequenceMenuItem_actionPerformed()
2288   {
2289     if (viewport.cursorMode)
2290     {
2291       alignPanel.seqPanel.keyboardNo1 = null;
2292       alignPanel.seqPanel.keyboardNo2 = null;
2293     }
2294     viewport.setSelectionGroup(null);
2295     viewport.getColumnSelection().clear();
2296     viewport.setSelectionGroup(null);
2297     alignPanel.idPanel.idCanvas.searchResults = null;
2298     alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);
2299     // JAL-2034 - should delegate to
2300     // alignPanel to decide if overview needs
2301     // updating.
2302     alignPanel.paintAlignment(false, false);
2303     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2304     viewport.sendSelection();
2305   }
2306
2307   public void invertSequenceMenuItem_actionPerformed()
2308   {
2309     SequenceGroup sg = viewport.getSelectionGroup();
2310     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2311     {
2312       sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
2313     }
2314
2315     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2316     viewport.sendSelection();
2317   }
2318
2319   public void invertColSel_actionPerformed()
2320   {
2321     viewport.invertColumnSelection();
2322     alignPanel.paintAlignment(true, false);
2323     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2324     viewport.sendSelection();
2325   }
2326
2327   void trimAlignment(boolean trimLeft)
2328   {
2329     AlignmentI al = viewport.getAlignment();
2330     ViewportRanges ranges = viewport.getRanges();
2331     ColumnSelection colSel = viewport.getColumnSelection();
2332     int column;
2333
2334     if (!colSel.isEmpty())
2335     {
2336       if (trimLeft)
2337       {
2338         column = colSel.getMin();
2339       }
2340       else
2341       {
2342         column = colSel.getMax();
2343       }
2344
2345       SequenceI[] seqs;
2346       if (viewport.getSelectionGroup() != null)
2347       {
2348         seqs = viewport.getSelectionGroup()
2349                 .getSequencesAsArray(viewport.getHiddenRepSequences());
2350       }
2351       else
2352       {
2353         seqs = al.getSequencesArray();
2354       }
2355
2356       TrimRegionCommand trimRegion;
2357       if (trimLeft)
2358       {
2359         trimRegion = new TrimRegionCommand("Remove Left", true, seqs,
2360                 column, al);
2361         ranges.setStartRes(0);
2362       }
2363       else
2364       {
2365         trimRegion = new TrimRegionCommand("Remove Right", false, seqs,
2366                 column, al);
2367       }
2368
2369       statusBar.setText(MessageManager
2370               .formatMessage("label.removed_columns", new String[]
2371               { Integer.valueOf(trimRegion.getSize()).toString() }));
2372       addHistoryItem(trimRegion);
2373
2374       for (SequenceGroup sg : al.getGroups())
2375       {
2376         if ((trimLeft && !sg.adjustForRemoveLeft(column))
2377                 || (!trimLeft && !sg.adjustForRemoveRight(column)))
2378         {
2379           al.deleteGroup(sg);
2380         }
2381       }
2382
2383       viewport.firePropertyChange("alignment", null, al.getSequences());
2384     }
2385   }
2386
2387   public void removeGappedColumnMenuItem_actionPerformed()
2388   {
2389     AlignmentI al = viewport.getAlignment();
2390     ViewportRanges ranges = viewport.getRanges();
2391     int start = 0;
2392     int end = ranges.getAbsoluteAlignmentWidth() - 1;
2393
2394     SequenceI[] seqs;
2395     if (viewport.getSelectionGroup() != null)
2396     {
2397       seqs = viewport.getSelectionGroup()
2398               .getSequencesAsArray(viewport.getHiddenRepSequences());
2399       start = viewport.getSelectionGroup().getStartRes();
2400       end = viewport.getSelectionGroup().getEndRes();
2401     }
2402     else
2403     {
2404       seqs = viewport.getAlignment().getSequencesArray();
2405     }
2406
2407     RemoveGapColCommand removeGapCols = new RemoveGapColCommand(
2408             "Remove Gapped Columns", seqs, start, end,
2409             viewport.getAlignment());
2410
2411     addHistoryItem(removeGapCols);
2412
2413     statusBar.setText(MessageManager
2414             .formatMessage("label.removed_empty_columns", new String[]
2415             { Integer.valueOf(removeGapCols.getSize()).toString() }));
2416
2417     // This is to maintain viewport position on first residue
2418     // of first sequence
2419     SequenceI seq = al.getSequenceAt(0);
2420     int startRes = seq.findPosition(ranges.getStartRes());
2421     // ShiftList shifts;
2422     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
2423     // edit.alColumnChanges=shifts.getInverse();
2424     // if (viewport.hasHiddenColumns)
2425     // viewport.getColumnSelection().compensateForEdits(shifts);
2426     ranges.setStartRes(seq.findIndex(startRes) - 1);
2427     viewport.firePropertyChange("alignment", null, al.getSequences());
2428
2429   }
2430
2431   public void removeAllGapsMenuItem_actionPerformed()
2432   {
2433     AlignmentI al = viewport.getAlignment();
2434     ViewportRanges ranges = viewport.getRanges();
2435     int start = 0;
2436     int end = ranges.getAbsoluteAlignmentWidth() - 1;
2437
2438     SequenceI[] seqs;
2439     if (viewport.getSelectionGroup() != null)
2440     {
2441       seqs = viewport.getSelectionGroup()
2442               .getSequencesAsArray(viewport.getHiddenRepSequences());
2443       start = viewport.getSelectionGroup().getStartRes();
2444       end = viewport.getSelectionGroup().getEndRes();
2445     }
2446     else
2447     {
2448       seqs = viewport.getAlignment().getSequencesArray();
2449     }
2450
2451     // This is to maintain viewport position on first residue
2452     // of first sequence
2453     SequenceI seq = al.getSequenceAt(0);
2454     int startRes = seq.findPosition(ranges.getStartRes());
2455
2456     addHistoryItem(
2457             new RemoveGapsCommand("Remove Gaps", seqs, start, end, al));
2458
2459     ranges.setStartRes(seq.findIndex(startRes) - 1);
2460
2461     viewport.firePropertyChange("alignment", null, al.getSequences());
2462
2463   }
2464
2465   public void findMenuItem_actionPerformed()
2466   {
2467     new Finder(alignPanel);
2468   }
2469
2470   /**
2471    * create a new view derived from the current view
2472    * 
2473    * @param viewtitle
2474    * @return frame for the new view
2475    */
2476   public AlignFrame newView(String viewtitle)
2477   {
2478     AlignmentI newal;
2479     if (viewport.hasHiddenRows())
2480     {
2481       newal = new Alignment(viewport.getAlignment().getHiddenSequences()
2482               .getFullAlignment().getSequencesArray());
2483     }
2484     else
2485     {
2486       newal = new Alignment(viewport.getAlignment().getSequencesArray());
2487     }
2488
2489     if (viewport.getAlignment().getAlignmentAnnotation() != null)
2490     {
2491       for (int i = 0; i < viewport.getAlignment()
2492               .getAlignmentAnnotation().length; i++)
2493       {
2494         if (!viewport.getAlignment()
2495                 .getAlignmentAnnotation()[i].autoCalculated)
2496         {
2497           newal.addAnnotation(
2498                   viewport.getAlignment().getAlignmentAnnotation()[i]);
2499         }
2500       }
2501     }
2502
2503     AlignFrame newaf = new AlignFrame(newal, viewport.applet, "", false);
2504
2505     newaf.viewport.setSequenceSetId(alignPanel.av.getSequenceSetId());
2506     PaintRefresher.Register(alignPanel, alignPanel.av.getSequenceSetId());
2507     PaintRefresher.Register(newaf.alignPanel,
2508             newaf.alignPanel.av.getSequenceSetId());
2509
2510     PaintRefresher.Register(newaf.alignPanel.idPanel.idCanvas,
2511             newaf.alignPanel.av.getSequenceSetId());
2512     PaintRefresher.Register(newaf.alignPanel.seqPanel.seqCanvas,
2513             newaf.alignPanel.av.getSequenceSetId());
2514
2515     Vector comps = PaintRefresher.components
2516             .get(viewport.getSequenceSetId());
2517     int viewSize = -1;
2518     for (int i = 0; i < comps.size(); i++)
2519     {
2520       if (comps.elementAt(i) instanceof AlignmentPanel)
2521       {
2522         viewSize++;
2523       }
2524     }
2525
2526     String title = new String(this.getTitle());
2527     if (viewtitle != null)
2528     {
2529       title = viewtitle + " ( " + title + ")";
2530     }
2531     else
2532     {
2533       if (title.indexOf("(View") > -1)
2534       {
2535         title = title.substring(0, title.indexOf("(View"));
2536       }
2537       title += "(View " + viewSize + ")";
2538     }
2539
2540     newaf.setTitle(title.toString());
2541
2542     newaf.viewport.setHistoryList(viewport.getHistoryList());
2543     newaf.viewport.setRedoList(viewport.getRedoList());
2544     return newaf;
2545   }
2546
2547   /**
2548    * 
2549    * @return list of feature groups on the view
2550    */
2551   public String[] getFeatureGroups()
2552   {
2553     FeatureRenderer fr = null;
2554     if (alignPanel != null
2555             && (fr = alignPanel.getFeatureRenderer()) != null)
2556     {
2557       List<String> gps = fr.getFeatureGroups();
2558       String[] _gps = gps.toArray(new String[gps.size()]);
2559       return _gps;
2560     }
2561     return null;
2562   }
2563
2564   /**
2565    * get sequence feature groups that are hidden or shown
2566    * 
2567    * @param visible
2568    *          true is visible
2569    * @return list
2570    */
2571   public String[] getFeatureGroupsOfState(boolean visible)
2572   {
2573     FeatureRenderer fr = null;
2574     if (alignPanel != null
2575             && (fr = alignPanel.getFeatureRenderer()) != null)
2576     {
2577       List<String> gps = fr.getGroups(visible);
2578       String[] _gps = gps.toArray(new String[gps.size()]);
2579       return _gps;
2580     }
2581     return null;
2582   }
2583
2584   /**
2585    * Change the display state for the given feature groups
2586    * 
2587    * @param groups
2588    *          list of group strings
2589    * @param state
2590    *          visible or invisible
2591    */
2592   public void setFeatureGroupState(String[] groups, boolean state)
2593   {
2594     FeatureRenderer fr = null;
2595     this.sequenceFeatures.setState(true);
2596     viewport.setShowSequenceFeatures(true);
2597     if (alignPanel != null
2598             && (fr = alignPanel.getFeatureRenderer()) != null)
2599     {
2600
2601       fr.setGroupVisibility(Arrays.asList(groups), state);
2602       alignPanel.seqPanel.seqCanvas.repaint();
2603       if (alignPanel.overviewPanel != null)
2604       {
2605         alignPanel.overviewPanel.updateOverviewImage();
2606       }
2607     }
2608   }
2609
2610   public void seqLimits_itemStateChanged()
2611   {
2612     viewport.setShowJVSuffix(seqLimits.getState());
2613     alignPanel.fontChanged();
2614     alignPanel.paintAlignment(true, false);
2615   }
2616
2617   protected void colourTextMenuItem_actionPerformed()
2618   {
2619     viewport.setColourText(colourTextMenuItem.getState());
2620     alignPanel.paintAlignment(false, false);
2621   }
2622
2623   protected void displayNonconservedMenuItem_actionPerformed()
2624   {
2625     viewport.setShowUnconserved(displayNonconservedMenuItem.getState());
2626     alignPanel.paintAlignment(false, false);
2627   }
2628
2629   protected void wrapMenuItem_actionPerformed()
2630   {
2631     viewport.setWrapAlignment(wrapMenuItem.getState());
2632     alignPanel.setWrapAlignment(wrapMenuItem.getState());
2633     scaleAbove.setEnabled(wrapMenuItem.getState());
2634     scaleLeft.setEnabled(wrapMenuItem.getState());
2635     scaleRight.setEnabled(wrapMenuItem.getState());
2636     alignPanel.paintAlignment(true, false);
2637   }
2638
2639   public void overviewMenuItem_actionPerformed()
2640   {
2641     if (alignPanel.overviewPanel != null)
2642     {
2643       return;
2644     }
2645
2646     Frame frame = new Frame();
2647     final OverviewPanel overview = new OverviewPanel(alignPanel);
2648     frame.add(overview);
2649     // +50 must allow for applet frame window
2650     jalview.bin.JalviewLite.addFrame(frame, MessageManager
2651             .formatMessage("label.overview_params", new String[]
2652             { this.getTitle() }), overview.getPreferredSize().width,
2653             overview.getPreferredSize().height + 50);
2654
2655     frame.pack();
2656     final AlignmentPanel ap = alignPanel;
2657     frame.addWindowListener(new WindowAdapter()
2658     {
2659       @Override
2660       public void windowClosing(WindowEvent e)
2661       {
2662         overview.dispose();
2663         if (ap != null)
2664         {
2665           ap.setOverviewPanel(null);
2666         }
2667       };
2668     });
2669
2670     alignPanel.setOverviewPanel(overview);
2671
2672   }
2673
2674   @Override
2675   public void changeColour(ColourSchemeI cs)
2676   {
2677     viewport.setGlobalColourScheme(cs);
2678
2679     alignPanel.paintAlignment(true, true);
2680   }
2681
2682   protected void modifyPID_actionPerformed()
2683   {
2684     if (viewport.getAbovePIDThreshold()
2685             && viewport.getGlobalColourScheme() != null)
2686     {
2687       SliderPanel.setPIDSliderSource(alignPanel,
2688               viewport.getResidueShading(), alignPanel.getViewName());
2689       SliderPanel.showPIDSlider();
2690     }
2691   }
2692
2693   protected void modifyConservation_actionPerformed()
2694   {
2695     if (viewport.getConservationSelected()
2696             && viewport.getGlobalColourScheme() != null)
2697     {
2698       SliderPanel.setConservationSlider(alignPanel,
2699               viewport.getResidueShading(), alignPanel.getViewName());
2700       SliderPanel.showConservationSlider();
2701     }
2702   }
2703
2704   protected void conservationMenuItem_actionPerformed()
2705   {
2706     boolean selected = conservationMenuItem.getState();
2707     modifyConservation.setEnabled(selected);
2708     viewport.setConservationSelected(selected);
2709     viewport.getResidueShading().setConservationApplied(selected);
2710
2711     changeColour(viewport.getGlobalColourScheme());
2712
2713     if (selected)
2714     {
2715       modifyConservation_actionPerformed();
2716     }
2717     else
2718     {
2719       SliderPanel.hideConservationSlider();
2720     }
2721   }
2722
2723   public void abovePIDThreshold_actionPerformed()
2724   {
2725     boolean selected = abovePIDThreshold.getState();
2726     modifyPID.setEnabled(selected);
2727     viewport.setAbovePIDThreshold(selected);
2728     if (!selected)
2729     {
2730       viewport.getResidueShading().setThreshold(0,
2731               viewport.isIgnoreGapsConsensus());
2732     }
2733
2734     changeColour(viewport.getGlobalColourScheme());
2735
2736     if (selected)
2737     {
2738       modifyPID_actionPerformed();
2739     }
2740     else
2741     {
2742       SliderPanel.hidePIDSlider();
2743     }
2744   }
2745
2746   public void sortPairwiseMenuItem_actionPerformed()
2747   {
2748     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2749     AlignmentSorter.sortByPID(viewport.getAlignment(),
2750             viewport.getAlignment().getSequenceAt(0));
2751
2752     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
2753             viewport.getAlignment()));
2754     alignPanel.paintAlignment(true, false);
2755   }
2756
2757   public void sortIDMenuItem_actionPerformed()
2758   {
2759     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2760     AlignmentSorter.sortByID(viewport.getAlignment());
2761     addHistoryItem(
2762             new OrderCommand("ID Sort", oldOrder, viewport.getAlignment()));
2763     alignPanel.paintAlignment(true, false);
2764   }
2765
2766   public void sortLengthMenuItem_actionPerformed()
2767   {
2768     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2769     AlignmentSorter.sortByLength(viewport.getAlignment());
2770     addHistoryItem(new OrderCommand("Length Sort", oldOrder,
2771             viewport.getAlignment()));
2772     alignPanel.paintAlignment(true, false);
2773   }
2774
2775   public void sortGroupMenuItem_actionPerformed()
2776   {
2777     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2778     AlignmentSorter.sortByGroup(viewport.getAlignment());
2779     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
2780             viewport.getAlignment()));
2781     alignPanel.paintAlignment(true, false);
2782
2783   }
2784
2785   public void sortEValueMenuItem_actionPerformed()
2786   {
2787     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2788     AlignmentSorter.sortByEValue(viewport.getAlignment());
2789     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
2790             viewport.getAlignment()));
2791     alignPanel.paintAlignment(true, false);
2792
2793   }
2794
2795   public void sortBitScoreMenuItem_actionPerformed()
2796   {
2797     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2798     AlignmentSorter.sortByBitScore(viewport.getAlignment());
2799     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
2800             viewport.getAlignment()));
2801     alignPanel.paintAlignment(true, false);
2802
2803   }
2804
2805   public void removeRedundancyMenuItem_actionPerformed()
2806   {
2807     new RedundancyPanel(alignPanel);
2808   }
2809
2810   public void pairwiseAlignmentMenuItem_actionPerformed()
2811   {
2812     if (viewport.getSelectionGroup() != null
2813             && viewport.getSelectionGroup().getSize() > 1)
2814     {
2815       Frame frame = new Frame();
2816       frame.add(new PairwiseAlignPanel(alignPanel));
2817       jalview.bin.JalviewLite.addFrame(frame,
2818               MessageManager.getString("action.pairwise_alignment"), 600,
2819               500);
2820     }
2821   }
2822
2823   public void PCAMenuItem_actionPerformed()
2824   {
2825     // are the sequences aligned?
2826     if (!viewport.getAlignment().isAligned(false))
2827     {
2828       SequenceI current;
2829       int Width = viewport.getAlignment().getWidth();
2830
2831       for (int i = 0; i < viewport.getAlignment().getSequences()
2832               .size(); i++)
2833       {
2834         current = viewport.getAlignment().getSequenceAt(i);
2835
2836         if (current.getLength() < Width)
2837         {
2838           current.insertCharAt(Width - 1, viewport.getGapCharacter());
2839         }
2840       }
2841       alignPanel.paintAlignment(false, false);
2842     }
2843
2844     if ((viewport.getSelectionGroup() != null
2845             && viewport.getSelectionGroup().getSize() < 4
2846             && viewport.getSelectionGroup().getSize() > 0)
2847             || viewport.getAlignment().getHeight() < 4)
2848     {
2849       return;
2850     }
2851
2852     try
2853     {
2854       new PCAPanel(viewport);
2855     } catch (java.lang.OutOfMemoryError ex)
2856     {
2857     }
2858
2859   }
2860
2861   public void averageDistanceTreeMenuItem_actionPerformed()
2862   {
2863     newTreePanel(TreeBuilder.AVERAGE_DISTANCE, new PIDModel().getName(),
2864             "Average distance tree using PID");
2865   }
2866
2867   public void neighbourTreeMenuItem_actionPerformed()
2868   {
2869     newTreePanel(TreeBuilder.NEIGHBOUR_JOINING, new PIDModel().getName(),
2870             "Neighbour joining tree using PID");
2871   }
2872
2873   protected void njTreeBlosumMenuItem_actionPerformed()
2874   {
2875     newTreePanel(TreeBuilder.NEIGHBOUR_JOINING,
2876             ScoreModels.getInstance().getBlosum62().getName(),
2877             "Neighbour joining tree using BLOSUM62");
2878   }
2879
2880   protected void avTreeBlosumMenuItem_actionPerformed()
2881   {
2882     newTreePanel(TreeBuilder.AVERAGE_DISTANCE,
2883             ScoreModels.getInstance().getBlosum62().getName(),
2884             "Average distance tree using BLOSUM62");
2885   }
2886
2887   void newTreePanel(String type, String pwType, String title)
2888   {
2889     // are the sequences aligned?
2890     if (!viewport.getAlignment().isAligned(false))
2891     {
2892       SequenceI current;
2893       int Width = viewport.getAlignment().getWidth();
2894
2895       for (int i = 0; i < viewport.getAlignment().getSequences()
2896               .size(); i++)
2897       {
2898         current = viewport.getAlignment().getSequenceAt(i);
2899
2900         if (current.getLength() < Width)
2901         {
2902           current.insertCharAt(Width - 1, viewport.getGapCharacter());
2903         }
2904       }
2905       alignPanel.paintAlignment(false, false);
2906
2907     }
2908
2909     if ((viewport.getSelectionGroup() != null
2910             && viewport.getSelectionGroup().getSize() > 1)
2911             || (viewport.getAlignment().getHeight() > 1))
2912     {
2913       final TreePanel tp = new TreePanel(alignPanel, type, pwType);
2914
2915       addTreeMenuItem(tp, title);
2916
2917       jalview.bin.JalviewLite.addFrame(tp, title, 600, 500);
2918     }
2919   }
2920
2921   void loadTree_actionPerformed()
2922   {
2923     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, this);
2924     cap.setText(MessageManager.getString("label.paste_newick_tree_file"));
2925     cap.setTreeImport();
2926     Frame frame = new Frame();
2927     frame.add(cap);
2928     jalview.bin.JalviewLite.addFrame(frame,
2929             MessageManager.getString("label.paste_newick_file"), 400, 300);
2930   }
2931
2932   public void loadTree(jalview.io.NewickFile tree, String treeFile)
2933   {
2934     TreePanel tp = new TreePanel(alignPanel, treeFile,
2935             MessageManager.getString("label.load_tree_from_file"), tree);
2936     jalview.bin.JalviewLite.addFrame(tp, treeFile, 600, 500);
2937     addTreeMenuItem(tp, treeFile);
2938   }
2939
2940   /**
2941    * sort the alignment using the given treePanel
2942    * 
2943    * @param treePanel
2944    *          tree used to sort view
2945    * @param title
2946    *          string used for undo event name
2947    */
2948   public void sortByTree(TreePanel treePanel, String title)
2949   {
2950     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2951     AlignmentSorter.sortByTree(viewport.getAlignment(),
2952             treePanel.getTree());
2953     // addHistoryItem(new HistoryItem("Sort", viewport.alignment,
2954     // HistoryItem.SORT));
2955     addHistoryItem(new OrderCommand(MessageManager
2956             .formatMessage("label.order_by_params", new String[]
2957             { title }), oldOrder, viewport.getAlignment()));
2958     alignPanel.paintAlignment(true, false);
2959   }
2960
2961   /**
2962    * Do any automatic reordering of the alignment and add the necessary bits to
2963    * the menu structure for the new tree
2964    * 
2965    * @param treePanel
2966    * @param title
2967    */
2968   protected void addTreeMenuItem(final TreePanel treePanel,
2969           final String title)
2970   {
2971     final MenuItem item = new MenuItem(title);
2972     sortByTreeMenu.add(item);
2973     item.addActionListener(new java.awt.event.ActionListener()
2974     {
2975       @Override
2976       public void actionPerformed(ActionEvent evt)
2977       {
2978         sortByTree(treePanel, title); // treePanel.getTitle());
2979       }
2980     });
2981
2982     treePanel.addWindowListener(new WindowAdapter()
2983     {
2984       @Override
2985       public void windowOpened(WindowEvent e)
2986       {
2987         if (viewport.sortByTree)
2988         {
2989           sortByTree(treePanel, title);
2990         }
2991         super.windowOpened(e);
2992       }
2993
2994       @Override
2995       public void windowClosing(WindowEvent e)
2996       {
2997         sortByTreeMenu.remove(item);
2998       };
2999     });
3000   }
3001
3002   public boolean sortBy(AlignmentOrder alorder, String undoname)
3003   {
3004     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3005     if (viewport.applet.debug)
3006     {
3007       System.err.println("Sorting " + alorder.getOrder().size()
3008               + " in alignment '" + getTitle() + "'");
3009     }
3010     AlignmentSorter.sortBy(viewport.getAlignment(), alorder);
3011     if (undoname != null)
3012     {
3013       addHistoryItem(new OrderCommand(undoname, oldOrder,
3014               viewport.getAlignment()));
3015     }
3016     alignPanel.paintAlignment(true, false);
3017     return true;
3018   }
3019
3020   protected void documentation_actionPerformed()
3021   {
3022     alignPanel.av.applet.openJalviewHelpUrl();
3023   }
3024
3025   protected void about_actionPerformed()
3026   {
3027
3028     class AboutPanel extends Canvas
3029     {
3030       String version;
3031
3032       String builddate;
3033
3034       public AboutPanel(String version, String builddate)
3035       {
3036         this.version = version;
3037         this.builddate = builddate;
3038       }
3039
3040       @Override
3041       public void paint(Graphics g)
3042       {
3043         g.setColor(Color.white);
3044         g.fillRect(0, 0, getSize().width, getSize().height);
3045         g.setFont(new Font("Helvetica", Font.PLAIN, 12));
3046         FontMetrics fm = g.getFontMetrics();
3047         int fh = fm.getHeight();
3048         int y = 5, x = 7;
3049         g.setColor(Color.black);
3050         // TODO: update this text for each release or centrally store it for
3051         // lite and application
3052         g.setFont(new Font("Helvetica", Font.BOLD, 14));
3053         g.drawString(MessageManager
3054                 .formatMessage("label.jalviewLite_release", new String[]
3055                 { version }), x, y += fh);
3056         g.setFont(new Font("Helvetica", Font.BOLD, 12));
3057         g.drawString(MessageManager.formatMessage("label.jaview_build_date",
3058                 new String[]
3059                 { builddate }), x, y += fh);
3060         g.setFont(new Font("Helvetica", Font.PLAIN, 12));
3061         g.drawString(MessageManager.getString("label.jalview_authors_1"), x,
3062                 y += fh * 1.5);
3063         g.drawString(MessageManager.getString("label.jalview_authors_2"),
3064                 x + 50, y += fh + 8);
3065         g.drawString(MessageManager.getString("label.jalview_dev_managers"),
3066                 x, y += fh);
3067         g.drawString(MessageManager
3068                 .getString("label.jalview_distribution_lists"), x, y += fh);
3069         g.drawString(MessageManager.getString("label.jalview_please_cite"),
3070                 x, y += fh + 8);
3071         g.drawString(
3072                 MessageManager.getString("label.jalview_cite_1_authors"), x,
3073                 y += fh);
3074         g.drawString(MessageManager.getString("label.jalview_cite_1_title"),
3075                 x, y += fh);
3076         g.drawString(MessageManager.getString("label.jalview_cite_1_ref"),
3077                 x, y += fh);
3078       }
3079     }
3080
3081     Frame frame = new Frame();
3082     frame.add(new AboutPanel(JalviewLite.getVersion(),
3083             JalviewLite.getBuildDate()));
3084     jalview.bin.JalviewLite.addFrame(frame,
3085             MessageManager.getString("label.jalview"), 580, 220);
3086
3087   }
3088
3089   public void showURL(String url, String target)
3090   {
3091     if (viewport.applet == null)
3092     {
3093       System.out.println("Not running as applet - no browser available.");
3094     }
3095     else
3096     {
3097       viewport.applet.showURL(url, target);
3098     }
3099   }
3100
3101   // ////////////////////////////////////////////////////////////////////////////////
3102   // JBuilder Graphics here
3103
3104   MenuBar alignFrameMenuBar = new MenuBar();
3105
3106   Menu fileMenu = new Menu(MessageManager.getString("action.file"));
3107
3108   MenuItem loadApplication = new MenuItem(
3109           MessageManager.getString("label.view_full_application"));
3110
3111   MenuItem loadTree = new MenuItem(
3112           MessageManager.getString("label.load_associated_tree"));
3113
3114   MenuItem loadAnnotations = new MenuItem(
3115           MessageManager.getString("label.load_features_annotations"));
3116
3117   MenuItem outputFeatures = new MenuItem(
3118           MessageManager.getString("label.export_features"));
3119
3120   MenuItem outputAnnotations = new MenuItem(
3121           MessageManager.getString("label.export_annotations"));
3122
3123   MenuItem closeMenuItem = new MenuItem(
3124           MessageManager.getString("action.close"));
3125
3126   MenuItem selectAllSequenceMenuItem = new MenuItem(
3127           MessageManager.getString("action.select_all"));
3128
3129   MenuItem deselectAllSequenceMenuItem = new MenuItem(
3130           MessageManager.getString("action.deselect_all"));
3131
3132   MenuItem invertSequenceMenuItem = new MenuItem(
3133           MessageManager.getString("action.invert_selection"));
3134
3135   MenuItem remove2LeftMenuItem = new MenuItem();
3136
3137   MenuItem remove2RightMenuItem = new MenuItem();
3138
3139   MenuItem removeGappedColumnMenuItem = new MenuItem();
3140
3141   MenuItem removeAllGapsMenuItem = new MenuItem();
3142
3143   CheckboxMenuItem viewBoxesMenuItem = new CheckboxMenuItem();
3144
3145   CheckboxMenuItem viewTextMenuItem = new CheckboxMenuItem();
3146
3147   MenuItem sortPairwiseMenuItem = new MenuItem();
3148
3149   MenuItem sortIDMenuItem = new MenuItem();
3150
3151   MenuItem sortLengthMenuItem = new MenuItem();
3152
3153   MenuItem sortGroupMenuItem = new MenuItem();
3154
3155   MenuItem sortEValueMenuItem = new MenuItem();
3156
3157   MenuItem sortBitScoreMenuItem = new MenuItem();
3158
3159   MenuItem removeRedundancyMenuItem = new MenuItem();
3160
3161   MenuItem pairwiseAlignmentMenuItem = new MenuItem();
3162
3163   MenuItem PCAMenuItem = new MenuItem();
3164
3165   MenuItem averageDistanceTreeMenuItem = new MenuItem();
3166
3167   MenuItem neighbourTreeMenuItem = new MenuItem();
3168
3169   BorderLayout borderLayout1 = new BorderLayout();
3170
3171   public Label statusBar = new Label();
3172
3173   MenuItem clustalColour = new MenuItem();
3174
3175   MenuItem zappoColour = new MenuItem();
3176
3177   MenuItem taylorColour = new MenuItem();
3178
3179   MenuItem hydrophobicityColour = new MenuItem();
3180
3181   MenuItem helixColour = new MenuItem();
3182
3183   MenuItem strandColour = new MenuItem();
3184
3185   MenuItem turnColour = new MenuItem();
3186
3187   MenuItem buriedColour = new MenuItem();
3188
3189   MenuItem purinePyrimidineColour = new MenuItem();
3190
3191   // MenuItem RNAInteractionColour = new MenuItem();
3192
3193   MenuItem RNAHelixColour = new MenuItem();
3194
3195   MenuItem userDefinedColour = new MenuItem();
3196
3197   MenuItem PIDColour = new MenuItem();
3198
3199   MenuItem BLOSUM62Colour = new MenuItem();
3200
3201   MenuItem tcoffeeColour = new MenuItem();
3202
3203   MenuItem njTreeBlosumMenuItem = new MenuItem();
3204
3205   MenuItem avDistanceTreeBlosumMenuItem = new MenuItem();
3206
3207   CheckboxMenuItem annotationPanelMenuItem = new CheckboxMenuItem();
3208
3209   CheckboxMenuItem colourTextMenuItem = new CheckboxMenuItem();
3210
3211   CheckboxMenuItem displayNonconservedMenuItem = new CheckboxMenuItem();
3212
3213   MenuItem alProperties = new MenuItem(
3214           MessageManager.getString("label.alignment_props"));
3215
3216   MenuItem overviewMenuItem = new MenuItem();
3217
3218   MenuItem undoMenuItem = new MenuItem();
3219
3220   MenuItem redoMenuItem = new MenuItem();
3221
3222   CheckboxMenuItem conservationMenuItem = new CheckboxMenuItem();
3223
3224   MenuItem noColourmenuItem = new MenuItem();
3225
3226   CheckboxMenuItem wrapMenuItem = new CheckboxMenuItem();
3227
3228   CheckboxMenuItem renderGapsMenuItem = new CheckboxMenuItem();
3229
3230   MenuItem findMenuItem = new MenuItem();
3231
3232   CheckboxMenuItem abovePIDThreshold = new CheckboxMenuItem();
3233
3234   MenuItem nucleotideColour = new MenuItem();
3235
3236   MenuItem deleteGroups = new MenuItem();
3237
3238   MenuItem grpsFromSelection = new MenuItem();
3239
3240   MenuItem createGroup = new MenuItem();
3241
3242   MenuItem unGroup = new MenuItem();
3243
3244   MenuItem delete = new MenuItem();
3245
3246   MenuItem copy = new MenuItem();
3247
3248   MenuItem cut = new MenuItem();
3249
3250   Menu pasteMenu = new Menu();
3251
3252   MenuItem pasteNew = new MenuItem();
3253
3254   MenuItem pasteThis = new MenuItem();
3255
3256   CheckboxMenuItem applyToAllGroups = new CheckboxMenuItem();
3257
3258   MenuItem font = new MenuItem();
3259
3260   CheckboxMenuItem scaleAbove = new CheckboxMenuItem();
3261
3262   CheckboxMenuItem scaleLeft = new CheckboxMenuItem();
3263
3264   CheckboxMenuItem scaleRight = new CheckboxMenuItem();
3265
3266   MenuItem modifyPID = new MenuItem();
3267
3268   MenuItem modifyConservation = new MenuItem();
3269
3270   CheckboxMenuItem autoCalculate = null;
3271
3272   CheckboxMenuItem sortByTree = new CheckboxMenuItem(
3273           "Sort Alignment With New Tree", true);
3274
3275   Menu sortByTreeMenu = new Menu();
3276
3277   MenuItem inputText = new MenuItem();
3278
3279   MenuItem documentation = new MenuItem();
3280
3281   MenuItem about = new MenuItem();
3282
3283   CheckboxMenuItem seqLimits = new CheckboxMenuItem();
3284
3285   CheckboxMenuItem centreColumnLabelFlag = new CheckboxMenuItem();
3286
3287   CheckboxMenuItem followMouseOverFlag = new CheckboxMenuItem();
3288
3289   CheckboxMenuItem showSequenceLogo = new CheckboxMenuItem();
3290
3291   CheckboxMenuItem applyAutoAnnotationSettings = new CheckboxMenuItem();
3292
3293   CheckboxMenuItem showConsensusHistogram = new CheckboxMenuItem();
3294
3295   CheckboxMenuItem showGroupConsensus = new CheckboxMenuItem();
3296
3297   CheckboxMenuItem showGroupConservation = new CheckboxMenuItem();
3298
3299   CheckboxMenuItem normSequenceLogo = new CheckboxMenuItem();
3300
3301   /**
3302    * Initialise menus and other items
3303    * 
3304    * @throws Exception
3305    */
3306   private void jbInit() throws Exception
3307   {
3308     setMenuBar(alignFrameMenuBar);
3309
3310     /*
3311      * Configure File menu items and actions
3312      */
3313     inputText
3314             .setLabel(MessageManager.getString("label.input_from_textbox"));
3315     inputText.addActionListener(this);
3316     Menu outputTextboxMenu = new Menu(
3317             MessageManager.getString("label.out_to_textbox"));
3318     for (String ff : FileFormats.getInstance().getWritableFormats(true))
3319     {
3320       MenuItem item = new MenuItem(ff);
3321
3322       item.addActionListener(new java.awt.event.ActionListener()
3323       {
3324         @Override
3325         public void actionPerformed(ActionEvent e)
3326         {
3327           outputText_actionPerformed(e);
3328         }
3329       });
3330
3331       outputTextboxMenu.add(item);
3332     }
3333     closeMenuItem.addActionListener(this);
3334     loadApplication.addActionListener(this);
3335     loadTree.addActionListener(this);
3336     loadAnnotations.addActionListener(this);
3337     outputFeatures.addActionListener(this);
3338     outputAnnotations.addActionListener(this);
3339
3340     /*
3341      * Configure Edit menu items and actions
3342      */
3343     undoMenuItem.setEnabled(false);
3344     undoMenuItem.setLabel(MessageManager.getString("action.undo"));
3345     undoMenuItem.addActionListener(this);
3346     redoMenuItem.setEnabled(false);
3347     redoMenuItem.setLabel(MessageManager.getString("action.redo"));
3348     redoMenuItem.addActionListener(this);
3349     copy.setLabel(MessageManager.getString("action.copy"));
3350     copy.addActionListener(this);
3351     cut.setLabel(MessageManager.getString("action.cut"));
3352     cut.addActionListener(this);
3353     delete.setLabel(MessageManager.getString("action.delete"));
3354     delete.addActionListener(this);
3355     pasteMenu.setLabel(MessageManager.getString("action.paste"));
3356     pasteNew.setLabel(MessageManager.getString("label.to_new_alignment"));
3357     pasteNew.addActionListener(this);
3358     pasteThis.setLabel(MessageManager.getString("label.to_this_alignment"));
3359     pasteThis.addActionListener(this);
3360     remove2LeftMenuItem
3361             .setLabel(MessageManager.getString("action.remove_left"));
3362     remove2LeftMenuItem.addActionListener(this);
3363     remove2RightMenuItem
3364             .setLabel(MessageManager.getString("action.remove_right"));
3365     remove2RightMenuItem.addActionListener(this);
3366     removeGappedColumnMenuItem.setLabel(
3367             MessageManager.getString("action.remove_empty_columns"));
3368     removeGappedColumnMenuItem.addActionListener(this);
3369     removeAllGapsMenuItem
3370             .setLabel(MessageManager.getString("action.remove_all_gaps"));
3371     removeAllGapsMenuItem.addActionListener(this);
3372     removeRedundancyMenuItem
3373             .setLabel(MessageManager.getString("action.remove_redundancy"));
3374     removeRedundancyMenuItem.addActionListener(this);
3375
3376     /*
3377      * Configure Select menu items and actions
3378      */
3379     findMenuItem.setLabel(MessageManager.getString("action.find"));
3380     findMenuItem.addActionListener(this);
3381     selectAllSequenceMenuItem.addActionListener(this);
3382     deselectAllSequenceMenuItem.addActionListener(this);
3383     invertSequenceMenuItem.setLabel(
3384             MessageManager.getString("action.invert_sequence_selection"));
3385     invertSequenceMenuItem.addActionListener(this);
3386     invertColSel.setLabel(
3387             MessageManager.getString("action.invert_column_selection"));
3388     invertColSel.addActionListener(this);
3389     deleteGroups
3390             .setLabel(MessageManager.getString("action.undefine_groups"));
3391     deleteGroups.addActionListener(this);
3392     grpsFromSelection.setLabel(
3393             MessageManager.getString("action.make_groups_selection"));
3394     grpsFromSelection.addActionListener(this);
3395     createGroup.setLabel(MessageManager.getString("action.create_group"));
3396     createGroup.addActionListener(this);
3397     unGroup.setLabel(MessageManager.getString("action.remove_group"));
3398     unGroup.addActionListener(this);
3399
3400     annotationColumnSelection.setLabel(
3401             MessageManager.getString("action.select_by_annotation"));
3402     annotationColumnSelection.addActionListener(this);
3403
3404     /*
3405      * Configure View menu items and actions
3406      */
3407     newView.setLabel(MessageManager.getString("action.new_view"));
3408     newView.addActionListener(this);
3409     Menu showMenu = new Menu(MessageManager.getString("action.show"));
3410     showColumns.setLabel(MessageManager.getString("label.all_columns"));
3411     showSeqs.setLabel(MessageManager.getString("label.all_sequences"));
3412     Menu hideMenu = new Menu(MessageManager.getString("action.hide"));
3413     hideColumns
3414             .setLabel(MessageManager.getString("label.selected_columns"));
3415     hideSequences
3416             .setLabel(MessageManager.getString("label.selected_sequences"));
3417     hideAllButSelection.setLabel(
3418             MessageManager.getString("label.all_but_selected_region"));
3419     hideAllSelection
3420             .setLabel(MessageManager.getString("label.selected_region"));
3421     showAllHidden.setLabel(
3422             MessageManager.getString("label.all_sequences_columns"));
3423     showColumns.addActionListener(this);
3424     showSeqs.addActionListener(this);
3425     hideColumns.addActionListener(this);
3426     hideSequences.addActionListener(this);
3427     hideAllButSelection.addActionListener(this);
3428     hideAllSelection.addActionListener(this);
3429     showAllHidden.addActionListener(this);
3430     featureSettings
3431             .setLabel(MessageManager.getString("action.feature_settings"));
3432     featureSettings.addActionListener(this);
3433     sequenceFeatures.setLabel(
3434             MessageManager.getString("label.show_sequence_features"));
3435     sequenceFeatures.addItemListener(this);
3436     sequenceFeatures.setState(false);
3437     followMouseOverFlag.setLabel(
3438             MessageManager.getString("label.automatic_scrolling"));
3439     followMouseOverFlag.addItemListener(this);
3440     alProperties.addActionListener(this);
3441     overviewMenuItem
3442             .setLabel(MessageManager.getString("label.overview_window"));
3443     overviewMenuItem.addActionListener(this);
3444
3445     /*
3446      * Configure Annotations menu items and actions
3447      */
3448     annotationPanelMenuItem
3449             .setLabel(MessageManager.getString("label.show_annotations"));
3450     annotationPanelMenuItem.addItemListener(this);
3451     showGroupConsensus
3452             .setLabel(MessageManager.getString("label.group_consensus"));
3453     showGroupConservation
3454             .setLabel(MessageManager.getString("label.group_conservation"));
3455     showConsensusHistogram.setLabel(
3456             MessageManager.getString("label.show_consensus_histogram"));
3457     showSequenceLogo.setLabel(
3458             MessageManager.getString("label.show_consensus_logo"));
3459     normSequenceLogo.setLabel(
3460             MessageManager.getString("label.norm_consensus_logo"));
3461     applyAutoAnnotationSettings
3462             .setLabel(MessageManager.getString("label.apply_all_groups"));
3463     applyAutoAnnotationSettings.setState(true);
3464     Menu autoAnnMenu = new Menu(
3465             MessageManager.getString("label.autocalculated_annotation"));
3466     showGroupConsensus.addItemListener(this);
3467     showGroupConservation.addItemListener(this);
3468     showConsensusHistogram.addItemListener(this);
3469     showSequenceLogo.addItemListener(this);
3470     normSequenceLogo.addItemListener(this);
3471     applyAutoAnnotationSettings.addItemListener(this);
3472     showAlignmentAnnotations = new CheckboxMenuItem(
3473             MessageManager.getString("label.show_all_al_annotations"));
3474     showSequenceAnnotations = new CheckboxMenuItem(
3475             MessageManager.getString("label.show_all_seq_annotations"));
3476     sortAnnBySequence = new CheckboxMenuItem(
3477             MessageManager.getString("label.sort_annotations_by_sequence"));
3478     sortAnnByLabel = new CheckboxMenuItem(
3479             MessageManager.getString("label.sort_annotations_by_label"));
3480     showAutoFirst = new CheckboxMenuItem(
3481             MessageManager.getString("label.show_first"));
3482     showAutoFirst.setState(false); // pending applet parameter
3483     setShowAutoCalculatedAbove(showAutoFirst.getState());
3484     showAutoLast = new CheckboxMenuItem(
3485             MessageManager.getString("label.show_last"));
3486     showAutoLast.setState(!showAutoFirst.getState());
3487     showAlignmentAnnotations.addItemListener(this);
3488     showSequenceAnnotations.addItemListener(this);
3489     sortAnnBySequence.addItemListener(this);
3490     sortAnnByLabel.addItemListener(this);
3491     showAutoFirst.addItemListener(this);
3492     showAutoLast.addItemListener(this);
3493
3494     /*
3495      * Configure Format menu items and actions
3496      */
3497     font.setLabel(MessageManager.getString("action.font"));
3498     font.addActionListener(this);
3499     scaleAbove.setLabel(MessageManager.getString("action.scale_above"));
3500     scaleAbove.setState(true);
3501     scaleAbove.setEnabled(false);
3502     scaleAbove.addItemListener(this);
3503     scaleLeft.setEnabled(false);
3504     scaleLeft.setState(true);
3505     scaleLeft.setLabel(MessageManager.getString("action.scale_left"));
3506     scaleLeft.addItemListener(this);
3507     scaleRight.setEnabled(false);
3508     scaleRight.setState(true);
3509     scaleRight.setLabel(MessageManager.getString("action.scale_right"));
3510     scaleRight.addItemListener(this);
3511     viewBoxesMenuItem.setLabel(MessageManager.getString("action.boxes"));
3512     viewBoxesMenuItem.setState(true);
3513     viewBoxesMenuItem.addItemListener(this);
3514     viewTextMenuItem.setLabel(MessageManager.getString("action.text"));
3515     viewTextMenuItem.setState(true);
3516     viewTextMenuItem.addItemListener(this);
3517     colourTextMenuItem
3518             .setLabel(MessageManager.getString("label.colour_text"));
3519     colourTextMenuItem.addItemListener(this);
3520     displayNonconservedMenuItem
3521             .setLabel(MessageManager.getString("label.show_non_conserved"));
3522     displayNonconservedMenuItem.addItemListener(this);
3523     wrapMenuItem.setLabel(MessageManager.getString("action.wrap"));
3524     wrapMenuItem.addItemListener(this);
3525     renderGapsMenuItem
3526             .setLabel(MessageManager.getString("action.show_gaps"));
3527     renderGapsMenuItem.setState(true);
3528     renderGapsMenuItem.addItemListener(this);
3529     centreColumnLabelFlag.setLabel(
3530             MessageManager.getString("label.centre_column_labels"));
3531     centreColumnLabelFlag.addItemListener(this);
3532     seqLimits.setState(true);
3533     seqLimits.setLabel(
3534             MessageManager.getString("label.show_sequence_limits"));
3535     seqLimits.addItemListener(this);
3536
3537     /*
3538      * Configure Colour menu items and actions
3539      */
3540     applyToAllGroups.setLabel(
3541             MessageManager.getString("label.apply_colour_to_all_groups"));
3542     applyToAllGroups.setState(true);
3543     applyToAllGroups.addItemListener(this);
3544     clustalColour.setLabel(
3545             MessageManager.getString("label.colourScheme_clustal"));
3546     clustalColour.addActionListener(this);
3547     zappoColour
3548             .setLabel(MessageManager.getString("label.colourScheme_zappo"));
3549     zappoColour.addActionListener(this);
3550     taylorColour.setLabel(
3551             MessageManager.getString("label.colourScheme_taylor"));
3552     taylorColour.addActionListener(this);
3553     hydrophobicityColour.setLabel(
3554             MessageManager.getString("label.colourScheme_hydrophobic"));
3555     hydrophobicityColour.addActionListener(this);
3556     helixColour.setLabel(MessageManager
3557             .getString("label.colourScheme_helix_propensity"));
3558     helixColour.addActionListener(this);
3559     strandColour.setLabel(MessageManager
3560             .getString("label.colourScheme_strand_propensity"));
3561     strandColour.addActionListener(this);
3562     turnColour.setLabel(
3563             MessageManager.getString("label.colourScheme_turn_propensity"));
3564     turnColour.addActionListener(this);
3565     buriedColour.setLabel(
3566             MessageManager.getString("label.colourScheme_buried_index"));
3567     buriedColour.addActionListener(this);
3568     purinePyrimidineColour.setLabel(MessageManager
3569             .getString("label.colourScheme_purine/pyrimidine"));
3570     purinePyrimidineColour.addActionListener(this);
3571     // RNAInteractionColour.setLabel(MessageManager
3572     // .getString("label.rna_interaction"));
3573     // RNAInteractionColour.addActionListener(this);
3574     RNAHelixColour.setLabel(
3575             MessageManager.getString("label.colourScheme_rna_helices"));
3576     RNAHelixColour.addActionListener(this);
3577     userDefinedColour
3578             .setLabel(MessageManager.getString("action.user_defined"));
3579     userDefinedColour.addActionListener(this);
3580     PIDColour.setLabel(
3581             MessageManager.getString("label.colourScheme_%_identity"));
3582     PIDColour.addActionListener(this);
3583     BLOSUM62Colour.setLabel(
3584             MessageManager.getString("label.colourScheme_blosum62"));
3585     BLOSUM62Colour.addActionListener(this);
3586     tcoffeeColour.setLabel(
3587             MessageManager.getString("label.colourScheme_t-coffee_scores"));
3588     // it will be enabled only if a score file is provided
3589     tcoffeeColour.setEnabled(false);
3590     tcoffeeColour.addActionListener(this);
3591     conservationMenuItem
3592             .setLabel(MessageManager.getString("action.by_conservation"));
3593     conservationMenuItem.addItemListener(this);
3594     noColourmenuItem.setLabel(MessageManager.getString("label.none"));
3595     noColourmenuItem.addActionListener(this);
3596     abovePIDThreshold.setLabel(
3597             MessageManager.getString("label.above_identity_threshold"));
3598     abovePIDThreshold.addItemListener(this);
3599     nucleotideColour.setLabel(
3600             MessageManager.getString("label.colourScheme_nucleotide"));
3601     nucleotideColour.addActionListener(this);
3602     modifyPID.setLabel(
3603             MessageManager.getString("label.modify_identity_threshold"));
3604     modifyPID.setEnabled(abovePIDThreshold.getState());
3605     modifyPID.addActionListener(this);
3606     modifyConservation.setLabel(MessageManager
3607             .getString("label.modify_conservation_threshold"));
3608     modifyConservation.setEnabled(conservationMenuItem.getState());
3609     modifyConservation.addActionListener(this);
3610     annotationColour
3611             .setLabel(MessageManager.getString("action.by_annotation"));
3612     annotationColour.addActionListener(this);
3613
3614     /*
3615      * Configure Calculate menu items and actions
3616      */
3617     sortPairwiseMenuItem
3618             .setLabel(MessageManager.getString("action.by_pairwise_id"));
3619     sortPairwiseMenuItem.addActionListener(this);
3620     sortIDMenuItem.setLabel(MessageManager.getString("action.by_id"));
3621     sortIDMenuItem.addActionListener(this);
3622     sortLengthMenuItem
3623             .setLabel(MessageManager.getString("action.by_length"));
3624     sortLengthMenuItem.addActionListener(this);
3625     sortGroupMenuItem.setLabel(MessageManager.getString("action.by_group"));
3626     sortGroupMenuItem.addActionListener(this);
3627     pairwiseAlignmentMenuItem.setLabel(
3628             MessageManager.getString("action.pairwise_alignment"));
3629     pairwiseAlignmentMenuItem.addActionListener(this);
3630     PCAMenuItem.setLabel(
3631             MessageManager.getString("label.principal_component_analysis"));
3632     PCAMenuItem.addActionListener(this);
3633     autoCalculate = new CheckboxMenuItem(
3634             MessageManager.getString("label.autocalculate_consensus"),
3635             true);
3636     averageDistanceTreeMenuItem.setLabel(
3637             MessageManager.getString("label.average_distance_identity"));
3638     averageDistanceTreeMenuItem.addActionListener(this);
3639     neighbourTreeMenuItem.setLabel(
3640             MessageManager.getString("label.neighbour_joining_identity"));
3641     neighbourTreeMenuItem.addActionListener(this);
3642     avDistanceTreeBlosumMenuItem.setLabel(
3643             MessageManager.getString("label.average_distance_blosum62"));
3644     avDistanceTreeBlosumMenuItem.addActionListener(this);
3645     njTreeBlosumMenuItem
3646             .setLabel(MessageManager.getString("label.neighbour_blosum62"));
3647     njTreeBlosumMenuItem.addActionListener(this);
3648     sortByTreeMenu
3649             .setLabel(MessageManager.getString("action.by_tree_order"));
3650     Menu sortMenu = new Menu(MessageManager.getString("action.sort"));
3651     Menu calculateTreeMenu = new Menu(
3652             MessageManager.getString("action.calculate_tree"));
3653     autoCalculate.addItemListener(this);
3654     sortByTree.addItemListener(this);
3655
3656     /*
3657      * Configure Help menu items and actions
3658      */
3659     Menu helpMenu = new Menu(MessageManager.getString("action.help"));
3660     documentation.setLabel(MessageManager.getString("label.documentation"));
3661     documentation.addActionListener(this);
3662     about.setLabel(MessageManager.getString("label.about"));
3663     about.addActionListener(this);
3664
3665     /*
3666      * Add top level menus to frame
3667      */
3668     alignFrameMenuBar.add(fileMenu);
3669     Menu editMenu = new Menu(MessageManager.getString("action.edit"));
3670     alignFrameMenuBar.add(editMenu);
3671     Menu selectMenu = new Menu(MessageManager.getString("action.select"));
3672     alignFrameMenuBar.add(selectMenu);
3673     Menu viewMenu = new Menu(MessageManager.getString("action.view"));
3674     alignFrameMenuBar.add(viewMenu);
3675     Menu annotationsMenu = new Menu(
3676             MessageManager.getString("action.annotations"));
3677     alignFrameMenuBar.add(annotationsMenu);
3678     Menu formatMenu = new Menu(MessageManager.getString("action.format"));
3679     alignFrameMenuBar.add(formatMenu);
3680     Menu colourMenu = new Menu(MessageManager.getString("action.colour"));
3681     alignFrameMenuBar.add(colourMenu);
3682     Menu calculateMenu = new Menu(
3683             MessageManager.getString("action.calculate"));
3684     alignFrameMenuBar.add(calculateMenu);
3685     alignFrameMenuBar.add(helpMenu);
3686
3687     /*
3688      * File menu
3689      */
3690     fileMenu.add(inputText);
3691     fileMenu.add(loadTree);
3692     fileMenu.add(loadAnnotations);
3693     fileMenu.addSeparator();
3694     fileMenu.add(outputTextboxMenu);
3695     fileMenu.add(outputFeatures);
3696     fileMenu.add(outputAnnotations);
3697     if (jalviewServletURL != null)
3698     {
3699       fileMenu.add(loadApplication);
3700     }
3701     fileMenu.addSeparator();
3702     fileMenu.add(closeMenuItem);
3703
3704     /*
3705      * Edit menu
3706      */
3707     editMenu.add(undoMenuItem);
3708     editMenu.add(redoMenuItem);
3709     editMenu.add(cut);
3710     editMenu.add(copy);
3711     pasteMenu.add(pasteNew);
3712     pasteMenu.add(pasteThis);
3713     editMenu.add(pasteMenu);
3714     editMenu.add(delete);
3715     editMenu.addSeparator();
3716     editMenu.add(remove2LeftMenuItem);
3717     editMenu.add(remove2RightMenuItem);
3718     editMenu.add(removeGappedColumnMenuItem);
3719     editMenu.add(removeAllGapsMenuItem);
3720     editMenu.add(removeRedundancyMenuItem);
3721
3722     /*
3723      * Select menu
3724      */
3725     selectMenu.add(findMenuItem);
3726     selectMenu.addSeparator();
3727     selectMenu.add(selectAllSequenceMenuItem);
3728     selectMenu.add(deselectAllSequenceMenuItem);
3729     selectMenu.add(invertSequenceMenuItem);
3730     selectMenu.add(invertColSel);
3731     selectMenu.add(createGroup);
3732     selectMenu.add(unGroup);
3733     selectMenu.add(grpsFromSelection);
3734     selectMenu.add(deleteGroups);
3735     selectMenu.add(annotationColumnSelection);
3736
3737     /*
3738      * View menu
3739      */
3740     viewMenu.add(newView);
3741     viewMenu.addSeparator();
3742     showMenu.add(showColumns);
3743     showMenu.add(showSeqs);
3744     showMenu.add(showAllHidden);
3745     viewMenu.add(showMenu);
3746     hideMenu.add(hideColumns);
3747     hideMenu.add(hideSequences);
3748     hideMenu.add(hideAllSelection);
3749     hideMenu.add(hideAllButSelection);
3750     viewMenu.add(hideMenu);
3751     viewMenu.addSeparator();
3752     viewMenu.add(followMouseOverFlag);
3753     viewMenu.addSeparator();
3754     viewMenu.add(sequenceFeatures);
3755     viewMenu.add(featureSettings);
3756     viewMenu.addSeparator();
3757     viewMenu.add(alProperties);
3758     viewMenu.addSeparator();
3759     viewMenu.add(overviewMenuItem);
3760
3761     /*
3762      * Annotations menu
3763      */
3764     annotationsMenu.add(annotationPanelMenuItem);
3765     annotationsMenu.addSeparator();
3766     annotationsMenu.add(showAlignmentAnnotations);
3767     annotationsMenu.add(showSequenceAnnotations);
3768     annotationsMenu.add(sortAnnBySequence);
3769     annotationsMenu.add(sortAnnByLabel);
3770     annotationsMenu.addSeparator();
3771     autoAnnMenu.add(showAutoFirst);
3772     autoAnnMenu.add(showAutoLast);
3773     autoAnnMenu.addSeparator();
3774     autoAnnMenu.add(applyAutoAnnotationSettings);
3775     autoAnnMenu.add(showConsensusHistogram);
3776     autoAnnMenu.add(showSequenceLogo);
3777     autoAnnMenu.add(normSequenceLogo);
3778     autoAnnMenu.addSeparator();
3779     autoAnnMenu.add(showGroupConservation);
3780     autoAnnMenu.add(showGroupConsensus);
3781     annotationsMenu.add(autoAnnMenu);
3782
3783     /*
3784      * Format menu
3785      */
3786     formatMenu.add(font);
3787     formatMenu.add(seqLimits);
3788     formatMenu.add(wrapMenuItem);
3789     formatMenu.add(scaleAbove);
3790     formatMenu.add(scaleLeft);
3791     formatMenu.add(scaleRight);
3792     formatMenu.add(viewBoxesMenuItem);
3793     formatMenu.add(viewTextMenuItem);
3794     formatMenu.add(colourTextMenuItem);
3795     formatMenu.add(displayNonconservedMenuItem);
3796     formatMenu.add(renderGapsMenuItem);
3797     formatMenu.add(centreColumnLabelFlag);
3798
3799     /*
3800      * Colour menu
3801      */
3802     colourMenu.add(applyToAllGroups);
3803     colourMenu.addSeparator();
3804     colourMenu.add(noColourmenuItem);
3805     colourMenu.add(clustalColour);
3806     colourMenu.add(BLOSUM62Colour);
3807     colourMenu.add(PIDColour);
3808     colourMenu.add(zappoColour);
3809     colourMenu.add(taylorColour);
3810     colourMenu.add(hydrophobicityColour);
3811     colourMenu.add(helixColour);
3812     colourMenu.add(strandColour);
3813     colourMenu.add(turnColour);
3814     colourMenu.add(buriedColour);
3815     colourMenu.add(nucleotideColour);
3816     colourMenu.add(purinePyrimidineColour);
3817     // colourMenu.add(RNAInteractionColour);
3818     colourMenu.add(tcoffeeColour);
3819     colourMenu.add(userDefinedColour);
3820     colourMenu.addSeparator();
3821     colourMenu.add(conservationMenuItem);
3822     colourMenu.add(modifyConservation);
3823     colourMenu.add(abovePIDThreshold);
3824     colourMenu.add(modifyPID);
3825     colourMenu.add(annotationColour);
3826     colourMenu.add(RNAHelixColour);
3827
3828     /*
3829      * Calculate menu
3830      */
3831     sortMenu.add(sortIDMenuItem);
3832     sortMenu.add(sortLengthMenuItem);
3833     sortMenu.add(sortByTreeMenu);
3834     sortMenu.add(sortGroupMenuItem);
3835     sortMenu.add(sortPairwiseMenuItem);
3836     calculateMenu.add(sortMenu);
3837     calculateTreeMenu.add(averageDistanceTreeMenuItem);
3838     calculateTreeMenu.add(neighbourTreeMenuItem);
3839     calculateTreeMenu.add(avDistanceTreeBlosumMenuItem);
3840     calculateTreeMenu.add(njTreeBlosumMenuItem);
3841     calculateMenu.add(calculateTreeMenu);
3842     calculateMenu.addSeparator();
3843     calculateMenu.add(pairwiseAlignmentMenuItem);
3844     calculateMenu.add(PCAMenuItem);
3845     calculateMenu.add(autoCalculate);
3846     calculateMenu.add(sortByTree);
3847
3848     /*
3849      * Help menu
3850      */
3851     helpMenu.add(documentation);
3852     helpMenu.add(about);
3853
3854     /*
3855      * Status bar
3856      */
3857     statusBar.setBackground(Color.white);
3858     statusBar.setFont(new java.awt.Font("Verdana", 0, 11));
3859     statusBar.setText(MessageManager.getString("label.status_bar"));
3860     this.add(statusBar, BorderLayout.SOUTH);
3861   }
3862
3863   @Override
3864   public void setStatus(String string)
3865   {
3866     statusBar.setText(string);
3867   };
3868
3869   MenuItem featureSettings = new MenuItem();
3870
3871   CheckboxMenuItem sequenceFeatures = new CheckboxMenuItem();
3872
3873   MenuItem annotationColour = new MenuItem();
3874
3875   MenuItem annotationColumnSelection = new MenuItem();
3876
3877   MenuItem invertColSel = new MenuItem();
3878
3879   MenuItem showColumns = new MenuItem();
3880
3881   MenuItem showSeqs = new MenuItem();
3882
3883   MenuItem hideColumns = new MenuItem();
3884
3885   MenuItem hideSequences = new MenuItem();
3886
3887   MenuItem hideAllButSelection = new MenuItem();
3888
3889   MenuItem hideAllSelection = new MenuItem();
3890
3891   MenuItem showAllHidden = new MenuItem();
3892
3893   MenuItem newView = new MenuItem();
3894
3895   private CheckboxMenuItem showAlignmentAnnotations;
3896
3897   private CheckboxMenuItem showSequenceAnnotations;
3898
3899   private CheckboxMenuItem sortAnnBySequence;
3900
3901   private CheckboxMenuItem sortAnnByLabel;
3902
3903   private CheckboxMenuItem showAutoFirst;
3904
3905   private CheckboxMenuItem showAutoLast;
3906
3907   private SplitFrame splitFrame;
3908
3909   /**
3910    * Attach the alignFrame panels after embedding menus, if necessary. This used
3911    * to be called setEmbedded, but is now creates the dropdown menus in a
3912    * platform independent manner to avoid OSX/Mac menu appendage daftness.
3913    * 
3914    * @param reallyEmbedded
3915    *          true to attach the view to the applet area on the page rather than
3916    *          in a new window
3917    */
3918   public void createAlignFrameWindow(boolean reallyEmbedded)
3919   {
3920     if (reallyEmbedded)
3921     {
3922       embedAlignFrameInApplet(viewport.applet);
3923     }
3924     else
3925     {
3926       // //////
3927       // test and embed menu bar if necessary.
3928       //
3929       if (embedMenuIfNeeded(alignPanel))
3930       {
3931         /*
3932          * adjust for status bar height too. ? pointless as overridden by layout
3933          * manager
3934          */
3935         alignPanel.setSize(getSize().width,
3936                 getSize().height - statusBar.getHeight());
3937       }
3938       add(statusBar, BorderLayout.SOUTH);
3939       add(alignPanel, BorderLayout.CENTER);
3940       // and register with the applet so it can pass external API calls to us
3941       jalview.bin.JalviewLite.addFrame(this, this.getTitle(), frameWidth,
3942               frameHeight);
3943     }
3944   }
3945
3946   /**
3947    * Add the components of this AlignFrame to the applet container.
3948    * 
3949    * @param theApplet
3950    */
3951   public void embedAlignFrameInApplet(final JalviewLite theApplet)
3952   {
3953     // ////
3954     // Explicitly build the embedded menu panel for the on-page applet
3955     //
3956     // view cannot be closed if its actually on the page
3957     fileMenu.remove(closeMenuItem);
3958     fileMenu.remove(3); // Remove Separator
3959     // construct embedded menu, using default font
3960     embeddedMenu = makeEmbeddedPopupMenu(alignFrameMenuBar, false, false);
3961     // and actually add the components to the applet area
3962     theApplet.setLayout(new BorderLayout());
3963     theApplet.add(embeddedMenu, BorderLayout.NORTH);
3964     theApplet.add(statusBar, BorderLayout.SOUTH);
3965     // TODO should size be left to the layout manager?
3966     alignPanel.setSize(theApplet.getSize().width, theApplet.getSize().height
3967             - embeddedMenu.getHeight() - statusBar.getHeight());
3968     theApplet.add(alignPanel, BorderLayout.CENTER);
3969     final AlignFrame me = this;
3970     theApplet.addFocusListener(new FocusListener()
3971     {
3972
3973       @Override
3974       public void focusLost(FocusEvent e)
3975       {
3976         if (theApplet.currentAlignFrame == me)
3977         {
3978           theApplet.currentAlignFrame = null;
3979         }
3980       }
3981
3982       @Override
3983       public void focusGained(FocusEvent e)
3984       {
3985         theApplet.currentAlignFrame = me;
3986       }
3987     });
3988     theApplet.validate();
3989   }
3990
3991   /**
3992    * create a new binding between structures in an existing jmol viewer instance
3993    * and an alignpanel with sequences that have existing PDBFile entries. Note,
3994    * this does not open a new Jmol window, or modify the display of the
3995    * structures in the original jmol window. Note This method doesn't work
3996    * without an additional javascript library to exchange messages between the
3997    * distinct applets. See http://issues.jalview.org/browse/JAL-621
3998    * 
3999    * @param viewer
4000    *          JmolViewer instance
4001    * @param sequenceIds
4002    *          - sequence Ids to search for associations
4003    */
4004   public SequenceStructureBinding addStructureViewInstance(
4005           Object jmolviewer, String[] sequenceIds)
4006   {
4007     Viewer viewer = null;
4008     try
4009     {
4010       viewer = (Viewer) jmolviewer;
4011     } catch (ClassCastException ex)
4012     {
4013       System.err.println(
4014               "Unsupported viewer object :" + jmolviewer.getClass());
4015     }
4016     if (viewer == null)
4017     {
4018       System.err.println("Can't use this object as a structure viewer:"
4019               + jmolviewer.getClass());
4020       return null;
4021     }
4022     SequenceI[] seqs = null;
4023     if (sequenceIds == null || sequenceIds.length == 0)
4024     {
4025       seqs = viewport.getAlignment().getSequencesArray();
4026     }
4027     else
4028     {
4029       Vector sqi = new Vector();
4030       AlignmentI al = viewport.getAlignment();
4031       for (int sid = 0; sid < sequenceIds.length; sid++)
4032       {
4033         SequenceI sq = al.findName(sequenceIds[sid]);
4034         if (sq != null)
4035         {
4036           sqi.addElement(sq);
4037         }
4038       }
4039       if (sqi.size() > 0)
4040       {
4041         seqs = new SequenceI[sqi.size()];
4042         for (int sid = 0, sSize = sqi.size(); sid < sSize; sid++)
4043         {
4044           seqs[sid] = (SequenceI) sqi.elementAt(sid);
4045         }
4046       }
4047       else
4048       {
4049         return null;
4050       }
4051     }
4052     AAStructureBindingModel jmv = null;
4053     // TODO: search for a jmv that involves viewer
4054     if (jmv == null)
4055     { // create a new viewer/jalview binding.
4056       jmv = new ExtJmol(viewer, alignPanel, new SequenceI[][] { seqs });
4057     }
4058     return jmv;
4059
4060   }
4061
4062   /**
4063    * bind a pdb file to a sequence in the current view
4064    * 
4065    * @param sequenceId
4066    *          - sequenceId within the dataset.
4067    * @param pdbEntryString
4068    *          - the short name for the PDB file
4069    * @param pdbFile
4070    *          - pdb file - either a URL or a valid PDB file.
4071    * @return true if binding was as success TODO: consider making an exception
4072    *         structure for indicating when PDB parsing or sequenceId location
4073    *         fails.
4074    */
4075   public boolean addPdbFile(String sequenceId, String pdbEntryString,
4076           String pdbFile)
4077   {
4078     SequenceI toaddpdb = viewport.getAlignment().findName(sequenceId);
4079     boolean needtoadd = false;
4080     if (toaddpdb != null)
4081     {
4082       Vector pdbe = toaddpdb.getAllPDBEntries();
4083       PDBEntry pdbentry = null;
4084       if (pdbe != null && pdbe.size() > 0)
4085       {
4086         for (int pe = 0, peSize = pdbe.size(); pe < peSize; pe++)
4087         {
4088           pdbentry = (PDBEntry) pdbe.elementAt(pe);
4089           if (!pdbentry.getId().equals(pdbEntryString)
4090                   && !pdbentry.getFile().equals(pdbFile))
4091           {
4092             pdbentry = null;
4093           }
4094           else
4095           {
4096             continue;
4097           }
4098         }
4099       }
4100       if (pdbentry == null)
4101       {
4102         pdbentry = new PDBEntry();
4103         pdbentry.setId(pdbEntryString);
4104         pdbentry.setFile(pdbFile);
4105         needtoadd = true; // add this new entry to sequence.
4106       }
4107       // resolve data source
4108       // TODO: this code should be a refactored to an io package
4109       DataSourceType protocol = AppletFormatAdapter.resolveProtocol(pdbFile,
4110               FileFormat.PDB);
4111       if (protocol == null)
4112       {
4113         return false;
4114       }
4115       if (needtoadd)
4116       {
4117         pdbentry.setProperty("protocol", protocol);
4118         toaddpdb.addPDBId(pdbentry);
4119         alignPanel.getStructureSelectionManager()
4120                 .registerPDBEntry(pdbentry);
4121       }
4122     }
4123     return true;
4124   }
4125
4126   private Object[] cleanSeqChainArrays(SequenceI[] seqs, String[] chains)
4127   {
4128     if (seqs != null)
4129     {
4130       Vector sequences = new Vector();
4131       for (int i = 0; i < seqs.length; i++)
4132       {
4133         if (seqs[i] != null)
4134         {
4135           sequences
4136                   .addElement(new Object[]
4137                   { seqs[i], (chains != null) ? chains[i] : null });
4138         }
4139       }
4140       seqs = new SequenceI[sequences.size()];
4141       chains = new String[sequences.size()];
4142       for (int i = 0, isize = sequences.size(); i < isize; i++)
4143       {
4144         Object[] oj = (Object[]) sequences.elementAt(i);
4145
4146         seqs[i] = (SequenceI) oj[0];
4147         chains[i] = (String) oj[1];
4148       }
4149     }
4150     return new Object[] { seqs, chains };
4151
4152   }
4153
4154   public void newStructureView(JalviewLite applet, PDBEntry pdb,
4155           SequenceI[] seqs, String[] chains, DataSourceType protocol)
4156   {
4157     // Scrub any null sequences from the array
4158     Object[] sqch = cleanSeqChainArrays(seqs, chains);
4159     seqs = (SequenceI[]) sqch[0];
4160     chains = (String[]) sqch[1];
4161     if (seqs == null || seqs.length == 0)
4162     {
4163       System.err.println(
4164               "JalviewLite.AlignFrame:newStructureView: No sequence to bind structure to.");
4165     }
4166     if (protocol == null)
4167     {
4168       String sourceType = (String) pdb.getProperty("protocol");
4169       try
4170       {
4171         protocol = DataSourceType.valueOf(sourceType);
4172       } catch (IllegalArgumentException e)
4173       {
4174         // ignore
4175       }
4176       if (protocol == null)
4177       {
4178         System.err.println("Couldn't work out protocol to open structure: "
4179                 + pdb.getId());
4180         return;
4181       }
4182     }
4183     if (applet.useXtrnalSviewer)
4184     {
4185       // register the association(s) and quit, don't create any windows.
4186       if (StructureSelectionManager.getStructureSelectionManager(applet)
4187               .setMapping(seqs, chains, pdb.getFile(), protocol, null) == null)
4188       {
4189         System.err.println("Failed to map " + pdb.getFile() + " ("
4190                 + protocol + ") to any sequences");
4191       }
4192       return;
4193     }
4194     if (applet.isAlignPdbStructures() && applet.jmolAvailable)
4195     {
4196       // can only do alignments with Jmol
4197       // find the last jmol window assigned to this alignment
4198       AppletJmol ajm = null, tajm;
4199       Vector jmols = applet.getAppletWindow(AppletJmol.class);
4200       for (int i = 0, iSize = jmols.size(); i < iSize; i++)
4201       {
4202         tajm = (AppletJmol) jmols.elementAt(i);
4203         if (tajm.ap.alignFrame == this)
4204         {
4205           ajm = tajm;
4206           break;
4207         }
4208       }
4209       if (ajm != null)
4210       {
4211         System.err.println(
4212                 "Incremental adding and aligning structure to existing Jmol view not yet implemented.");
4213         // try and add the pdb structure
4214         // ajm.addS
4215         ajm = null;
4216       }
4217     }
4218     // otherwise, create a new window
4219     if (applet.jmolAvailable)
4220     {
4221       new AppletJmol(pdb, seqs, chains, alignPanel, protocol);
4222       applet.lastFrameX += 40;
4223       applet.lastFrameY += 40;
4224     }
4225     else
4226     {
4227       new MCview.AppletPDBViewer(pdb, seqs, chains, alignPanel, protocol);
4228     }
4229
4230   }
4231
4232   public void alignedStructureView(JalviewLite applet, PDBEntry[] pdb,
4233           SequenceI[][] seqs, String[][] chains, String[] protocols)
4234   {
4235     // TODO Auto-generated method stub
4236     System.err.println("Aligned Structure View: Not yet implemented.");
4237   }
4238
4239   /**
4240    * modify the current selection, providing the user has not made a selection
4241    * already.
4242    * 
4243    * @param sel
4244    *          - sequences from this alignment
4245    * @param csel
4246    *          - columns to be selected on the alignment
4247    */
4248   public void select(SequenceGroup sel, ColumnSelection csel,
4249           HiddenColumns hidden)
4250   {
4251     alignPanel.seqPanel.selection(sel, csel, hidden, null);
4252   }
4253
4254   public void scrollTo(int row, int column)
4255   {
4256     alignPanel.seqPanel.scrollTo(row, column);
4257   }
4258
4259   public void scrollToRow(int row)
4260   {
4261     alignPanel.seqPanel.scrollToRow(row);
4262   }
4263
4264   public void scrollToColumn(int column)
4265   {
4266     alignPanel.seqPanel.scrollToColumn(column);
4267   }
4268
4269   /**
4270    * @return the alignments unique ID.
4271    */
4272   public String getSequenceSetId()
4273   {
4274     return viewport.getSequenceSetId();
4275   }
4276
4277   /**
4278    * Load the (T-Coffee) score file from the specified url
4279    * 
4280    * @param source
4281    *          File/URL/T-COFFEE score file contents
4282    * @throws IOException
4283    * @return true if alignment was annotated with data from source
4284    */
4285   public boolean loadScoreFile(String source) throws IOException
4286   {
4287
4288     TCoffeeScoreFile file = new TCoffeeScoreFile(source,
4289             AppletFormatAdapter.checkProtocol(source));
4290     if (!file.isValid())
4291     {
4292       // TODO: raise dialog for gui
4293       System.err.println("Problems parsing T-Coffee scores: "
4294               + file.getWarningMessage());
4295       System.err.println("Origin was:\n" + source);
4296       return false;
4297     }
4298
4299     /*
4300      * check that the score matrix matches the alignment dimensions
4301      */
4302     AlignmentI aln;
4303     if ((aln = viewport.getAlignment()) != null
4304             && (aln.getHeight() != file.getHeight()
4305                     || aln.getWidth() != file.getWidth()))
4306     {
4307       // TODO: raise a dialog box here rather than bomb out.
4308       System.err.println(
4309               "The scores matrix does not match the alignment dimensions");
4310
4311     }
4312
4313     // TODO add parameter to indicate if matching should be done
4314     if (file.annotateAlignment(alignPanel.getAlignment(), false))
4315     {
4316       alignPanel.fontChanged();
4317       tcoffeeColour.setEnabled(true);
4318       // switch to this color
4319       changeColour(new TCoffeeColourScheme(alignPanel.getAlignment()));
4320       return true;
4321     }
4322     else
4323     {
4324       System.err.println("Problems resolving T-Coffee scores:");
4325       if (file.getWarningMessage() != null)
4326       {
4327         System.err.println(file.getWarningMessage());
4328       }
4329     }
4330     return false;
4331   }
4332
4333   public SplitFrame getSplitFrame()
4334   {
4335     return this.splitFrame;
4336   }
4337
4338   public void setSplitFrame(SplitFrame sf)
4339   {
4340     this.splitFrame = sf;
4341   }
4342
4343   // may not need this
4344   @Override
4345   public void setShowSeqFeatures(boolean b)
4346   {
4347     // showSeqFeatures.setSelected(b);
4348     viewport.setShowSequenceFeatures(b);
4349
4350   }
4351
4352   @Override
4353   public void setMenusForViewport()
4354   {
4355     // setMenusFromViewport(viewport);
4356
4357   }
4358
4359   @Override
4360   public void refreshFeatureUI(boolean enableIfNecessary)
4361   {
4362     if (enableIfNecessary)
4363     {
4364       sequenceFeatures.setState(true);
4365       alignPanel.av.setShowSequenceFeatures(true);
4366     }
4367   }
4368
4369   @Override
4370   public FeatureSettingsControllerI getFeatureSettingsUI()
4371   {
4372     return alignPanel.av.featureSettings;
4373   }
4374
4375   @Override
4376   public FeatureSettingsControllerI showFeatureSettingsUI()
4377   {
4378     return new FeatureSettings(alignPanel);
4379   }
4380
4381   private Rectangle fs_bounds = null;
4382
4383   @Override
4384   public void setFeatureSettingsGeometry(Rectangle bounds)
4385   {
4386     fs_bounds = bounds;
4387   }
4388
4389   @Override
4390   public Rectangle getFeatureSettingsGeometry()
4391   {
4392     return fs_bounds;
4393   }
4394
4395 }