Merge branch 'Jalview-JS/develop' into merge_js_develop
[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       setStatus(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       setStatus(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.setAutoCalculateConsensusAndConservation(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.notifyAlignment();
1714   }
1715
1716   /**
1717    * TODO: JAL-1104 DOCUMENT ME!
1718    * 
1719    * @param e
1720    *          DOCUMENT ME!
1721    */
1722   protected void redoMenuItem_actionPerformed()
1723   {
1724     if (viewport.getRedoList().isEmpty())
1725     {
1726       return;
1727     }
1728
1729     CommandI command = viewport.getRedoList().pop();
1730     viewport.addToHistoryList(command);
1731     command.doCommand(null);
1732
1733     AlignmentViewport originalSource = getOriginatingSource(command);
1734     // JBPNote Test
1735     if (originalSource != viewport)
1736     {
1737       System.err
1738               .println("Warning: Viewport object mismatch whilst re-doing");
1739     }
1740     originalSource.updateHiddenColumns(); // sethasHiddenColumns(); =
1741                                           // viewport.getColumnSelection().getHiddenColumns()
1742                                           // != null;
1743
1744     updateEditMenuBar();
1745     originalSource.notifyAlignment();
1746   }
1747
1748   AlignmentViewport getOriginatingSource(CommandI command)
1749   {
1750     AlignmentViewport originalSource = null;
1751     // For sequence removal and addition, we need to fire
1752     // the property change event FROM the viewport where the
1753     // original alignment was altered
1754     AlignmentI al = null;
1755     if (command instanceof EditCommand)
1756     {
1757       EditCommand editCommand = (EditCommand) command;
1758       al = editCommand.getAlignment();
1759       Vector comps = PaintRefresher.components
1760               .get(viewport.getSequenceSetId());
1761       for (int i = 0; i < comps.size(); i++)
1762       {
1763         if (comps.elementAt(i) instanceof AlignmentPanel)
1764         {
1765           if (al == ((AlignmentPanel) comps.elementAt(i)).av.getAlignment())
1766           {
1767             originalSource = ((AlignmentPanel) comps.elementAt(i)).av;
1768             break;
1769           }
1770         }
1771       }
1772     }
1773
1774     if (originalSource == null)
1775     {
1776       // The original view is closed, we must validate
1777       // the current view against the closed view first
1778       if (al != null)
1779       {
1780         PaintRefresher.validateSequences(al, viewport.getAlignment());
1781       }
1782
1783       originalSource = viewport;
1784     }
1785
1786     return originalSource;
1787   }
1788
1789   /**
1790    * Move the currently selected sequences up or down one position in the
1791    * alignment
1792    * 
1793    * @param up
1794    */
1795   public void moveSelectedSequences(boolean up)
1796   {
1797     SequenceGroup sg = viewport.getSelectionGroup();
1798     if (sg == null)
1799     {
1800       return;
1801     }
1802     viewport.getAlignment().moveSelectedSequencesByOne(sg,
1803             up ? null : viewport.getHiddenRepSequences(), up);
1804     alignPanel.paintAlignment(true, false);
1805
1806     /*
1807      * Also move cDNA/protein complement sequences
1808      */
1809     AlignViewportI complement = viewport.getCodingComplement();
1810     if (complement != null)
1811     {
1812       SequenceGroup mappedSelection = MappingUtils.mapSequenceGroup(sg,
1813               viewport, complement);
1814       complement.getAlignment().moveSelectedSequencesByOne(mappedSelection,
1815               up ? null : complement.getHiddenRepSequences(), up);
1816       getSplitFrame().getComplement(this).alignPanel.paintAlignment(true,
1817               false);
1818     }
1819   }
1820
1821   synchronized void slideSequences(boolean right, int size)
1822   {
1823     List<SequenceI> sg = new Vector<>();
1824     if (viewport.cursorMode)
1825     {
1826       sg.add(viewport.getAlignment()
1827               .getSequenceAt(alignPanel.seqPanel.seqCanvas.cursorY));
1828     }
1829     else if (viewport.getSelectionGroup() != null
1830             && viewport.getSelectionGroup().getSize() != viewport
1831                     .getAlignment().getHeight())
1832     {
1833       sg = viewport.getSelectionGroup()
1834               .getSequences(viewport.getHiddenRepSequences());
1835     }
1836
1837     if (sg.size() < 1)
1838     {
1839       return;
1840     }
1841
1842     Vector<SequenceI> invertGroup = new Vector();
1843
1844     for (int i = 0; i < viewport.getAlignment().getHeight(); i++)
1845     {
1846       if (!sg.contains(viewport.getAlignment().getSequenceAt(i)))
1847       {
1848         invertGroup.addElement(viewport.getAlignment().getSequenceAt(i));
1849       }
1850     }
1851
1852     SequenceI[] seqs1 = sg.toArray(new SequenceI[sg.size()]);
1853
1854     SequenceI[] seqs2 = invertGroup
1855             .toArray(new SequenceI[invertGroup.size()]);
1856     for (int i = 0; i < invertGroup.size(); i++)
1857     {
1858       seqs2[i] = invertGroup.elementAt(i);
1859     }
1860
1861     SlideSequencesCommand ssc;
1862     if (right)
1863     {
1864       ssc = new SlideSequencesCommand("Slide Sequences", seqs2, seqs1, size,
1865               viewport.getGapCharacter());
1866     }
1867     else
1868     {
1869       ssc = new SlideSequencesCommand("Slide Sequences", seqs1, seqs2, size,
1870               viewport.getGapCharacter());
1871     }
1872
1873     int groupAdjustment = 0;
1874     if (ssc.getGapsInsertedBegin() && right)
1875     {
1876       if (viewport.cursorMode)
1877       {
1878         alignPanel.seqPanel.moveCursor(size, 0);
1879       }
1880       else
1881       {
1882         groupAdjustment = size;
1883       }
1884     }
1885     else if (!ssc.getGapsInsertedBegin() && !right)
1886     {
1887       if (viewport.cursorMode)
1888       {
1889         alignPanel.seqPanel.moveCursor(-size, 0);
1890       }
1891       else
1892       {
1893         groupAdjustment = -size;
1894       }
1895     }
1896
1897     if (groupAdjustment != 0)
1898     {
1899       viewport.getSelectionGroup().setStartRes(
1900               viewport.getSelectionGroup().getStartRes() + groupAdjustment);
1901       viewport.getSelectionGroup().setEndRes(
1902               viewport.getSelectionGroup().getEndRes() + groupAdjustment);
1903     }
1904
1905     boolean appendHistoryItem = false;
1906     Deque<CommandI> historyList = viewport.getHistoryList();
1907     if (historyList != null && historyList.size() > 0
1908             && historyList.peek() instanceof SlideSequencesCommand)
1909     {
1910       appendHistoryItem = ssc.appendSlideCommand(
1911               (SlideSequencesCommand) historyList.peek());
1912     }
1913
1914     if (!appendHistoryItem)
1915     {
1916       addHistoryItem(ssc);
1917     }
1918
1919     repaint();
1920   }
1921
1922   static StringBuffer copiedSequences;
1923
1924   static HiddenColumns copiedHiddenColumns;
1925
1926   protected void copy_actionPerformed()
1927   {
1928     if (viewport.getSelectionGroup() == null)
1929     {
1930       return;
1931     }
1932
1933     SequenceGroup sg = viewport.getSelectionGroup();
1934     copiedSequences = new StringBuffer();
1935     Map<Integer, SequenceI> orderedSeqs = new HashMap<>();
1936     for (int i = 0; i < sg.getSize(); i++)
1937     {
1938       SequenceI seq = sg.getSequenceAt(i);
1939       int index = viewport.getAlignment().findIndex(seq);
1940       orderedSeqs.put(index, seq);
1941     }
1942
1943     int index = 0, startRes, endRes;
1944     char ch;
1945
1946     if (viewport.hasHiddenColumns() && viewport.getSelectionGroup() != null)
1947     {
1948       int hiddenOffset = viewport.getSelectionGroup().getStartRes();
1949       int hiddenCutoff = viewport.getSelectionGroup().getEndRes();
1950
1951       // create new HiddenColumns object with copy of hidden regions
1952       // between startRes and endRes, offset by startRes
1953       copiedHiddenColumns = new HiddenColumns(
1954               viewport.getAlignment().getHiddenColumns(), hiddenOffset,
1955               hiddenCutoff, hiddenOffset);
1956     }
1957     else
1958     {
1959       copiedHiddenColumns = null;
1960     }
1961
1962     for (int i = 0; i < sg.getSize(); i++)
1963     {
1964       SequenceI seq = null;
1965
1966       while (seq == null)
1967       {
1968         if (orderedSeqs.containsKey(index))
1969         {
1970           seq = orderedSeqs.get(index);
1971           index++;
1972           break;
1973         }
1974         else
1975         {
1976           index++;
1977         }
1978       }
1979
1980       // FIND START RES
1981       // Returns residue following index if gap
1982       startRes = seq.findPosition(sg.getStartRes());
1983
1984       // FIND END RES
1985       // Need to find the residue preceeding index if gap
1986       endRes = 0;
1987
1988       for (int j = 0; j < sg.getEndRes() + 1 && j < seq.getLength(); j++)
1989       {
1990         ch = seq.getCharAt(j);
1991         if (!jalview.util.Comparison.isGap((ch)))
1992         {
1993           endRes++;
1994         }
1995       }
1996
1997       if (endRes > 0)
1998       {
1999         endRes += seq.getStart() - 1;
2000       }
2001
2002       copiedSequences.append(seq.getName() + "\t" + startRes + "\t" + endRes
2003               + "\t" + seq.getSequenceAsString(sg.getStartRes(),
2004                       sg.getEndRes() + 1)
2005               + "\n");
2006     }
2007
2008   }
2009
2010   protected void pasteNew_actionPerformed()
2011   {
2012     paste(true);
2013   }
2014
2015   protected void pasteThis_actionPerformed()
2016   {
2017     paste(false);
2018   }
2019
2020   void paste(boolean newAlignment)
2021   {
2022     try
2023     {
2024       if (copiedSequences == null)
2025       {
2026         return;
2027       }
2028
2029       StringTokenizer st = new StringTokenizer(copiedSequences.toString(),
2030               "\t");
2031       Vector seqs = new Vector();
2032       while (st.hasMoreElements())
2033       {
2034         String name = st.nextToken();
2035         int start = Integer.parseInt(st.nextToken());
2036         int end = Integer.parseInt(st.nextToken());
2037         seqs.addElement(new Sequence(name, st.nextToken(), start, end));
2038       }
2039       SequenceI[] newSeqs = new SequenceI[seqs.size()];
2040       for (int i = 0; i < seqs.size(); i++)
2041       {
2042         newSeqs[i] = (SequenceI) seqs.elementAt(i);
2043       }
2044
2045       if (newAlignment)
2046       {
2047         String newtitle = MessageManager
2048                 .getString("label.copied_sequences");
2049         if (getTitle().startsWith(
2050                 MessageManager.getString("label.copied_sequences")))
2051         {
2052           newtitle = getTitle();
2053         }
2054         else
2055         {
2056           newtitle = newtitle.concat(MessageManager
2057                   .formatMessage("label.from_msname", new String[]
2058                   { getTitle() }));
2059         }
2060         AlignFrame af = new AlignFrame(new Alignment(newSeqs),
2061                 viewport.applet, newtitle, false);
2062         af.viewport.setHiddenColumns(copiedHiddenColumns);
2063
2064         jalview.bin.JalviewLite.addFrame(af, newtitle, frameWidth,
2065                 frameHeight);
2066       }
2067       else
2068       {
2069         addSequences(newSeqs);
2070       }
2071
2072     } catch (Exception ex)
2073     {
2074     } // could be anything being pasted in here
2075
2076   }
2077
2078   void addSequences(SequenceI[] seqs)
2079   {
2080     for (int i = 0; i < seqs.length; i++)
2081     {
2082       viewport.getAlignment().addSequence(seqs[i]);
2083     }
2084
2085     // !newAlignment
2086     addHistoryItem(new EditCommand(
2087             MessageManager.getString("label.add_sequences"), Action.PASTE,
2088             seqs, 0, viewport.getAlignment().getWidth(),
2089             viewport.getAlignment()));
2090
2091     viewport.getRanges().setEndSeq(viewport.getAlignment().getHeight() - 1); // BH
2092                                                                              // 2019.04.18
2093     viewport.getAlignment().getWidth();
2094     viewport.notifyAlignment();
2095
2096   }
2097
2098   protected void cut_actionPerformed()
2099   {
2100     copy_actionPerformed();
2101     delete_actionPerformed();
2102   }
2103
2104   protected void delete_actionPerformed()
2105   {
2106
2107     SequenceGroup sg = viewport.getSelectionGroup();
2108     if (sg == null)
2109     {
2110       return;
2111     }
2112
2113     Vector seqs = new Vector();
2114     SequenceI seq;
2115     for (int i = 0; i < sg.getSize(); i++)
2116     {
2117       seq = sg.getSequenceAt(i);
2118       seqs.addElement(seq);
2119     }
2120
2121     /*
2122      * If the cut affects all sequences, warn, remove highlighted columns
2123      */
2124     if (sg.getSize() == viewport.getAlignment().getHeight())
2125     {
2126       boolean isEntireAlignWidth = (((sg.getEndRes() - sg.getStartRes())
2127               + 1) == viewport.getAlignment().getWidth()) ? true : false;
2128       if (isEntireAlignWidth)
2129       {
2130         String title = MessageManager.getString("label.delete_all");
2131         Panel infoPanel = new Panel();
2132         infoPanel.setLayout(new FlowLayout());
2133         infoPanel.add(
2134                 new Label(MessageManager.getString("warn.delete_all")));
2135
2136         final JVDialog dialog = new JVDialog(this, title, true, 400, 200);
2137         dialog.setMainPanel(infoPanel);
2138         dialog.ok.setLabel(MessageManager.getString("action.ok"));
2139         dialog.cancel.setLabel(MessageManager.getString("action.cancel"));
2140         dialog.setVisible(true);
2141
2142         if (!dialog.accept)
2143         {
2144           return;
2145         }
2146       }
2147       viewport.getColumnSelection().removeElements(sg.getStartRes(),
2148               sg.getEndRes() + 1);
2149     }
2150
2151     SequenceI[] cut = new SequenceI[seqs.size()];
2152     for (int i = 0; i < seqs.size(); i++)
2153     {
2154       cut[i] = (SequenceI) seqs.elementAt(i);
2155     }
2156
2157     /*
2158      * //ADD HISTORY ITEM
2159      */
2160     addHistoryItem(new EditCommand(
2161             MessageManager.getString("label.cut_sequences"), Action.CUT,
2162             cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
2163             viewport.getAlignment()));
2164
2165     viewport.setSelectionGroup(null);
2166     viewport.getAlignment().deleteGroup(sg);
2167
2168     viewport.notifyAlignment();
2169
2170     if (viewport.getAlignment().getHeight() < 1)
2171     {
2172       this.setVisible(false);
2173     }
2174     viewport.sendSelection();
2175   }
2176
2177   /**
2178    * group consensus toggled
2179    * 
2180    */
2181   protected void showGroupConsensus_actionPerformed()
2182   {
2183     viewport.setShowGroupConsensus(showGroupConsensus.getState());
2184     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2185
2186   }
2187
2188   /**
2189    * group conservation toggled.
2190    */
2191   protected void showGroupConservation_actionPerformed()
2192   {
2193     viewport.setShowGroupConservation(showGroupConservation.getState());
2194     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2195   }
2196
2197   /*
2198    * (non-Javadoc)
2199    * 
2200    * @see
2201    * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt
2202    * .event.ActionEvent)
2203    */
2204   protected void showConsensusHistogram_actionPerformed()
2205   {
2206     viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
2207     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2208   }
2209
2210   /*
2211    * (non-Javadoc)
2212    * 
2213    * @see
2214    * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt
2215    * .event.ActionEvent)
2216    */
2217   protected void showSequenceLogo_actionPerformed()
2218   {
2219     viewport.setShowSequenceLogo(showSequenceLogo.getState());
2220     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2221   }
2222
2223   protected void normSequenceLogo_actionPerformed()
2224   {
2225     showSequenceLogo.setState(true);
2226     viewport.setShowSequenceLogo(true);
2227     viewport.setNormaliseSequenceLogo(normSequenceLogo.getState());
2228     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2229   }
2230
2231   protected void applyAutoAnnotationSettings_actionPerformed()
2232   {
2233     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2234   }
2235
2236   protected void makeGrpsFromSelection_actionPerformed()
2237   {
2238     if (avc.makeGroupsFromSelection())
2239     {
2240       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
2241       alignPanel.updateAnnotation();
2242       alignPanel.paintAlignment(true, true);
2243     }
2244   }
2245
2246   protected void createGroup_actionPerformed()
2247   {
2248     avc.createGroup();
2249   }
2250
2251   protected void unGroup_actionPerformed()
2252   {
2253     if (avc.unGroup())
2254     {
2255       alignPanel.alignmentChanged();
2256     }
2257   }
2258
2259   protected void deleteGroups_actionPerformed()
2260   {
2261     if (avc.deleteGroups())
2262     {
2263       alignPanel.alignmentChanged();
2264     }
2265   }
2266
2267   public void selectAllSequenceMenuItem_actionPerformed()
2268   {
2269     SequenceGroup sg = new SequenceGroup();
2270     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2271     {
2272       sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
2273     }
2274     sg.setEndRes(viewport.getAlignment().getWidth() - 1);
2275     viewport.setSelectionGroup(sg);
2276     // JAL-2034 - should delegate to
2277     // alignPanel to decide if overview needs
2278     // updating.
2279     alignPanel.paintAlignment(false, false);
2280     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2281     viewport.sendSelection();
2282   }
2283
2284   public void deselectAllSequenceMenuItem_actionPerformed()
2285   {
2286     if (viewport.cursorMode)
2287     {
2288       alignPanel.seqPanel.keyboardNo1 = null;
2289       alignPanel.seqPanel.keyboardNo2 = null;
2290     }
2291     viewport.setSelectionGroup(null);
2292     viewport.getColumnSelection().clear();
2293     viewport.setSelectionGroup(null);
2294     alignPanel.idPanel.idCanvas.searchResults = null;
2295     alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);
2296     // JAL-2034 - should delegate to
2297     // alignPanel to decide if overview needs
2298     // updating.
2299     alignPanel.paintAlignment(false, false);
2300     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2301     viewport.sendSelection();
2302   }
2303
2304   public void invertSequenceMenuItem_actionPerformed()
2305   {
2306     SequenceGroup sg = viewport.getSelectionGroup();
2307     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2308     {
2309       sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
2310     }
2311
2312     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2313     viewport.sendSelection();
2314   }
2315
2316   public void invertColSel_actionPerformed()
2317   {
2318     viewport.invertColumnSelection();
2319     alignPanel.paintAlignment(true, false);
2320     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2321     viewport.sendSelection();
2322   }
2323
2324   void trimAlignment(boolean trimLeft)
2325   {
2326     AlignmentI al = viewport.getAlignment();
2327     ViewportRanges ranges = viewport.getRanges();
2328     ColumnSelection colSel = viewport.getColumnSelection();
2329     int column;
2330
2331     if (!colSel.isEmpty())
2332     {
2333       if (trimLeft)
2334       {
2335         column = colSel.getMin();
2336       }
2337       else
2338       {
2339         column = colSel.getMax();
2340       }
2341
2342       SequenceI[] seqs;
2343       if (viewport.getSelectionGroup() != null)
2344       {
2345         seqs = viewport.getSelectionGroup()
2346                 .getSequencesAsArray(viewport.getHiddenRepSequences());
2347       }
2348       else
2349       {
2350         seqs = al.getSequencesArray();
2351       }
2352
2353       TrimRegionCommand trimRegion;
2354       if (trimLeft)
2355       {
2356         trimRegion = new TrimRegionCommand("Remove Left", true, seqs,
2357                 column, al);
2358         ranges.setStartRes(0);
2359       }
2360       else
2361       {
2362         trimRegion = new TrimRegionCommand("Remove Right", false, seqs,
2363                 column, al);
2364       }
2365
2366       setStatus(MessageManager
2367               .formatMessage("label.removed_columns", new String[]
2368               { Integer.valueOf(trimRegion.getSize()).toString() }));
2369       addHistoryItem(trimRegion);
2370
2371       for (SequenceGroup sg : al.getGroups())
2372       {
2373         if ((trimLeft && !sg.adjustForRemoveLeft(column))
2374                 || (!trimLeft && !sg.adjustForRemoveRight(column)))
2375         {
2376           al.deleteGroup(sg);
2377         }
2378       }
2379
2380       viewport.notifyAlignment();
2381     }
2382   }
2383
2384   public void removeGappedColumnMenuItem_actionPerformed()
2385   {
2386     AlignmentI al = viewport.getAlignment();
2387     ViewportRanges ranges = viewport.getRanges();
2388     int start = 0;
2389     int end = ranges.getAbsoluteAlignmentWidth() - 1;
2390
2391     SequenceI[] seqs;
2392     if (viewport.getSelectionGroup() != null)
2393     {
2394       seqs = viewport.getSelectionGroup()
2395               .getSequencesAsArray(viewport.getHiddenRepSequences());
2396       start = viewport.getSelectionGroup().getStartRes();
2397       end = viewport.getSelectionGroup().getEndRes();
2398     }
2399     else
2400     {
2401       seqs = viewport.getAlignment().getSequencesArray();
2402     }
2403
2404     RemoveGapColCommand removeGapCols = new RemoveGapColCommand(
2405             "Remove Gapped Columns", seqs, start, end,
2406             viewport.getAlignment());
2407
2408     addHistoryItem(removeGapCols);
2409
2410     setStatus(MessageManager
2411             .formatMessage("label.removed_empty_columns", new String[]
2412             { Integer.valueOf(removeGapCols.getSize()).toString() }));
2413
2414     // This is to maintain viewport position on first residue
2415     // of first sequence
2416     SequenceI seq = al.getSequenceAt(0);
2417     int startRes = seq.findPosition(ranges.getStartRes());
2418     // ShiftList shifts;
2419     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
2420     // edit.alColumnChanges=shifts.getInverse();
2421     // if (viewport.hasHiddenColumns)
2422     // viewport.getColumnSelection().compensateForEdits(shifts);
2423     ranges.setStartRes(seq.findIndex(startRes) - 1);
2424     viewport.notifyAlignment();
2425
2426   }
2427
2428   public void removeAllGapsMenuItem_actionPerformed()
2429   {
2430     AlignmentI al = viewport.getAlignment();
2431     ViewportRanges ranges = viewport.getRanges();
2432     int start = 0;
2433     int end = ranges.getAbsoluteAlignmentWidth() - 1;
2434
2435     SequenceI[] seqs;
2436     if (viewport.getSelectionGroup() != null)
2437     {
2438       seqs = viewport.getSelectionGroup()
2439               .getSequencesAsArray(viewport.getHiddenRepSequences());
2440       start = viewport.getSelectionGroup().getStartRes();
2441       end = viewport.getSelectionGroup().getEndRes();
2442     }
2443     else
2444     {
2445       seqs = viewport.getAlignment().getSequencesArray();
2446     }
2447
2448     // This is to maintain viewport position on first residue
2449     // of first sequence
2450     SequenceI seq = al.getSequenceAt(0);
2451     int startRes = seq.findPosition(ranges.getStartRes());
2452
2453     addHistoryItem(
2454             new RemoveGapsCommand("Remove Gaps", seqs, start, end, al));
2455
2456     ranges.setStartRes(seq.findIndex(startRes) - 1);
2457
2458     viewport.notifyAlignment();
2459
2460   }
2461
2462   public void findMenuItem_actionPerformed()
2463   {
2464     new Finder(alignPanel);
2465   }
2466
2467   /**
2468    * create a new view derived from the current view
2469    * 
2470    * @param viewtitle
2471    * @return frame for the new view
2472    */
2473   public AlignFrame newView(String viewtitle)
2474   {
2475     AlignmentI newal;
2476     if (viewport.hasHiddenRows())
2477     {
2478       newal = new Alignment(viewport.getAlignment().getHiddenSequences()
2479               .getFullAlignment().getSequencesArray());
2480     }
2481     else
2482     {
2483       newal = new Alignment(viewport.getAlignment().getSequencesArray());
2484     }
2485
2486     if (viewport.getAlignment().getAlignmentAnnotation() != null)
2487     {
2488       for (int i = 0; i < viewport.getAlignment()
2489               .getAlignmentAnnotation().length; i++)
2490       {
2491         if (!viewport.getAlignment()
2492                 .getAlignmentAnnotation()[i].autoCalculated)
2493         {
2494           newal.addAnnotation(
2495                   viewport.getAlignment().getAlignmentAnnotation()[i]);
2496         }
2497       }
2498     }
2499
2500     AlignFrame newaf = new AlignFrame(newal, viewport.applet, "", false);
2501
2502     newaf.viewport.setSequenceSetId(alignPanel.av.getSequenceSetId());
2503     PaintRefresher.Register(alignPanel, alignPanel.av.getSequenceSetId());
2504     PaintRefresher.Register(newaf.alignPanel,
2505             newaf.alignPanel.av.getSequenceSetId());
2506
2507     PaintRefresher.Register(newaf.alignPanel.idPanel.idCanvas,
2508             newaf.alignPanel.av.getSequenceSetId());
2509     PaintRefresher.Register(newaf.alignPanel.seqPanel.seqCanvas,
2510             newaf.alignPanel.av.getSequenceSetId());
2511
2512     Vector comps = PaintRefresher.components
2513             .get(viewport.getSequenceSetId());
2514     int viewSize = -1;
2515     for (int i = 0; i < comps.size(); i++)
2516     {
2517       if (comps.elementAt(i) instanceof AlignmentPanel)
2518       {
2519         viewSize++;
2520       }
2521     }
2522
2523     String title = new String(this.getTitle());
2524     if (viewtitle != null)
2525     {
2526       title = viewtitle + " ( " + title + ")";
2527     }
2528     else
2529     {
2530       if (title.indexOf("(View") > -1)
2531       {
2532         title = title.substring(0, title.indexOf("(View"));
2533       }
2534       title += "(View " + viewSize + ")";
2535     }
2536
2537     newaf.setTitle(title.toString());
2538
2539     newaf.viewport.setHistoryList(viewport.getHistoryList());
2540     newaf.viewport.setRedoList(viewport.getRedoList());
2541     return newaf;
2542   }
2543
2544   /**
2545    * 
2546    * @return list of feature groups on the view
2547    */
2548   public String[] getFeatureGroups()
2549   {
2550     FeatureRenderer fr = null;
2551     if (alignPanel != null
2552             && (fr = alignPanel.getFeatureRenderer()) != null)
2553     {
2554       List<String> gps = fr.getFeatureGroups();
2555       String[] _gps = gps.toArray(new String[gps.size()]);
2556       return _gps;
2557     }
2558     return null;
2559   }
2560
2561   /**
2562    * get sequence feature groups that are hidden or shown
2563    * 
2564    * @param visible
2565    *          true is visible
2566    * @return list
2567    */
2568   public String[] getFeatureGroupsOfState(boolean visible)
2569   {
2570     FeatureRenderer fr = null;
2571     if (alignPanel != null
2572             && (fr = alignPanel.getFeatureRenderer()) != null)
2573     {
2574       List<String> gps = fr.getGroups(visible);
2575       String[] _gps = gps.toArray(new String[gps.size()]);
2576       return _gps;
2577     }
2578     return null;
2579   }
2580
2581   /**
2582    * Change the display state for the given feature groups
2583    * 
2584    * @param groups
2585    *          list of group strings
2586    * @param state
2587    *          visible or invisible
2588    */
2589   public void setFeatureGroupState(String[] groups, boolean state)
2590   {
2591     FeatureRenderer fr = null;
2592     this.sequenceFeatures.setState(true);
2593     viewport.setShowSequenceFeatures(true);
2594     if (alignPanel != null
2595             && (fr = alignPanel.getFeatureRenderer()) != null)
2596     {
2597
2598       fr.setGroupVisibility(Arrays.asList(groups), state);
2599       alignPanel.seqPanel.seqCanvas.repaint();
2600       if (alignPanel.overviewPanel != null)
2601       {
2602         alignPanel.overviewPanel.updateOverviewImage();
2603       }
2604     }
2605   }
2606
2607   public void seqLimits_itemStateChanged()
2608   {
2609     viewport.setShowJVSuffix(seqLimits.getState());
2610     alignPanel.fontChanged();
2611     alignPanel.paintAlignment(true, false);
2612   }
2613
2614   protected void colourTextMenuItem_actionPerformed()
2615   {
2616     viewport.setColourText(colourTextMenuItem.getState());
2617     alignPanel.paintAlignment(false, false);
2618   }
2619
2620   protected void displayNonconservedMenuItem_actionPerformed()
2621   {
2622     viewport.setShowUnconserved(displayNonconservedMenuItem.getState());
2623     alignPanel.paintAlignment(false, false);
2624   }
2625
2626   protected void wrapMenuItem_actionPerformed()
2627   {
2628     viewport.setWrapAlignment(wrapMenuItem.getState());
2629     alignPanel.setWrapAlignment(wrapMenuItem.getState());
2630     scaleAbove.setEnabled(wrapMenuItem.getState());
2631     scaleLeft.setEnabled(wrapMenuItem.getState());
2632     scaleRight.setEnabled(wrapMenuItem.getState());
2633     alignPanel.paintAlignment(true, false);
2634   }
2635
2636   public void overviewMenuItem_actionPerformed()
2637   {
2638     if (alignPanel.overviewPanel != null)
2639     {
2640       return;
2641     }
2642
2643     Frame frame = new Frame();
2644     final OverviewPanel overview = new OverviewPanel(alignPanel);
2645     frame.add(overview);
2646     // +50 must allow for applet frame window
2647     jalview.bin.JalviewLite.addFrame(frame, MessageManager
2648             .formatMessage("label.overview_params", new String[]
2649             { this.getTitle() }), overview.getPreferredSize().width,
2650             overview.getPreferredSize().height + 50);
2651
2652     frame.pack();
2653     final AlignmentPanel ap = alignPanel;
2654     frame.addWindowListener(new WindowAdapter()
2655     {
2656       @Override
2657       public void windowClosing(WindowEvent e)
2658       {
2659         overview.dispose();
2660         if (ap != null)
2661         {
2662           ap.setOverviewPanel(null);
2663         }
2664       };
2665     });
2666
2667     alignPanel.setOverviewPanel(overview);
2668
2669   }
2670
2671   @Override
2672   public void changeColour(ColourSchemeI cs)
2673   {
2674     viewport.setGlobalColourScheme(cs);
2675
2676     alignPanel.paintAlignment(true, true);
2677   }
2678
2679   protected void modifyPID_actionPerformed()
2680   {
2681     if (viewport.getAbovePIDThreshold()
2682             && viewport.getGlobalColourScheme() != null)
2683     {
2684       SliderPanel.setPIDSliderSource(alignPanel,
2685               viewport.getResidueShading(), alignPanel.getViewName());
2686       SliderPanel.showPIDSlider();
2687     }
2688   }
2689
2690   protected void modifyConservation_actionPerformed()
2691   {
2692     if (viewport.getConservationSelected()
2693             && viewport.getGlobalColourScheme() != null)
2694     {
2695       SliderPanel.setConservationSlider(alignPanel,
2696               viewport.getResidueShading(), alignPanel.getViewName());
2697       SliderPanel.showConservationSlider();
2698     }
2699   }
2700
2701   protected void conservationMenuItem_actionPerformed()
2702   {
2703     boolean selected = conservationMenuItem.getState();
2704     modifyConservation.setEnabled(selected);
2705     viewport.setConservationSelected(selected);
2706     viewport.getResidueShading().setConservationApplied(selected);
2707
2708     changeColour(viewport.getGlobalColourScheme());
2709
2710     if (selected)
2711     {
2712       modifyConservation_actionPerformed();
2713     }
2714     else
2715     {
2716       SliderPanel.hideConservationSlider();
2717     }
2718   }
2719
2720   public void abovePIDThreshold_actionPerformed()
2721   {
2722     boolean selected = abovePIDThreshold.getState();
2723     modifyPID.setEnabled(selected);
2724     viewport.setAbovePIDThreshold(selected);
2725     if (!selected)
2726     {
2727       viewport.getResidueShading().setThreshold(0,
2728               viewport.isIgnoreGapsConsensus());
2729     }
2730
2731     changeColour(viewport.getGlobalColourScheme());
2732
2733     if (selected)
2734     {
2735       modifyPID_actionPerformed();
2736     }
2737     else
2738     {
2739       SliderPanel.hidePIDSlider();
2740     }
2741   }
2742
2743   public void sortPairwiseMenuItem_actionPerformed()
2744   {
2745     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2746     AlignmentSorter.sortByPID(viewport.getAlignment(),
2747             viewport.getAlignment().getSequenceAt(0));
2748
2749     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
2750             viewport.getAlignment()));
2751     alignPanel.paintAlignment(true, false);
2752   }
2753
2754   public void sortIDMenuItem_actionPerformed()
2755   {
2756     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2757     AlignmentSorter.sortByID(viewport.getAlignment());
2758     addHistoryItem(
2759             new OrderCommand("ID Sort", oldOrder, viewport.getAlignment()));
2760     alignPanel.paintAlignment(true, false);
2761   }
2762
2763   public void sortLengthMenuItem_actionPerformed()
2764   {
2765     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2766     AlignmentSorter.sortByLength(viewport.getAlignment());
2767     addHistoryItem(new OrderCommand("Length Sort", oldOrder,
2768             viewport.getAlignment()));
2769     alignPanel.paintAlignment(true, false);
2770   }
2771
2772   public void sortGroupMenuItem_actionPerformed()
2773   {
2774     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2775     AlignmentSorter.sortByGroup(viewport.getAlignment());
2776     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
2777             viewport.getAlignment()));
2778     alignPanel.paintAlignment(true, false);
2779
2780   }
2781
2782   public void sortEValueMenuItem_actionPerformed()
2783   {
2784     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2785     AlignmentSorter.sortByEValue(viewport.getAlignment());
2786     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
2787             viewport.getAlignment()));
2788     alignPanel.paintAlignment(true, false);
2789
2790   }
2791
2792   public void sortBitScoreMenuItem_actionPerformed()
2793   {
2794     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2795     AlignmentSorter.sortByBitScore(viewport.getAlignment());
2796     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
2797             viewport.getAlignment()));
2798     alignPanel.paintAlignment(true, false);
2799
2800   }
2801
2802   public void removeRedundancyMenuItem_actionPerformed()
2803   {
2804     new RedundancyPanel(alignPanel);
2805   }
2806
2807   public void pairwiseAlignmentMenuItem_actionPerformed()
2808   {
2809     if (viewport.getSelectionGroup() != null
2810             && viewport.getSelectionGroup().getSize() > 1)
2811     {
2812       Frame frame = new Frame();
2813       frame.add(new PairwiseAlignPanel(alignPanel));
2814       jalview.bin.JalviewLite.addFrame(frame,
2815               MessageManager.getString("action.pairwise_alignment"), 600,
2816               500);
2817     }
2818   }
2819
2820   public void PCAMenuItem_actionPerformed()
2821   {
2822     // are the sequences aligned?
2823     if (!viewport.getAlignment().isAligned(false))
2824     {
2825       SequenceI current;
2826       int Width = viewport.getAlignment().getWidth();
2827
2828       for (int i = 0; i < viewport.getAlignment().getSequences()
2829               .size(); i++)
2830       {
2831         current = viewport.getAlignment().getSequenceAt(i);
2832
2833         if (current.getLength() < Width)
2834         {
2835           current.insertCharAt(Width - 1, viewport.getGapCharacter());
2836         }
2837       }
2838       alignPanel.paintAlignment(false, false);
2839     }
2840
2841     if ((viewport.getSelectionGroup() != null
2842             && viewport.getSelectionGroup().getSize() < 4
2843             && viewport.getSelectionGroup().getSize() > 0)
2844             || viewport.getAlignment().getHeight() < 4)
2845     {
2846       return;
2847     }
2848
2849     try
2850     {
2851       new PCAPanel(viewport);
2852     } catch (java.lang.OutOfMemoryError ex)
2853     {
2854     }
2855
2856   }
2857
2858   public void averageDistanceTreeMenuItem_actionPerformed()
2859   {
2860     newTreePanel(TreeBuilder.AVERAGE_DISTANCE, new PIDModel().getName(),
2861             "Average distance tree using PID");
2862   }
2863
2864   public void neighbourTreeMenuItem_actionPerformed()
2865   {
2866     newTreePanel(TreeBuilder.NEIGHBOUR_JOINING, new PIDModel().getName(),
2867             "Neighbour joining tree using PID");
2868   }
2869
2870   protected void njTreeBlosumMenuItem_actionPerformed()
2871   {
2872     newTreePanel(TreeBuilder.NEIGHBOUR_JOINING,
2873             ScoreModels.getInstance().getBlosum62().getName(),
2874             "Neighbour joining tree using BLOSUM62");
2875   }
2876
2877   protected void avTreeBlosumMenuItem_actionPerformed()
2878   {
2879     newTreePanel(TreeBuilder.AVERAGE_DISTANCE,
2880             ScoreModels.getInstance().getBlosum62().getName(),
2881             "Average distance tree using BLOSUM62");
2882   }
2883
2884   void newTreePanel(String type, String pwType, String title)
2885   {
2886     // are the sequences aligned?
2887     if (!viewport.getAlignment().isAligned(false))
2888     {
2889       SequenceI current;
2890       int Width = viewport.getAlignment().getWidth();
2891
2892       for (int i = 0; i < viewport.getAlignment().getSequences()
2893               .size(); i++)
2894       {
2895         current = viewport.getAlignment().getSequenceAt(i);
2896
2897         if (current.getLength() < Width)
2898         {
2899           current.insertCharAt(Width - 1, viewport.getGapCharacter());
2900         }
2901       }
2902       alignPanel.paintAlignment(false, false);
2903
2904     }
2905
2906     if ((viewport.getSelectionGroup() != null
2907             && viewport.getSelectionGroup().getSize() > 1)
2908             || (viewport.getAlignment().getHeight() > 1))
2909     {
2910       final TreePanel tp = new TreePanel(alignPanel, type, pwType);
2911
2912       addTreeMenuItem(tp, title);
2913
2914       jalview.bin.JalviewLite.addFrame(tp, title, 600, 500);
2915     }
2916   }
2917
2918   void loadTree_actionPerformed()
2919   {
2920     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, this);
2921     cap.setText(MessageManager.getString("label.paste_newick_tree_file"));
2922     cap.setTreeImport();
2923     Frame frame = new Frame();
2924     frame.add(cap);
2925     jalview.bin.JalviewLite.addFrame(frame,
2926             MessageManager.getString("label.paste_newick_file"), 400, 300);
2927   }
2928
2929   public void loadTree(jalview.io.NewickFile tree, String treeFile)
2930   {
2931     TreePanel tp = new TreePanel(alignPanel, treeFile,
2932             MessageManager.getString("label.load_tree_from_file"), tree);
2933     jalview.bin.JalviewLite.addFrame(tp, treeFile, 600, 500);
2934     addTreeMenuItem(tp, treeFile);
2935   }
2936
2937   /**
2938    * sort the alignment using the given treePanel
2939    * 
2940    * @param treePanel
2941    *          tree used to sort view
2942    * @param title
2943    *          string used for undo event name
2944    */
2945   public void sortByTree(TreePanel treePanel, String title)
2946   {
2947     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2948     AlignmentSorter.sortByTree(viewport.getAlignment(),
2949             treePanel.getTree());
2950     // addHistoryItem(new HistoryItem("Sort", viewport.alignment,
2951     // HistoryItem.SORT));
2952     addHistoryItem(new OrderCommand(MessageManager
2953             .formatMessage("label.order_by_params", new String[]
2954             { title }), oldOrder, viewport.getAlignment()));
2955     alignPanel.paintAlignment(true, false);
2956   }
2957
2958   /**
2959    * Do any automatic reordering of the alignment and add the necessary bits to
2960    * the menu structure for the new tree
2961    * 
2962    * @param treePanel
2963    * @param title
2964    */
2965   protected void addTreeMenuItem(final TreePanel treePanel,
2966           final String title)
2967   {
2968     final MenuItem item = new MenuItem(title);
2969     sortByTreeMenu.add(item);
2970     item.addActionListener(new java.awt.event.ActionListener()
2971     {
2972       @Override
2973       public void actionPerformed(ActionEvent evt)
2974       {
2975         sortByTree(treePanel, title); // treePanel.getTitle());
2976       }
2977     });
2978
2979     treePanel.addWindowListener(new WindowAdapter()
2980     {
2981       @Override
2982       public void windowOpened(WindowEvent e)
2983       {
2984         if (viewport.sortByTree)
2985         {
2986           sortByTree(treePanel, title);
2987         }
2988         super.windowOpened(e);
2989       }
2990
2991       @Override
2992       public void windowClosing(WindowEvent e)
2993       {
2994         sortByTreeMenu.remove(item);
2995       };
2996     });
2997   }
2998
2999   public boolean sortBy(AlignmentOrder alorder, String undoname)
3000   {
3001     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3002     if (viewport.applet.debug)
3003     {
3004       System.err.println("Sorting " + alorder.getOrder().size()
3005               + " in alignment '" + getTitle() + "'");
3006     }
3007     AlignmentSorter.sortBy(viewport.getAlignment(), alorder);
3008     if (undoname != null)
3009     {
3010       addHistoryItem(new OrderCommand(undoname, oldOrder,
3011               viewport.getAlignment()));
3012     }
3013     alignPanel.paintAlignment(true, false);
3014     return true;
3015   }
3016
3017   protected void documentation_actionPerformed()
3018   {
3019     alignPanel.av.applet.openJalviewHelpUrl();
3020   }
3021
3022   protected void about_actionPerformed()
3023   {
3024
3025     class AboutPanel extends Canvas
3026     {
3027       String version;
3028
3029       String builddate;
3030
3031       public AboutPanel(String version, String builddate)
3032       {
3033         this.version = version;
3034         this.builddate = builddate;
3035       }
3036
3037       @Override
3038       public void paint(Graphics g)
3039       {
3040         g.setColor(Color.white);
3041         g.fillRect(0, 0, getSize().width, getSize().height);
3042         g.setFont(new Font("Helvetica", Font.PLAIN, 12));
3043         FontMetrics fm = g.getFontMetrics();
3044         int fh = fm.getHeight();
3045         int y = 5, x = 7;
3046         g.setColor(Color.black);
3047         // TODO: update this text for each release or centrally store it for
3048         // lite and application
3049         g.setFont(new Font("Helvetica", Font.BOLD, 14));
3050         g.drawString(MessageManager
3051                 .formatMessage("label.jalviewLite_release", new String[]
3052                 { version }), x, y += fh);
3053         g.setFont(new Font("Helvetica", Font.BOLD, 12));
3054         g.drawString(MessageManager.formatMessage("label.jaview_build_date",
3055                 new String[]
3056                 { builddate }), x, y += fh);
3057         g.setFont(new Font("Helvetica", Font.PLAIN, 12));
3058         g.drawString(MessageManager.getString("label.jalview_authors_1"), x,
3059                 y += fh * 1.5);
3060         g.drawString(MessageManager.getString("label.jalview_authors_2"),
3061                 x + 50, y += fh + 8);
3062         g.drawString(MessageManager.getString("label.jalview_dev_managers"),
3063                 x, y += fh);
3064         g.drawString(MessageManager
3065                 .getString("label.jalview_distribution_lists"), x, y += fh);
3066         g.drawString(MessageManager.getString("label.jalview_please_cite"),
3067                 x, y += fh + 8);
3068         g.drawString(
3069                 MessageManager.getString("label.jalview_cite_1_authors"), x,
3070                 y += fh);
3071         g.drawString(MessageManager.getString("label.jalview_cite_1_title"),
3072                 x, y += fh);
3073         g.drawString(MessageManager.getString("label.jalview_cite_1_ref"),
3074                 x, y += fh);
3075       }
3076     }
3077
3078     Frame frame = new Frame();
3079     frame.add(new AboutPanel(JalviewLite.getVersion(),
3080             JalviewLite.getBuildDate()));
3081     jalview.bin.JalviewLite.addFrame(frame,
3082             MessageManager.getString("label.jalview"), 580, 220);
3083
3084   }
3085
3086   public void showURL(String url, String target)
3087   {
3088     if (viewport.applet == null)
3089     {
3090       System.out.println("Not running as applet - no browser available.");
3091     }
3092     else
3093     {
3094       viewport.applet.showURL(url, target);
3095     }
3096   }
3097
3098   // ////////////////////////////////////////////////////////////////////////////////
3099   // JBuilder Graphics here
3100
3101   MenuBar alignFrameMenuBar = new MenuBar();
3102
3103   Menu fileMenu = new Menu(MessageManager.getString("action.file"));
3104
3105   MenuItem loadApplication = new MenuItem(
3106           MessageManager.getString("label.view_full_application"));
3107
3108   MenuItem loadTree = new MenuItem(
3109           MessageManager.getString("label.load_associated_tree"));
3110
3111   MenuItem loadAnnotations = new MenuItem(
3112           MessageManager.getString("label.load_features_annotations"));
3113
3114   MenuItem outputFeatures = new MenuItem(
3115           MessageManager.getString("label.export_features"));
3116
3117   MenuItem outputAnnotations = new MenuItem(
3118           MessageManager.getString("label.export_annotations"));
3119
3120   MenuItem closeMenuItem = new MenuItem(
3121           MessageManager.getString("action.close"));
3122
3123   MenuItem selectAllSequenceMenuItem = new MenuItem(
3124           MessageManager.getString("action.select_all"));
3125
3126   MenuItem deselectAllSequenceMenuItem = new MenuItem(
3127           MessageManager.getString("action.deselect_all"));
3128
3129   MenuItem invertSequenceMenuItem = new MenuItem(
3130           MessageManager.getString("action.invert_selection"));
3131
3132   MenuItem remove2LeftMenuItem = new MenuItem();
3133
3134   MenuItem remove2RightMenuItem = new MenuItem();
3135
3136   MenuItem removeGappedColumnMenuItem = new MenuItem();
3137
3138   MenuItem removeAllGapsMenuItem = new MenuItem();
3139
3140   CheckboxMenuItem viewBoxesMenuItem = new CheckboxMenuItem();
3141
3142   CheckboxMenuItem viewTextMenuItem = new CheckboxMenuItem();
3143
3144   MenuItem sortPairwiseMenuItem = new MenuItem();
3145
3146   MenuItem sortIDMenuItem = new MenuItem();
3147
3148   MenuItem sortLengthMenuItem = new MenuItem();
3149
3150   MenuItem sortGroupMenuItem = new MenuItem();
3151
3152   MenuItem sortEValueMenuItem = new MenuItem();
3153
3154   MenuItem sortBitScoreMenuItem = new MenuItem();
3155
3156   MenuItem removeRedundancyMenuItem = new MenuItem();
3157
3158   MenuItem pairwiseAlignmentMenuItem = new MenuItem();
3159
3160   MenuItem PCAMenuItem = new MenuItem();
3161
3162   MenuItem averageDistanceTreeMenuItem = new MenuItem();
3163
3164   MenuItem neighbourTreeMenuItem = new MenuItem();
3165
3166   BorderLayout borderLayout1 = new BorderLayout();
3167
3168   public Label statusBar = new Label();
3169
3170   MenuItem clustalColour = new MenuItem();
3171
3172   MenuItem zappoColour = new MenuItem();
3173
3174   MenuItem taylorColour = new MenuItem();
3175
3176   MenuItem hydrophobicityColour = new MenuItem();
3177
3178   MenuItem helixColour = new MenuItem();
3179
3180   MenuItem strandColour = new MenuItem();
3181
3182   MenuItem turnColour = new MenuItem();
3183
3184   MenuItem buriedColour = new MenuItem();
3185
3186   MenuItem purinePyrimidineColour = new MenuItem();
3187
3188   // MenuItem RNAInteractionColour = new MenuItem();
3189
3190   MenuItem RNAHelixColour = new MenuItem();
3191
3192   MenuItem userDefinedColour = new MenuItem();
3193
3194   MenuItem PIDColour = new MenuItem();
3195
3196   MenuItem BLOSUM62Colour = new MenuItem();
3197
3198   MenuItem tcoffeeColour = new MenuItem();
3199
3200   MenuItem njTreeBlosumMenuItem = new MenuItem();
3201
3202   MenuItem avDistanceTreeBlosumMenuItem = new MenuItem();
3203
3204   CheckboxMenuItem annotationPanelMenuItem = new CheckboxMenuItem();
3205
3206   CheckboxMenuItem colourTextMenuItem = new CheckboxMenuItem();
3207
3208   CheckboxMenuItem displayNonconservedMenuItem = new CheckboxMenuItem();
3209
3210   MenuItem alProperties = new MenuItem(
3211           MessageManager.getString("label.alignment_props"));
3212
3213   MenuItem overviewMenuItem = new MenuItem();
3214
3215   MenuItem undoMenuItem = new MenuItem();
3216
3217   MenuItem redoMenuItem = new MenuItem();
3218
3219   CheckboxMenuItem conservationMenuItem = new CheckboxMenuItem();
3220
3221   MenuItem noColourmenuItem = new MenuItem();
3222
3223   CheckboxMenuItem wrapMenuItem = new CheckboxMenuItem();
3224
3225   CheckboxMenuItem renderGapsMenuItem = new CheckboxMenuItem();
3226
3227   MenuItem findMenuItem = new MenuItem();
3228
3229   CheckboxMenuItem abovePIDThreshold = new CheckboxMenuItem();
3230
3231   MenuItem nucleotideColour = new MenuItem();
3232
3233   MenuItem deleteGroups = new MenuItem();
3234
3235   MenuItem grpsFromSelection = new MenuItem();
3236
3237   MenuItem createGroup = new MenuItem();
3238
3239   MenuItem unGroup = new MenuItem();
3240
3241   MenuItem delete = new MenuItem();
3242
3243   MenuItem copy = new MenuItem();
3244
3245   MenuItem cut = new MenuItem();
3246
3247   Menu pasteMenu = new Menu();
3248
3249   MenuItem pasteNew = new MenuItem();
3250
3251   MenuItem pasteThis = new MenuItem();
3252
3253   CheckboxMenuItem applyToAllGroups = new CheckboxMenuItem();
3254
3255   MenuItem font = new MenuItem();
3256
3257   CheckboxMenuItem scaleAbove = new CheckboxMenuItem();
3258
3259   CheckboxMenuItem scaleLeft = new CheckboxMenuItem();
3260
3261   CheckboxMenuItem scaleRight = new CheckboxMenuItem();
3262
3263   MenuItem modifyPID = new MenuItem();
3264
3265   MenuItem modifyConservation = new MenuItem();
3266
3267   CheckboxMenuItem autoCalculate = null;
3268
3269   CheckboxMenuItem sortByTree = new CheckboxMenuItem(
3270           "Sort Alignment With New Tree", true);
3271
3272   Menu sortByTreeMenu = new Menu();
3273
3274   MenuItem inputText = new MenuItem();
3275
3276   MenuItem documentation = new MenuItem();
3277
3278   MenuItem about = new MenuItem();
3279
3280   CheckboxMenuItem seqLimits = new CheckboxMenuItem();
3281
3282   CheckboxMenuItem centreColumnLabelFlag = new CheckboxMenuItem();
3283
3284   CheckboxMenuItem followMouseOverFlag = new CheckboxMenuItem();
3285
3286   CheckboxMenuItem showSequenceLogo = new CheckboxMenuItem();
3287
3288   CheckboxMenuItem applyAutoAnnotationSettings = new CheckboxMenuItem();
3289
3290   CheckboxMenuItem showConsensusHistogram = new CheckboxMenuItem();
3291
3292   CheckboxMenuItem showGroupConsensus = new CheckboxMenuItem();
3293
3294   CheckboxMenuItem showGroupConservation = new CheckboxMenuItem();
3295
3296   CheckboxMenuItem normSequenceLogo = new CheckboxMenuItem();
3297
3298   /**
3299    * Initialise menus and other items
3300    * 
3301    * @throws Exception
3302    */
3303   private void jbInit() throws Exception
3304   {
3305     setMenuBar(alignFrameMenuBar);
3306
3307     /*
3308      * Configure File menu items and actions
3309      */
3310     inputText
3311             .setLabel(MessageManager.getString("label.input_from_textbox"));
3312     inputText.addActionListener(this);
3313     Menu outputTextboxMenu = new Menu(
3314             MessageManager.getString("label.out_to_textbox"));
3315     for (String ff : FileFormats.getInstance().getWritableFormats(true))
3316     {
3317       MenuItem item = new MenuItem(ff);
3318
3319       item.addActionListener(new java.awt.event.ActionListener()
3320       {
3321         @Override
3322         public void actionPerformed(ActionEvent e)
3323         {
3324           outputText_actionPerformed(e);
3325         }
3326       });
3327
3328       outputTextboxMenu.add(item);
3329     }
3330     closeMenuItem.addActionListener(this);
3331     loadApplication.addActionListener(this);
3332     loadTree.addActionListener(this);
3333     loadAnnotations.addActionListener(this);
3334     outputFeatures.addActionListener(this);
3335     outputAnnotations.addActionListener(this);
3336
3337     /*
3338      * Configure Edit menu items and actions
3339      */
3340     undoMenuItem.setEnabled(false);
3341     undoMenuItem.setLabel(MessageManager.getString("action.undo"));
3342     undoMenuItem.addActionListener(this);
3343     redoMenuItem.setEnabled(false);
3344     redoMenuItem.setLabel(MessageManager.getString("action.redo"));
3345     redoMenuItem.addActionListener(this);
3346     copy.setLabel(MessageManager.getString("action.copy"));
3347     copy.addActionListener(this);
3348     cut.setLabel(MessageManager.getString("action.cut"));
3349     cut.addActionListener(this);
3350     delete.setLabel(MessageManager.getString("action.delete"));
3351     delete.addActionListener(this);
3352     pasteMenu.setLabel(MessageManager.getString("action.paste"));
3353     pasteNew.setLabel(MessageManager.getString("label.to_new_alignment"));
3354     pasteNew.addActionListener(this);
3355     pasteThis.setLabel(MessageManager.getString("label.to_this_alignment"));
3356     pasteThis.addActionListener(this);
3357     remove2LeftMenuItem
3358             .setLabel(MessageManager.getString("action.remove_left"));
3359     remove2LeftMenuItem.addActionListener(this);
3360     remove2RightMenuItem
3361             .setLabel(MessageManager.getString("action.remove_right"));
3362     remove2RightMenuItem.addActionListener(this);
3363     removeGappedColumnMenuItem.setLabel(
3364             MessageManager.getString("action.remove_empty_columns"));
3365     removeGappedColumnMenuItem.addActionListener(this);
3366     removeAllGapsMenuItem
3367             .setLabel(MessageManager.getString("action.remove_all_gaps"));
3368     removeAllGapsMenuItem.addActionListener(this);
3369     removeRedundancyMenuItem
3370             .setLabel(MessageManager.getString("action.remove_redundancy"));
3371     removeRedundancyMenuItem.addActionListener(this);
3372
3373     /*
3374      * Configure Select menu items and actions
3375      */
3376     findMenuItem.setLabel(MessageManager.getString("action.find"));
3377     findMenuItem.addActionListener(this);
3378     selectAllSequenceMenuItem.addActionListener(this);
3379     deselectAllSequenceMenuItem.addActionListener(this);
3380     invertSequenceMenuItem.setLabel(
3381             MessageManager.getString("action.invert_sequence_selection"));
3382     invertSequenceMenuItem.addActionListener(this);
3383     invertColSel.setLabel(
3384             MessageManager.getString("action.invert_column_selection"));
3385     invertColSel.addActionListener(this);
3386     deleteGroups
3387             .setLabel(MessageManager.getString("action.undefine_groups"));
3388     deleteGroups.addActionListener(this);
3389     grpsFromSelection.setLabel(
3390             MessageManager.getString("action.make_groups_selection"));
3391     grpsFromSelection.addActionListener(this);
3392     createGroup.setLabel(MessageManager.getString("action.create_group"));
3393     createGroup.addActionListener(this);
3394     unGroup.setLabel(MessageManager.getString("action.remove_group"));
3395     unGroup.addActionListener(this);
3396
3397     annotationColumnSelection.setLabel(
3398             MessageManager.getString("action.select_by_annotation"));
3399     annotationColumnSelection.addActionListener(this);
3400
3401     /*
3402      * Configure View menu items and actions
3403      */
3404     newView.setLabel(MessageManager.getString("action.new_view"));
3405     newView.addActionListener(this);
3406     Menu showMenu = new Menu(MessageManager.getString("action.show"));
3407     showColumns.setLabel(MessageManager.getString("label.all_columns"));
3408     showSeqs.setLabel(MessageManager.getString("label.all_sequences"));
3409     Menu hideMenu = new Menu(MessageManager.getString("action.hide"));
3410     hideColumns
3411             .setLabel(MessageManager.getString("label.selected_columns"));
3412     hideSequences
3413             .setLabel(MessageManager.getString("label.selected_sequences"));
3414     hideAllButSelection.setLabel(
3415             MessageManager.getString("label.all_but_selected_region"));
3416     hideAllSelection
3417             .setLabel(MessageManager.getString("label.selected_region"));
3418     showAllHidden.setLabel(
3419             MessageManager.getString("label.all_sequences_columns"));
3420     showColumns.addActionListener(this);
3421     showSeqs.addActionListener(this);
3422     hideColumns.addActionListener(this);
3423     hideSequences.addActionListener(this);
3424     hideAllButSelection.addActionListener(this);
3425     hideAllSelection.addActionListener(this);
3426     showAllHidden.addActionListener(this);
3427     featureSettings
3428             .setLabel(MessageManager.getString("action.feature_settings"));
3429     featureSettings.addActionListener(this);
3430     sequenceFeatures.setLabel(
3431             MessageManager.getString("label.show_sequence_features"));
3432     sequenceFeatures.addItemListener(this);
3433     sequenceFeatures.setState(false);
3434     followMouseOverFlag.setLabel(
3435             MessageManager.getString("label.automatic_scrolling"));
3436     followMouseOverFlag.addItemListener(this);
3437     alProperties.addActionListener(this);
3438     overviewMenuItem
3439             .setLabel(MessageManager.getString("label.overview_window"));
3440     overviewMenuItem.addActionListener(this);
3441
3442     /*
3443      * Configure Annotations menu items and actions
3444      */
3445     annotationPanelMenuItem
3446             .setLabel(MessageManager.getString("label.show_annotations"));
3447     annotationPanelMenuItem.addItemListener(this);
3448     showGroupConsensus
3449             .setLabel(MessageManager.getString("label.group_consensus"));
3450     showGroupConservation
3451             .setLabel(MessageManager.getString("label.group_conservation"));
3452     showConsensusHistogram.setLabel(
3453             MessageManager.getString("label.show_consensus_histogram"));
3454     showSequenceLogo.setLabel(
3455             MessageManager.getString("label.show_consensus_logo"));
3456     normSequenceLogo.setLabel(
3457             MessageManager.getString("label.norm_consensus_logo"));
3458     applyAutoAnnotationSettings
3459             .setLabel(MessageManager.getString("label.apply_all_groups"));
3460     applyAutoAnnotationSettings.setState(true);
3461     Menu autoAnnMenu = new Menu(
3462             MessageManager.getString("label.autocalculated_annotation"));
3463     showGroupConsensus.addItemListener(this);
3464     showGroupConservation.addItemListener(this);
3465     showConsensusHistogram.addItemListener(this);
3466     showSequenceLogo.addItemListener(this);
3467     normSequenceLogo.addItemListener(this);
3468     applyAutoAnnotationSettings.addItemListener(this);
3469     showAlignmentAnnotations = new CheckboxMenuItem(
3470             MessageManager.getString("label.show_all_al_annotations"));
3471     showSequenceAnnotations = new CheckboxMenuItem(
3472             MessageManager.getString("label.show_all_seq_annotations"));
3473     sortAnnBySequence = new CheckboxMenuItem(
3474             MessageManager.getString("label.sort_annotations_by_sequence"));
3475     sortAnnByLabel = new CheckboxMenuItem(
3476             MessageManager.getString("label.sort_annotations_by_label"));
3477     showAutoFirst = new CheckboxMenuItem(
3478             MessageManager.getString("label.show_first"));
3479     showAutoFirst.setState(false); // pending applet parameter
3480     setShowAutoCalculatedAbove(showAutoFirst.getState());
3481     showAutoLast = new CheckboxMenuItem(
3482             MessageManager.getString("label.show_last"));
3483     showAutoLast.setState(!showAutoFirst.getState());
3484     showAlignmentAnnotations.addItemListener(this);
3485     showSequenceAnnotations.addItemListener(this);
3486     sortAnnBySequence.addItemListener(this);
3487     sortAnnByLabel.addItemListener(this);
3488     showAutoFirst.addItemListener(this);
3489     showAutoLast.addItemListener(this);
3490
3491     /*
3492      * Configure Format menu items and actions
3493      */
3494     font.setLabel(MessageManager.getString("action.font"));
3495     font.addActionListener(this);
3496     scaleAbove.setLabel(MessageManager.getString("action.scale_above"));
3497     scaleAbove.setState(true);
3498     scaleAbove.setEnabled(false);
3499     scaleAbove.addItemListener(this);
3500     scaleLeft.setEnabled(false);
3501     scaleLeft.setState(true);
3502     scaleLeft.setLabel(MessageManager.getString("action.scale_left"));
3503     scaleLeft.addItemListener(this);
3504     scaleRight.setEnabled(false);
3505     scaleRight.setState(true);
3506     scaleRight.setLabel(MessageManager.getString("action.scale_right"));
3507     scaleRight.addItemListener(this);
3508     viewBoxesMenuItem.setLabel(MessageManager.getString("action.boxes"));
3509     viewBoxesMenuItem.setState(true);
3510     viewBoxesMenuItem.addItemListener(this);
3511     viewTextMenuItem.setLabel(MessageManager.getString("action.text"));
3512     viewTextMenuItem.setState(true);
3513     viewTextMenuItem.addItemListener(this);
3514     colourTextMenuItem
3515             .setLabel(MessageManager.getString("label.colour_text"));
3516     colourTextMenuItem.addItemListener(this);
3517     displayNonconservedMenuItem
3518             .setLabel(MessageManager.getString("label.show_non_conserved"));
3519     displayNonconservedMenuItem.addItemListener(this);
3520     wrapMenuItem.setLabel(MessageManager.getString("action.wrap"));
3521     wrapMenuItem.addItemListener(this);
3522     renderGapsMenuItem
3523             .setLabel(MessageManager.getString("action.show_gaps"));
3524     renderGapsMenuItem.setState(true);
3525     renderGapsMenuItem.addItemListener(this);
3526     centreColumnLabelFlag.setLabel(
3527             MessageManager.getString("label.centre_column_labels"));
3528     centreColumnLabelFlag.addItemListener(this);
3529     seqLimits.setState(true);
3530     seqLimits.setLabel(
3531             MessageManager.getString("label.show_sequence_limits"));
3532     seqLimits.addItemListener(this);
3533
3534     /*
3535      * Configure Colour menu items and actions
3536      */
3537     applyToAllGroups.setLabel(
3538             MessageManager.getString("label.apply_colour_to_all_groups"));
3539     applyToAllGroups.setState(true);
3540     applyToAllGroups.addItemListener(this);
3541     clustalColour.setLabel(
3542             MessageManager.getString("label.colourScheme_clustal"));
3543     clustalColour.addActionListener(this);
3544     zappoColour
3545             .setLabel(MessageManager.getString("label.colourScheme_zappo"));
3546     zappoColour.addActionListener(this);
3547     taylorColour.setLabel(
3548             MessageManager.getString("label.colourScheme_taylor"));
3549     taylorColour.addActionListener(this);
3550     hydrophobicityColour.setLabel(
3551             MessageManager.getString("label.colourScheme_hydrophobic"));
3552     hydrophobicityColour.addActionListener(this);
3553     helixColour.setLabel(MessageManager
3554             .getString("label.colourScheme_helix_propensity"));
3555     helixColour.addActionListener(this);
3556     strandColour.setLabel(MessageManager
3557             .getString("label.colourScheme_strand_propensity"));
3558     strandColour.addActionListener(this);
3559     turnColour.setLabel(
3560             MessageManager.getString("label.colourScheme_turn_propensity"));
3561     turnColour.addActionListener(this);
3562     buriedColour.setLabel(
3563             MessageManager.getString("label.colourScheme_buried_index"));
3564     buriedColour.addActionListener(this);
3565     purinePyrimidineColour.setLabel(MessageManager
3566             .getString("label.colourScheme_purine/pyrimidine"));
3567     purinePyrimidineColour.addActionListener(this);
3568     // RNAInteractionColour.setLabel(MessageManager
3569     // .getString("label.rna_interaction"));
3570     // RNAInteractionColour.addActionListener(this);
3571     RNAHelixColour.setLabel(
3572             MessageManager.getString("label.colourScheme_rna_helices"));
3573     RNAHelixColour.addActionListener(this);
3574     userDefinedColour
3575             .setLabel(MessageManager.getString("action.user_defined"));
3576     userDefinedColour.addActionListener(this);
3577     PIDColour.setLabel(
3578             MessageManager.getString("label.colourScheme_%_identity"));
3579     PIDColour.addActionListener(this);
3580     BLOSUM62Colour.setLabel(
3581             MessageManager.getString("label.colourScheme_blosum62"));
3582     BLOSUM62Colour.addActionListener(this);
3583     tcoffeeColour.setLabel(
3584             MessageManager.getString("label.colourScheme_t-coffee_scores"));
3585     // it will be enabled only if a score file is provided
3586     tcoffeeColour.setEnabled(false);
3587     tcoffeeColour.addActionListener(this);
3588     conservationMenuItem
3589             .setLabel(MessageManager.getString("action.by_conservation"));
3590     conservationMenuItem.addItemListener(this);
3591     noColourmenuItem.setLabel(MessageManager.getString("label.none"));
3592     noColourmenuItem.addActionListener(this);
3593     abovePIDThreshold.setLabel(
3594             MessageManager.getString("label.above_identity_threshold"));
3595     abovePIDThreshold.addItemListener(this);
3596     nucleotideColour.setLabel(
3597             MessageManager.getString("label.colourScheme_nucleotide"));
3598     nucleotideColour.addActionListener(this);
3599     modifyPID.setLabel(
3600             MessageManager.getString("label.modify_identity_threshold"));
3601     modifyPID.setEnabled(abovePIDThreshold.getState());
3602     modifyPID.addActionListener(this);
3603     modifyConservation.setLabel(MessageManager
3604             .getString("label.modify_conservation_threshold"));
3605     modifyConservation.setEnabled(conservationMenuItem.getState());
3606     modifyConservation.addActionListener(this);
3607     annotationColour
3608             .setLabel(MessageManager.getString("action.by_annotation"));
3609     annotationColour.addActionListener(this);
3610
3611     /*
3612      * Configure Calculate menu items and actions
3613      */
3614     sortPairwiseMenuItem
3615             .setLabel(MessageManager.getString("action.by_pairwise_id"));
3616     sortPairwiseMenuItem.addActionListener(this);
3617     sortIDMenuItem.setLabel(MessageManager.getString("action.by_id"));
3618     sortIDMenuItem.addActionListener(this);
3619     sortLengthMenuItem
3620             .setLabel(MessageManager.getString("action.by_length"));
3621     sortLengthMenuItem.addActionListener(this);
3622     sortGroupMenuItem.setLabel(MessageManager.getString("action.by_group"));
3623     sortGroupMenuItem.addActionListener(this);
3624     pairwiseAlignmentMenuItem.setLabel(
3625             MessageManager.getString("action.pairwise_alignment"));
3626     pairwiseAlignmentMenuItem.addActionListener(this);
3627     PCAMenuItem.setLabel(
3628             MessageManager.getString("label.principal_component_analysis"));
3629     PCAMenuItem.addActionListener(this);
3630     autoCalculate = new CheckboxMenuItem(
3631             MessageManager.getString("label.autocalculate_consensus"),
3632             true);
3633     averageDistanceTreeMenuItem.setLabel(
3634             MessageManager.getString("label.average_distance_identity"));
3635     averageDistanceTreeMenuItem.addActionListener(this);
3636     neighbourTreeMenuItem.setLabel(
3637             MessageManager.getString("label.neighbour_joining_identity"));
3638     neighbourTreeMenuItem.addActionListener(this);
3639     avDistanceTreeBlosumMenuItem.setLabel(
3640             MessageManager.getString("label.average_distance_blosum62"));
3641     avDistanceTreeBlosumMenuItem.addActionListener(this);
3642     njTreeBlosumMenuItem
3643             .setLabel(MessageManager.getString("label.neighbour_blosum62"));
3644     njTreeBlosumMenuItem.addActionListener(this);
3645     sortByTreeMenu
3646             .setLabel(MessageManager.getString("action.by_tree_order"));
3647     Menu sortMenu = new Menu(MessageManager.getString("action.sort"));
3648     Menu calculateTreeMenu = new Menu(
3649             MessageManager.getString("action.calculate_tree"));
3650     autoCalculate.addItemListener(this);
3651     sortByTree.addItemListener(this);
3652
3653     /*
3654      * Configure Help menu items and actions
3655      */
3656     Menu helpMenu = new Menu(MessageManager.getString("action.help"));
3657     documentation.setLabel(MessageManager.getString("label.documentation"));
3658     documentation.addActionListener(this);
3659     about.setLabel(MessageManager.getString("label.about"));
3660     about.addActionListener(this);
3661
3662     /*
3663      * Add top level menus to frame
3664      */
3665     alignFrameMenuBar.add(fileMenu);
3666     Menu editMenu = new Menu(MessageManager.getString("action.edit"));
3667     alignFrameMenuBar.add(editMenu);
3668     Menu selectMenu = new Menu(MessageManager.getString("action.select"));
3669     alignFrameMenuBar.add(selectMenu);
3670     Menu viewMenu = new Menu(MessageManager.getString("action.view"));
3671     alignFrameMenuBar.add(viewMenu);
3672     Menu annotationsMenu = new Menu(
3673             MessageManager.getString("action.annotations"));
3674     alignFrameMenuBar.add(annotationsMenu);
3675     Menu formatMenu = new Menu(MessageManager.getString("action.format"));
3676     alignFrameMenuBar.add(formatMenu);
3677     Menu colourMenu = new Menu(MessageManager.getString("action.colour"));
3678     alignFrameMenuBar.add(colourMenu);
3679     Menu calculateMenu = new Menu(
3680             MessageManager.getString("action.calculate"));
3681     alignFrameMenuBar.add(calculateMenu);
3682     alignFrameMenuBar.add(helpMenu);
3683
3684     /*
3685      * File menu
3686      */
3687     fileMenu.add(inputText);
3688     fileMenu.add(loadTree);
3689     fileMenu.add(loadAnnotations);
3690     fileMenu.addSeparator();
3691     fileMenu.add(outputTextboxMenu);
3692     fileMenu.add(outputFeatures);
3693     fileMenu.add(outputAnnotations);
3694     if (jalviewServletURL != null)
3695     {
3696       fileMenu.add(loadApplication);
3697     }
3698     fileMenu.addSeparator();
3699     fileMenu.add(closeMenuItem);
3700
3701     /*
3702      * Edit menu
3703      */
3704     editMenu.add(undoMenuItem);
3705     editMenu.add(redoMenuItem);
3706     editMenu.add(cut);
3707     editMenu.add(copy);
3708     pasteMenu.add(pasteNew);
3709     pasteMenu.add(pasteThis);
3710     editMenu.add(pasteMenu);
3711     editMenu.add(delete);
3712     editMenu.addSeparator();
3713     editMenu.add(remove2LeftMenuItem);
3714     editMenu.add(remove2RightMenuItem);
3715     editMenu.add(removeGappedColumnMenuItem);
3716     editMenu.add(removeAllGapsMenuItem);
3717     editMenu.add(removeRedundancyMenuItem);
3718
3719     /*
3720      * Select menu
3721      */
3722     selectMenu.add(findMenuItem);
3723     selectMenu.addSeparator();
3724     selectMenu.add(selectAllSequenceMenuItem);
3725     selectMenu.add(deselectAllSequenceMenuItem);
3726     selectMenu.add(invertSequenceMenuItem);
3727     selectMenu.add(invertColSel);
3728     selectMenu.add(createGroup);
3729     selectMenu.add(unGroup);
3730     selectMenu.add(grpsFromSelection);
3731     selectMenu.add(deleteGroups);
3732     selectMenu.add(annotationColumnSelection);
3733
3734     /*
3735      * View menu
3736      */
3737     viewMenu.add(newView);
3738     viewMenu.addSeparator();
3739     showMenu.add(showColumns);
3740     showMenu.add(showSeqs);
3741     showMenu.add(showAllHidden);
3742     viewMenu.add(showMenu);
3743     hideMenu.add(hideColumns);
3744     hideMenu.add(hideSequences);
3745     hideMenu.add(hideAllSelection);
3746     hideMenu.add(hideAllButSelection);
3747     viewMenu.add(hideMenu);
3748     viewMenu.addSeparator();
3749     viewMenu.add(followMouseOverFlag);
3750     viewMenu.addSeparator();
3751     viewMenu.add(sequenceFeatures);
3752     viewMenu.add(featureSettings);
3753     viewMenu.addSeparator();
3754     viewMenu.add(alProperties);
3755     viewMenu.addSeparator();
3756     viewMenu.add(overviewMenuItem);
3757
3758     /*
3759      * Annotations menu
3760      */
3761     annotationsMenu.add(annotationPanelMenuItem);
3762     annotationsMenu.addSeparator();
3763     annotationsMenu.add(showAlignmentAnnotations);
3764     annotationsMenu.add(showSequenceAnnotations);
3765     annotationsMenu.add(sortAnnBySequence);
3766     annotationsMenu.add(sortAnnByLabel);
3767     annotationsMenu.addSeparator();
3768     autoAnnMenu.add(showAutoFirst);
3769     autoAnnMenu.add(showAutoLast);
3770     autoAnnMenu.addSeparator();
3771     autoAnnMenu.add(applyAutoAnnotationSettings);
3772     autoAnnMenu.add(showConsensusHistogram);
3773     autoAnnMenu.add(showSequenceLogo);
3774     autoAnnMenu.add(normSequenceLogo);
3775     autoAnnMenu.addSeparator();
3776     autoAnnMenu.add(showGroupConservation);
3777     autoAnnMenu.add(showGroupConsensus);
3778     annotationsMenu.add(autoAnnMenu);
3779
3780     /*
3781      * Format menu
3782      */
3783     formatMenu.add(font);
3784     formatMenu.add(seqLimits);
3785     formatMenu.add(wrapMenuItem);
3786     formatMenu.add(scaleAbove);
3787     formatMenu.add(scaleLeft);
3788     formatMenu.add(scaleRight);
3789     formatMenu.add(viewBoxesMenuItem);
3790     formatMenu.add(viewTextMenuItem);
3791     formatMenu.add(colourTextMenuItem);
3792     formatMenu.add(displayNonconservedMenuItem);
3793     formatMenu.add(renderGapsMenuItem);
3794     formatMenu.add(centreColumnLabelFlag);
3795
3796     /*
3797      * Colour menu
3798      */
3799     colourMenu.add(applyToAllGroups);
3800     colourMenu.addSeparator();
3801     colourMenu.add(noColourmenuItem);
3802     colourMenu.add(clustalColour);
3803     colourMenu.add(BLOSUM62Colour);
3804     colourMenu.add(PIDColour);
3805     colourMenu.add(zappoColour);
3806     colourMenu.add(taylorColour);
3807     colourMenu.add(hydrophobicityColour);
3808     colourMenu.add(helixColour);
3809     colourMenu.add(strandColour);
3810     colourMenu.add(turnColour);
3811     colourMenu.add(buriedColour);
3812     colourMenu.add(nucleotideColour);
3813     colourMenu.add(purinePyrimidineColour);
3814     // colourMenu.add(RNAInteractionColour);
3815     colourMenu.add(tcoffeeColour);
3816     colourMenu.add(userDefinedColour);
3817     colourMenu.addSeparator();
3818     colourMenu.add(conservationMenuItem);
3819     colourMenu.add(modifyConservation);
3820     colourMenu.add(abovePIDThreshold);
3821     colourMenu.add(modifyPID);
3822     colourMenu.add(annotationColour);
3823     colourMenu.add(RNAHelixColour);
3824
3825     /*
3826      * Calculate menu
3827      */
3828     sortMenu.add(sortIDMenuItem);
3829     sortMenu.add(sortLengthMenuItem);
3830     sortMenu.add(sortByTreeMenu);
3831     sortMenu.add(sortGroupMenuItem);
3832     sortMenu.add(sortPairwiseMenuItem);
3833     calculateMenu.add(sortMenu);
3834     calculateTreeMenu.add(averageDistanceTreeMenuItem);
3835     calculateTreeMenu.add(neighbourTreeMenuItem);
3836     calculateTreeMenu.add(avDistanceTreeBlosumMenuItem);
3837     calculateTreeMenu.add(njTreeBlosumMenuItem);
3838     calculateMenu.add(calculateTreeMenu);
3839     calculateMenu.addSeparator();
3840     calculateMenu.add(pairwiseAlignmentMenuItem);
3841     calculateMenu.add(PCAMenuItem);
3842     calculateMenu.add(autoCalculate);
3843     calculateMenu.add(sortByTree);
3844
3845     /*
3846      * Help menu
3847      */
3848     helpMenu.add(documentation);
3849     helpMenu.add(about);
3850
3851     /*
3852      * Status bar
3853      */
3854     statusBar.setBackground(Color.white);
3855     statusBar.setFont(new java.awt.Font("Verdana", 0, 11));
3856     setStatus(MessageManager.getString("label.status_bar"));
3857     this.add(statusBar, BorderLayout.SOUTH);
3858   }
3859
3860   @Override
3861   public void setStatus(String string)
3862   {
3863     statusBar.setText(string);
3864   };
3865
3866   MenuItem featureSettings = new MenuItem();
3867
3868   CheckboxMenuItem sequenceFeatures = new CheckboxMenuItem();
3869
3870   MenuItem annotationColour = new MenuItem();
3871
3872   MenuItem annotationColumnSelection = new MenuItem();
3873
3874   MenuItem invertColSel = new MenuItem();
3875
3876   MenuItem showColumns = new MenuItem();
3877
3878   MenuItem showSeqs = new MenuItem();
3879
3880   MenuItem hideColumns = new MenuItem();
3881
3882   MenuItem hideSequences = new MenuItem();
3883
3884   MenuItem hideAllButSelection = new MenuItem();
3885
3886   MenuItem hideAllSelection = new MenuItem();
3887
3888   MenuItem showAllHidden = new MenuItem();
3889
3890   MenuItem newView = new MenuItem();
3891
3892   private CheckboxMenuItem showAlignmentAnnotations;
3893
3894   private CheckboxMenuItem showSequenceAnnotations;
3895
3896   private CheckboxMenuItem sortAnnBySequence;
3897
3898   private CheckboxMenuItem sortAnnByLabel;
3899
3900   private CheckboxMenuItem showAutoFirst;
3901
3902   private CheckboxMenuItem showAutoLast;
3903
3904   private SplitFrame splitFrame;
3905
3906   /**
3907    * Attach the alignFrame panels after embedding menus, if necessary. This used
3908    * to be called setEmbedded, but is now creates the dropdown menus in a
3909    * platform independent manner to avoid OSX/Mac menu appendage daftness.
3910    * 
3911    * @param reallyEmbedded
3912    *          true to attach the view to the applet area on the page rather than
3913    *          in a new window
3914    */
3915   public void createAlignFrameWindow(boolean reallyEmbedded)
3916   {
3917     if (reallyEmbedded)
3918     {
3919       embedAlignFrameInApplet(viewport.applet);
3920     }
3921     else
3922     {
3923       // //////
3924       // test and embed menu bar if necessary.
3925       //
3926       if (embedMenuIfNeeded(alignPanel))
3927       {
3928         /*
3929          * adjust for status bar height too. ? pointless as overridden by layout
3930          * manager
3931          */
3932         alignPanel.setSize(getSize().width,
3933                 getSize().height - statusBar.getHeight());
3934       }
3935       add(statusBar, BorderLayout.SOUTH);
3936       add(alignPanel, BorderLayout.CENTER);
3937       // and register with the applet so it can pass external API calls to us
3938       jalview.bin.JalviewLite.addFrame(this, this.getTitle(), frameWidth,
3939               frameHeight);
3940     }
3941   }
3942
3943   /**
3944    * Add the components of this AlignFrame to the applet container.
3945    * 
3946    * @param theApplet
3947    */
3948   public void embedAlignFrameInApplet(final JalviewLite theApplet)
3949   {
3950     // ////
3951     // Explicitly build the embedded menu panel for the on-page applet
3952     //
3953     // view cannot be closed if its actually on the page
3954     fileMenu.remove(closeMenuItem);
3955     fileMenu.remove(3); // Remove Separator
3956     // construct embedded menu, using default font
3957     embeddedMenu = makeEmbeddedPopupMenu(alignFrameMenuBar, false, false);
3958     // and actually add the components to the applet area
3959     theApplet.setLayout(new BorderLayout());
3960     theApplet.add(embeddedMenu, BorderLayout.NORTH);
3961     theApplet.add(statusBar, BorderLayout.SOUTH);
3962     // TODO should size be left to the layout manager?
3963     alignPanel.setSize(theApplet.getSize().width, theApplet.getSize().height
3964             - embeddedMenu.getHeight() - statusBar.getHeight());
3965     theApplet.add(alignPanel, BorderLayout.CENTER);
3966     final AlignFrame me = this;
3967     theApplet.addFocusListener(new FocusListener()
3968     {
3969
3970       @Override
3971       public void focusLost(FocusEvent e)
3972       {
3973         if (theApplet.currentAlignFrame == me)
3974         {
3975           theApplet.currentAlignFrame = null;
3976         }
3977       }
3978
3979       @Override
3980       public void focusGained(FocusEvent e)
3981       {
3982         theApplet.currentAlignFrame = me;
3983       }
3984     });
3985     theApplet.validate();
3986   }
3987
3988   /**
3989    * create a new binding between structures in an existing jmol viewer instance
3990    * and an alignpanel with sequences that have existing PDBFile entries. Note,
3991    * this does not open a new Jmol window, or modify the display of the
3992    * structures in the original jmol window. Note This method doesn't work
3993    * without an additional javascript library to exchange messages between the
3994    * distinct applets. See http://issues.jalview.org/browse/JAL-621
3995    * 
3996    * @param viewer
3997    *          JmolViewer instance
3998    * @param sequenceIds
3999    *          - sequence Ids to search for associations
4000    */
4001   public SequenceStructureBinding addStructureViewInstance(
4002           Object jmolviewer, String[] sequenceIds)
4003   {
4004     Viewer viewer = null;
4005     try
4006     {
4007       viewer = (Viewer) jmolviewer;
4008     } catch (ClassCastException ex)
4009     {
4010       System.err.println(
4011               "Unsupported viewer object :" + jmolviewer.getClass());
4012     }
4013     if (viewer == null)
4014     {
4015       System.err.println("Can't use this object as a structure viewer:"
4016               + jmolviewer.getClass());
4017       return null;
4018     }
4019     SequenceI[] seqs = null;
4020     if (sequenceIds == null || sequenceIds.length == 0)
4021     {
4022       seqs = viewport.getAlignment().getSequencesArray();
4023     }
4024     else
4025     {
4026       Vector sqi = new Vector();
4027       AlignmentI al = viewport.getAlignment();
4028       for (int sid = 0; sid < sequenceIds.length; sid++)
4029       {
4030         SequenceI sq = al.findName(sequenceIds[sid]);
4031         if (sq != null)
4032         {
4033           sqi.addElement(sq);
4034         }
4035       }
4036       if (sqi.size() > 0)
4037       {
4038         seqs = new SequenceI[sqi.size()];
4039         for (int sid = 0, sSize = sqi.size(); sid < sSize; sid++)
4040         {
4041           seqs[sid] = (SequenceI) sqi.elementAt(sid);
4042         }
4043       }
4044       else
4045       {
4046         return null;
4047       }
4048     }
4049     AAStructureBindingModel jmv = null;
4050     // TODO: search for a jmv that involves viewer
4051     if (jmv == null)
4052     { // create a new viewer/jalview binding.
4053       jmv = new ExtJmol(viewer, alignPanel, new SequenceI[][] { seqs });
4054     }
4055     return jmv;
4056
4057   }
4058
4059   /**
4060    * bind a pdb file to a sequence in the current view
4061    * 
4062    * @param sequenceId
4063    *          - sequenceId within the dataset.
4064    * @param pdbEntryString
4065    *          - the short name for the PDB file
4066    * @param pdbFile
4067    *          - pdb file - either a URL or a valid PDB file.
4068    * @return true if binding was as success TODO: consider making an exception
4069    *         structure for indicating when PDB parsing or sequenceId location
4070    *         fails.
4071    */
4072   public boolean addPdbFile(String sequenceId, String pdbEntryString,
4073           String pdbFile)
4074   {
4075     SequenceI toaddpdb = viewport.getAlignment().findName(sequenceId);
4076     boolean needtoadd = false;
4077     if (toaddpdb != null)
4078     {
4079       Vector pdbe = toaddpdb.getAllPDBEntries();
4080       PDBEntry pdbentry = null;
4081       if (pdbe != null && pdbe.size() > 0)
4082       {
4083         for (int pe = 0, peSize = pdbe.size(); pe < peSize; pe++)
4084         {
4085           pdbentry = (PDBEntry) pdbe.elementAt(pe);
4086           if (!pdbentry.getId().equals(pdbEntryString)
4087                   && !pdbentry.getFile().equals(pdbFile))
4088           {
4089             pdbentry = null;
4090           }
4091           else
4092           {
4093             continue;
4094           }
4095         }
4096       }
4097       if (pdbentry == null)
4098       {
4099         pdbentry = new PDBEntry();
4100         pdbentry.setId(pdbEntryString);
4101         pdbentry.setFile(pdbFile);
4102         needtoadd = true; // add this new entry to sequence.
4103       }
4104       // resolve data source
4105       // TODO: this code should be a refactored to an io package
4106       DataSourceType protocol = AppletFormatAdapter.resolveProtocol(pdbFile,
4107               FileFormat.PDB);
4108       if (protocol == null)
4109       {
4110         return false;
4111       }
4112       if (needtoadd)
4113       {
4114         pdbentry.setProperty("protocol", protocol);
4115         toaddpdb.addPDBId(pdbentry);
4116         alignPanel.getStructureSelectionManager()
4117                 .registerPDBEntry(pdbentry);
4118       }
4119     }
4120     return true;
4121   }
4122
4123   private Object[] cleanSeqChainArrays(SequenceI[] seqs, String[] chains)
4124   {
4125     if (seqs != null)
4126     {
4127       Vector sequences = new Vector();
4128       for (int i = 0; i < seqs.length; i++)
4129       {
4130         if (seqs[i] != null)
4131         {
4132           sequences
4133                   .addElement(new Object[]
4134                   { seqs[i], (chains != null) ? chains[i] : null });
4135         }
4136       }
4137       seqs = new SequenceI[sequences.size()];
4138       chains = new String[sequences.size()];
4139       for (int i = 0, isize = sequences.size(); i < isize; i++)
4140       {
4141         Object[] oj = (Object[]) sequences.elementAt(i);
4142
4143         seqs[i] = (SequenceI) oj[0];
4144         chains[i] = (String) oj[1];
4145       }
4146     }
4147     return new Object[] { seqs, chains };
4148
4149   }
4150
4151   public void newStructureView(JalviewLite applet, PDBEntry pdb,
4152           SequenceI[] seqs, String[] chains, DataSourceType protocol)
4153   {
4154     // Scrub any null sequences from the array
4155     Object[] sqch = cleanSeqChainArrays(seqs, chains);
4156     seqs = (SequenceI[]) sqch[0];
4157     chains = (String[]) sqch[1];
4158     if (seqs == null || seqs.length == 0)
4159     {
4160       System.err.println(
4161               "JalviewLite.AlignFrame:newStructureView: No sequence to bind structure to.");
4162     }
4163     if (protocol == null)
4164     {
4165       String sourceType = (String) pdb.getProperty("protocol");
4166       try
4167       {
4168         protocol = DataSourceType.valueOf(sourceType);
4169       } catch (IllegalArgumentException e)
4170       {
4171         // ignore
4172       }
4173       if (protocol == null)
4174       {
4175         System.err.println("Couldn't work out protocol to open structure: "
4176                 + pdb.getId());
4177         return;
4178       }
4179     }
4180     if (applet.useXtrnalSviewer)
4181     {
4182       // register the association(s) and quit, don't create any windows.
4183       if (StructureSelectionManager.getStructureSelectionManager(applet)
4184               .setMapping(seqs, chains, pdb.getFile(), protocol, null) == null)
4185       {
4186         System.err.println("Failed to map " + pdb.getFile() + " ("
4187                 + protocol + ") to any sequences");
4188       }
4189       return;
4190     }
4191     if (applet.isAlignPdbStructures() && applet.jmolAvailable)
4192     {
4193       // can only do alignments with Jmol
4194       // find the last jmol window assigned to this alignment
4195       AppletJmol ajm = null, tajm;
4196       Vector jmols = applet.getAppletWindow(AppletJmol.class);
4197       for (int i = 0, iSize = jmols.size(); i < iSize; i++)
4198       {
4199         tajm = (AppletJmol) jmols.elementAt(i);
4200         if (tajm.ap.alignFrame == this)
4201         {
4202           ajm = tajm;
4203           break;
4204         }
4205       }
4206       if (ajm != null)
4207       {
4208         System.err.println(
4209                 "Incremental adding and aligning structure to existing Jmol view not yet implemented.");
4210         // try and add the pdb structure
4211         // ajm.addS
4212         ajm = null;
4213       }
4214     }
4215     // otherwise, create a new window
4216     if (applet.jmolAvailable)
4217     {
4218       new AppletJmol(pdb, seqs, chains, alignPanel, protocol);
4219       applet.lastFrameX += 40;
4220       applet.lastFrameY += 40;
4221     }
4222     else
4223     {
4224       new mc_view.AppletPDBViewer(pdb, seqs, chains, alignPanel, protocol);
4225     }
4226
4227   }
4228
4229   public void alignedStructureView(JalviewLite applet, PDBEntry[] pdb,
4230           SequenceI[][] seqs, String[][] chains, String[] protocols)
4231   {
4232     // TODO Auto-generated method stub
4233     System.err.println("Aligned Structure View: Not yet implemented.");
4234   }
4235
4236   /**
4237    * modify the current selection, providing the user has not made a selection
4238    * already.
4239    * 
4240    * @param sel
4241    *          - sequences from this alignment
4242    * @param csel
4243    *          - columns to be selected on the alignment
4244    */
4245   public void select(SequenceGroup sel, ColumnSelection csel,
4246           HiddenColumns hidden)
4247   {
4248     alignPanel.seqPanel.selection(sel, csel, hidden, null);
4249   }
4250
4251   public void scrollTo(int row, int column)
4252   {
4253     alignPanel.seqPanel.scrollTo(row, column);
4254   }
4255
4256   public void scrollToRow(int row)
4257   {
4258     alignPanel.seqPanel.scrollToRow(row);
4259   }
4260
4261   public void scrollToColumn(int column)
4262   {
4263     alignPanel.seqPanel.scrollToColumn(column);
4264   }
4265
4266   /**
4267    * @return the alignments unique ID.
4268    */
4269   public String getSequenceSetId()
4270   {
4271     return viewport.getSequenceSetId();
4272   }
4273
4274   /**
4275    * Load the (T-Coffee) score file from the specified url
4276    * 
4277    * @param source
4278    *          File/URL/T-COFFEE score file contents
4279    * @throws IOException
4280    * @return true if alignment was annotated with data from source
4281    */
4282   public boolean loadScoreFile(String source) throws IOException
4283   {
4284
4285     TCoffeeScoreFile file = new TCoffeeScoreFile(source,
4286             AppletFormatAdapter.checkProtocol(source));
4287     if (!file.isValid())
4288     {
4289       // TODO: raise dialog for gui
4290       System.err.println("Problems parsing T-Coffee scores: "
4291               + file.getWarningMessage());
4292       System.err.println("Origin was:\n" + source);
4293       return false;
4294     }
4295
4296     /*
4297      * check that the score matrix matches the alignment dimensions
4298      */
4299     AlignmentI aln;
4300     if ((aln = viewport.getAlignment()) != null
4301             && (aln.getHeight() != file.getHeight()
4302                     || aln.getWidth() != file.getWidth()))
4303     {
4304       // TODO: raise a dialog box here rather than bomb out.
4305       System.err.println(
4306               "The scores matrix does not match the alignment dimensions");
4307
4308     }
4309
4310     // TODO add parameter to indicate if matching should be done
4311     if (file.annotateAlignment(alignPanel.getAlignment(), false))
4312     {
4313       alignPanel.fontChanged();
4314       tcoffeeColour.setEnabled(true);
4315       // switch to this color
4316       changeColour(new TCoffeeColourScheme(alignPanel.getAlignment()));
4317       return true;
4318     }
4319     else
4320     {
4321       System.err.println("Problems resolving T-Coffee scores:");
4322       if (file.getWarningMessage() != null)
4323       {
4324         System.err.println(file.getWarningMessage());
4325       }
4326     }
4327     return false;
4328   }
4329
4330   public SplitFrame getSplitFrame()
4331   {
4332     return this.splitFrame;
4333   }
4334
4335   public void setSplitFrame(SplitFrame sf)
4336   {
4337     this.splitFrame = sf;
4338   }
4339
4340   // may not need this
4341   @Override
4342   public void setShowSeqFeatures(boolean b)
4343   {
4344     // showSeqFeatures.setSelected(b);
4345     viewport.setShowSequenceFeatures(b);
4346
4347   }
4348
4349   @Override
4350   public void setMenusForViewport()
4351   {
4352     // setMenusFromViewport(viewport);
4353
4354   }
4355
4356   @Override
4357   public void refreshFeatureUI(boolean enableIfNecessary)
4358   {
4359     if (enableIfNecessary)
4360     {
4361       sequenceFeatures.setState(true);
4362       alignPanel.av.setShowSequenceFeatures(true);
4363     }
4364   }
4365
4366   @Override
4367   public FeatureSettingsControllerI getFeatureSettingsUI()
4368   {
4369     return alignPanel.av.featureSettings;
4370   }
4371
4372   @Override
4373   public FeatureSettingsControllerI showFeatureSettingsUI()
4374   {
4375     return new FeatureSettings(alignPanel);
4376   }
4377
4378   private Rectangle fs_bounds = null;
4379
4380   @Override
4381   public void setFeatureSettingsGeometry(Rectangle bounds)
4382   {
4383     fs_bounds = bounds;
4384   }
4385
4386   @Override
4387   public Rectangle getFeatureSettingsGeometry()
4388   {
4389     return fs_bounds;
4390   }
4391
4392 }