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