0d1fd35ef876ad41da9936cfd6199e986071b5f5
[jalview.git] / src / jalview / appletgui / AlignFrame.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.appletgui;
22
23 import jalview.analysis.AlignmentSorter;
24 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
25 import jalview.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.FlowLayout;
79 import java.awt.Font;
80 import java.awt.FontMetrics;
81 import java.awt.Frame;
82 import java.awt.Graphics;
83 import java.awt.Label;
84 import java.awt.Menu;
85 import java.awt.MenuBar;
86 import java.awt.MenuItem;
87 import java.awt.Panel;
88 import java.awt.event.ActionEvent;
89 import java.awt.event.ActionListener;
90 import java.awt.event.FocusEvent;
91 import java.awt.event.FocusListener;
92 import java.awt.event.ItemEvent;
93 import java.awt.event.ItemListener;
94 import java.awt.event.KeyEvent;
95 import java.awt.event.KeyListener;
96 import java.awt.event.WindowAdapter;
97 import java.awt.event.WindowEvent;
98 import java.io.IOException;
99 import java.net.URL;
100 import java.net.URLEncoder;
101 import java.util.Arrays;
102 import java.util.Deque;
103 import java.util.HashMap;
104 import java.util.Hashtable;
105 import java.util.List;
106 import java.util.Map;
107 import java.util.StringTokenizer;
108 import java.util.Vector;
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      */
2069     if (sg.getSize() == viewport.getAlignment().getHeight())
2070     {
2071       boolean isEntireAlignWidth = (((sg.getEndRes() - sg.getStartRes()) + 1) == viewport
2072               .getAlignment().getWidth()) ? true : false;
2073       if (isEntireAlignWidth)
2074       {
2075
2076         String title = MessageManager.getString("label.delete_all");
2077         Panel mp = new Panel();
2078         mp.setLayout(new FlowLayout());
2079         mp.add(new Label(MessageManager.getString("warn.delete_all")));
2080
2081         final JVDialog dialog = new JVDialog(this, title, true, 400,
2082                 200);
2083         dialog.setMainPanel(mp);
2084         dialog.setVisible(true);
2085
2086         if (!dialog.accept)
2087         {
2088           return;
2089         }
2090       }
2091       viewport.getColumnSelection().removeElements(sg.getStartRes(),
2092               sg.getEndRes() + 1);
2093     }
2094
2095     SequenceI[] cut = new SequenceI[seqs.size()];
2096     for (int i = 0; i < seqs.size(); i++)
2097     {
2098       cut[i] = (SequenceI) seqs.elementAt(i);
2099     }
2100
2101     /*
2102      * //ADD HISTORY ITEM
2103      */
2104     addHistoryItem(new EditCommand(
2105             MessageManager.getString("label.cut_sequences"), Action.CUT,
2106             cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
2107             viewport.getAlignment()));
2108
2109     viewport.setSelectionGroup(null);
2110     viewport.getAlignment().deleteGroup(sg);
2111
2112     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2113             .getSequences());
2114
2115     if (viewport.getAlignment().getHeight() < 1)
2116     {
2117       this.setVisible(false);
2118     }
2119     viewport.sendSelection();
2120   }
2121
2122   /**
2123    * group consensus toggled
2124    * 
2125    */
2126   protected void showGroupConsensus_actionPerformed()
2127   {
2128     viewport.setShowGroupConsensus(showGroupConsensus.getState());
2129     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2130
2131   }
2132
2133   /**
2134    * group conservation toggled.
2135    */
2136   protected void showGroupConservation_actionPerformed()
2137   {
2138     viewport.setShowGroupConservation(showGroupConservation.getState());
2139     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2140   }
2141
2142   /*
2143    * (non-Javadoc)
2144    * 
2145    * @see
2146    * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt
2147    * .event.ActionEvent)
2148    */
2149   protected void showConsensusHistogram_actionPerformed()
2150   {
2151     viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
2152     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2153   }
2154
2155   /*
2156    * (non-Javadoc)
2157    * 
2158    * @see
2159    * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt
2160    * .event.ActionEvent)
2161    */
2162   protected void showSequenceLogo_actionPerformed()
2163   {
2164     viewport.setShowSequenceLogo(showSequenceLogo.getState());
2165     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2166   }
2167
2168   protected void normSequenceLogo_actionPerformed()
2169   {
2170     showSequenceLogo.setState(true);
2171     viewport.setShowSequenceLogo(true);
2172     viewport.setNormaliseSequenceLogo(normSequenceLogo.getState());
2173     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2174   }
2175
2176   protected void applyAutoAnnotationSettings_actionPerformed()
2177   {
2178     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
2179   }
2180
2181   protected void makeGrpsFromSelection_actionPerformed()
2182   {
2183     if (avc.makeGroupsFromSelection())
2184     {
2185       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
2186       alignPanel.updateAnnotation();
2187       alignPanel.paintAlignment(true);
2188     }
2189   }
2190
2191   protected void createGroup_actionPerformed()
2192   {
2193     avc.createGroup();
2194   }
2195
2196   protected void unGroup_actionPerformed()
2197   {
2198     if (avc.unGroup())
2199     {
2200       alignPanel.alignmentChanged();
2201     }
2202   }
2203
2204   protected void deleteGroups_actionPerformed()
2205   {
2206     if (avc.deleteGroups())
2207     {
2208       alignPanel.alignmentChanged();
2209     }
2210   }
2211
2212   public void selectAllSequenceMenuItem_actionPerformed()
2213   {
2214     SequenceGroup sg = new SequenceGroup();
2215     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2216     {
2217       sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
2218     }
2219     sg.setEndRes(viewport.getAlignment().getWidth() - 1);
2220     viewport.setSelectionGroup(sg);
2221     alignPanel.paintAlignment(true);
2222     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2223     viewport.sendSelection();
2224   }
2225
2226   public void deselectAllSequenceMenuItem_actionPerformed()
2227   {
2228     if (viewport.cursorMode)
2229     {
2230       alignPanel.seqPanel.keyboardNo1 = null;
2231       alignPanel.seqPanel.keyboardNo2 = null;
2232     }
2233     viewport.setSelectionGroup(null);
2234     viewport.getColumnSelection().clear();
2235     viewport.setSelectionGroup(null);
2236     alignPanel.idPanel.idCanvas.searchResults = null;
2237     alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);
2238     alignPanel.paintAlignment(true);
2239     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2240     viewport.sendSelection();
2241   }
2242
2243   public void invertSequenceMenuItem_actionPerformed()
2244   {
2245     SequenceGroup sg = viewport.getSelectionGroup();
2246     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2247     {
2248       sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
2249     }
2250
2251     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2252     viewport.sendSelection();
2253   }
2254
2255   public void invertColSel_actionPerformed()
2256   {
2257     viewport.invertColumnSelection();
2258     alignPanel.paintAlignment(true);
2259     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2260     viewport.sendSelection();
2261   }
2262
2263   void trimAlignment(boolean trimLeft)
2264   {
2265     ColumnSelection colSel = viewport.getColumnSelection();
2266     int column;
2267
2268     if (colSel.size() > 0)
2269     {
2270       if (trimLeft)
2271       {
2272         column = colSel.getMin();
2273       }
2274       else
2275       {
2276         column = colSel.getMax();
2277       }
2278
2279       SequenceI[] seqs;
2280       if (viewport.getSelectionGroup() != null)
2281       {
2282         seqs = viewport.getSelectionGroup().getSequencesAsArray(
2283                 viewport.getHiddenRepSequences());
2284       }
2285       else
2286       {
2287         seqs = viewport.getAlignment().getSequencesArray();
2288       }
2289
2290       TrimRegionCommand trimRegion;
2291       if (trimLeft)
2292       {
2293         trimRegion = new TrimRegionCommand("Remove Left",
2294                 TrimRegionCommand.TRIM_LEFT, seqs, column,
2295                 viewport.getAlignment(), viewport.getColumnSelection(),
2296                 viewport.getSelectionGroup());
2297         viewport.setStartRes(0);
2298       }
2299       else
2300       {
2301         trimRegion = new TrimRegionCommand("Remove Right",
2302                 TrimRegionCommand.TRIM_RIGHT, seqs, column,
2303                 viewport.getAlignment(), viewport.getColumnSelection(),
2304                 viewport.getSelectionGroup());
2305       }
2306
2307       statusBar.setText(MessageManager.formatMessage(
2308               "label.removed_columns",
2309               new String[] { Integer.valueOf(trimRegion.getSize())
2310                       .toString() }));
2311       addHistoryItem(trimRegion);
2312
2313       for (SequenceGroup sg : viewport.getAlignment().getGroups())
2314       {
2315         if ((trimLeft && !sg.adjustForRemoveLeft(column))
2316                 || (!trimLeft && !sg.adjustForRemoveRight(column)))
2317         {
2318           viewport.getAlignment().deleteGroup(sg);
2319         }
2320       }
2321
2322       viewport.firePropertyChange("alignment", null, viewport
2323               .getAlignment().getSequences());
2324     }
2325   }
2326
2327   public void removeGappedColumnMenuItem_actionPerformed()
2328   {
2329     int start = 0, end = viewport.getAlignment().getWidth() - 1;
2330
2331     SequenceI[] seqs;
2332     if (viewport.getSelectionGroup() != null)
2333     {
2334       seqs = viewport.getSelectionGroup().getSequencesAsArray(
2335               viewport.getHiddenRepSequences());
2336       start = viewport.getSelectionGroup().getStartRes();
2337       end = viewport.getSelectionGroup().getEndRes();
2338     }
2339     else
2340     {
2341       seqs = viewport.getAlignment().getSequencesArray();
2342     }
2343
2344     RemoveGapColCommand removeGapCols = new RemoveGapColCommand(
2345             "Remove Gapped Columns", seqs, start, end,
2346             viewport.getAlignment());
2347
2348     addHistoryItem(removeGapCols);
2349
2350     statusBar.setText(MessageManager.formatMessage(
2351             "label.removed_empty_columns",
2352             new String[] { Integer.valueOf(removeGapCols.getSize())
2353                     .toString() }));
2354
2355     // This is to maintain viewport position on first residue
2356     // of first sequence
2357     SequenceI seq = viewport.getAlignment().getSequenceAt(0);
2358     int startRes = seq.findPosition(viewport.startRes);
2359     // ShiftList shifts;
2360     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
2361     // edit.alColumnChanges=shifts.getInverse();
2362     // if (viewport.hasHiddenColumns)
2363     // viewport.getColumnSelection().compensateForEdits(shifts);
2364     viewport.setStartRes(seq.findIndex(startRes) - 1);
2365     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2366             .getSequences());
2367
2368   }
2369
2370   public void removeAllGapsMenuItem_actionPerformed()
2371   {
2372     int start = 0, end = viewport.getAlignment().getWidth() - 1;
2373
2374     SequenceI[] seqs;
2375     if (viewport.getSelectionGroup() != null)
2376     {
2377       seqs = viewport.getSelectionGroup().getSequencesAsArray(
2378               viewport.getHiddenRepSequences());
2379       start = viewport.getSelectionGroup().getStartRes();
2380       end = viewport.getSelectionGroup().getEndRes();
2381     }
2382     else
2383     {
2384       seqs = viewport.getAlignment().getSequencesArray();
2385     }
2386
2387     // This is to maintain viewport position on first residue
2388     // of first sequence
2389     SequenceI seq = viewport.getAlignment().getSequenceAt(0);
2390     int startRes = seq.findPosition(viewport.startRes);
2391
2392     addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
2393             viewport.getAlignment()));
2394
2395     viewport.setStartRes(seq.findIndex(startRes) - 1);
2396
2397     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2398             .getSequences());
2399
2400   }
2401
2402   public void findMenuItem_actionPerformed()
2403   {
2404     new Finder(alignPanel);
2405   }
2406
2407   /**
2408    * create a new view derived from the current view
2409    * 
2410    * @param viewtitle
2411    * @return frame for the new view
2412    */
2413   public AlignFrame newView(String viewtitle)
2414   {
2415     AlignmentI newal;
2416     if (viewport.hasHiddenRows())
2417     {
2418       newal = new Alignment(viewport.getAlignment().getHiddenSequences()
2419               .getFullAlignment().getSequencesArray());
2420     }
2421     else
2422     {
2423       newal = new Alignment(viewport.getAlignment().getSequencesArray());
2424     }
2425
2426     if (viewport.getAlignment().getAlignmentAnnotation() != null)
2427     {
2428       for (int i = 0; i < viewport.getAlignment().getAlignmentAnnotation().length; i++)
2429       {
2430         if (!viewport.getAlignment().getAlignmentAnnotation()[i].autoCalculated)
2431         {
2432           newal.addAnnotation(viewport.getAlignment()
2433                   .getAlignmentAnnotation()[i]);
2434         }
2435       }
2436     }
2437
2438     AlignFrame newaf = new AlignFrame(newal, viewport.applet, "", false);
2439
2440     newaf.viewport.setSequenceSetId(alignPanel.av.getSequenceSetId());
2441     PaintRefresher.Register(alignPanel, alignPanel.av.getSequenceSetId());
2442     PaintRefresher.Register(newaf.alignPanel,
2443             newaf.alignPanel.av.getSequenceSetId());
2444
2445     PaintRefresher.Register(newaf.alignPanel.idPanel.idCanvas,
2446             newaf.alignPanel.av.getSequenceSetId());
2447     PaintRefresher.Register(newaf.alignPanel.seqPanel.seqCanvas,
2448             newaf.alignPanel.av.getSequenceSetId());
2449
2450     Vector comps = (Vector) PaintRefresher.components.get(viewport
2451             .getSequenceSetId());
2452     int viewSize = -1;
2453     for (int i = 0; i < comps.size(); i++)
2454     {
2455       if (comps.elementAt(i) instanceof AlignmentPanel)
2456       {
2457         viewSize++;
2458       }
2459     }
2460
2461     String title = new String(this.getTitle());
2462     if (viewtitle != null)
2463     {
2464       title = viewtitle + " ( " + title + ")";
2465     }
2466     else
2467     {
2468       if (title.indexOf("(View") > -1)
2469       {
2470         title = title.substring(0, title.indexOf("(View"));
2471       }
2472       title += "(View " + viewSize + ")";
2473     }
2474
2475     newaf.setTitle(title.toString());
2476
2477     newaf.viewport.setHistoryList(viewport.getHistoryList());
2478     newaf.viewport.setRedoList(viewport.getRedoList());
2479     return newaf;
2480   }
2481
2482   /**
2483    * 
2484    * @return list of feature groups on the view
2485    */
2486   public String[] getFeatureGroups()
2487   {
2488     FeatureRenderer fr = null;
2489     if (alignPanel != null
2490             && (fr = alignPanel.getFeatureRenderer()) != null)
2491     {
2492       List<String> gps = fr.getFeatureGroups();
2493       String[] _gps = gps.toArray(new String[gps.size()]);
2494       return _gps;
2495     }
2496     return null;
2497   }
2498
2499   /**
2500    * get sequence feature groups that are hidden or shown
2501    * 
2502    * @param visible
2503    *          true is visible
2504    * @return list
2505    */
2506   public String[] getFeatureGroupsOfState(boolean visible)
2507   {
2508     FeatureRenderer fr = null;
2509     if (alignPanel != null
2510             && (fr = alignPanel.getFeatureRenderer()) != null)
2511     {
2512       List<String> gps = fr.getGroups(visible);
2513       String[] _gps = gps.toArray(new String[gps.size()]);
2514       return _gps;
2515     }
2516     return null;
2517   }
2518
2519   /**
2520    * Change the display state for the given feature groups
2521    * 
2522    * @param groups
2523    *          list of group strings
2524    * @param state
2525    *          visible or invisible
2526    */
2527   public void setFeatureGroupState(String[] groups, boolean state)
2528   {
2529     FeatureRenderer fr = null;
2530     this.sequenceFeatures.setState(true);
2531     viewport.setShowSequenceFeatures(true);
2532     if (alignPanel != null
2533             && (fr = alignPanel.getFeatureRenderer()) != null)
2534     {
2535
2536       fr.setGroupVisibility(Arrays.asList(groups), state);
2537       alignPanel.seqPanel.seqCanvas.repaint();
2538       if (alignPanel.overviewPanel != null)
2539       {
2540         alignPanel.overviewPanel.updateOverviewImage();
2541       }
2542     }
2543   }
2544
2545   public void seqLimits_itemStateChanged()
2546   {
2547     viewport.setShowJVSuffix(seqLimits.getState());
2548     alignPanel.fontChanged();
2549     alignPanel.paintAlignment(true);
2550   }
2551
2552   protected void colourTextMenuItem_actionPerformed()
2553   {
2554     viewport.setColourText(colourTextMenuItem.getState());
2555     alignPanel.paintAlignment(true);
2556   }
2557
2558   protected void displayNonconservedMenuItem_actionPerformed()
2559   {
2560     viewport.setShowUnconserved(displayNonconservedMenuItem.getState());
2561     alignPanel.paintAlignment(true);
2562   }
2563
2564   protected void wrapMenuItem_actionPerformed()
2565   {
2566     viewport.setWrapAlignment(wrapMenuItem.getState());
2567     alignPanel.setWrapAlignment(wrapMenuItem.getState());
2568     scaleAbove.setEnabled(wrapMenuItem.getState());
2569     scaleLeft.setEnabled(wrapMenuItem.getState());
2570     scaleRight.setEnabled(wrapMenuItem.getState());
2571     alignPanel.paintAlignment(true);
2572   }
2573
2574   public void overviewMenuItem_actionPerformed()
2575   {
2576     if (alignPanel.overviewPanel != null)
2577     {
2578       return;
2579     }
2580
2581     Frame frame = new Frame();
2582     OverviewPanel overview = new OverviewPanel(alignPanel);
2583     frame.add(overview);
2584     // +50 must allow for applet frame window
2585     jalview.bin.JalviewLite.addFrame(frame, MessageManager.formatMessage(
2586             "label.overview_params", new String[] { this.getTitle() }),
2587             overview.getPreferredSize().width,
2588             overview.getPreferredSize().height + 50);
2589
2590     frame.pack();
2591     final AlignmentPanel ap = alignPanel;
2592     frame.addWindowListener(new WindowAdapter()
2593     {
2594       @Override
2595       public void windowClosing(WindowEvent e)
2596       {
2597         if (ap != null)
2598         {
2599           ap.setOverviewPanel(null);
2600         }
2601       };
2602     });
2603
2604     alignPanel.setOverviewPanel(overview);
2605
2606   }
2607
2608   public void changeColour(ColourSchemeI cs)
2609   {
2610
2611     if (cs != null)
2612     {
2613       if (viewport.getAbovePIDThreshold())
2614       {
2615         viewport.setThreshold(SliderPanel.setPIDSliderSource(alignPanel,
2616                 cs, "Background"));
2617       }
2618
2619       if (viewport.getConservationSelected())
2620       {
2621         cs.setConservationApplied(true);
2622         viewport.setIncrement(SliderPanel.setConservationSlider(alignPanel,
2623                 cs, "Background"));
2624       }
2625       else
2626       {
2627         cs.setConservationApplied(false);
2628       }
2629     }
2630     viewport.setGlobalColourScheme(cs);
2631
2632     alignPanel.paintAlignment(true);
2633   }
2634
2635   protected void modifyPID_actionPerformed()
2636   {
2637     if (viewport.getAbovePIDThreshold()
2638             && viewport.getGlobalColourScheme() != null)
2639     {
2640       SliderPanel.setPIDSliderSource(alignPanel,
2641               viewport.getGlobalColourScheme(), "Background");
2642       SliderPanel.showPIDSlider();
2643     }
2644   }
2645
2646   protected void modifyConservation_actionPerformed()
2647   {
2648     if (viewport.getConservationSelected()
2649             && viewport.getGlobalColourScheme() != null)
2650     {
2651       SliderPanel.setConservationSlider(alignPanel,
2652               viewport.getGlobalColourScheme(), "Background");
2653       SliderPanel.showConservationSlider();
2654     }
2655   }
2656
2657   protected void conservationMenuItem_actionPerformed()
2658   {
2659     viewport.setConservationSelected(conservationMenuItem.getState());
2660
2661     viewport.setAbovePIDThreshold(false);
2662     abovePIDThreshold.setState(false);
2663
2664     changeColour(viewport.getGlobalColourScheme());
2665
2666     modifyConservation_actionPerformed();
2667   }
2668
2669   public void abovePIDThreshold_actionPerformed()
2670   {
2671     viewport.setAbovePIDThreshold(abovePIDThreshold.getState());
2672
2673     conservationMenuItem.setState(false);
2674     viewport.setConservationSelected(false);
2675
2676     changeColour(viewport.getGlobalColourScheme());
2677
2678     modifyPID_actionPerformed();
2679   }
2680
2681   public void sortPairwiseMenuItem_actionPerformed()
2682   {
2683     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2684     AlignmentSorter.sortByPID(viewport.getAlignment(), viewport
2685             .getAlignment().getSequenceAt(0), null);
2686
2687     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
2688             viewport.getAlignment()));
2689     alignPanel.paintAlignment(true);
2690   }
2691
2692   public void sortIDMenuItem_actionPerformed()
2693   {
2694     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2695     AlignmentSorter.sortByID(viewport.getAlignment());
2696     addHistoryItem(new OrderCommand("ID Sort", oldOrder,
2697             viewport.getAlignment()));
2698     alignPanel.paintAlignment(true);
2699   }
2700
2701   public void sortLengthMenuItem_actionPerformed()
2702   {
2703     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2704     AlignmentSorter.sortByLength(viewport.getAlignment());
2705     addHistoryItem(new OrderCommand("Length Sort", oldOrder,
2706             viewport.getAlignment()));
2707     alignPanel.paintAlignment(true);
2708   }
2709
2710   public void sortGroupMenuItem_actionPerformed()
2711   {
2712     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2713     AlignmentSorter.sortByGroup(viewport.getAlignment());
2714     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
2715             viewport.getAlignment()));
2716     alignPanel.paintAlignment(true);
2717
2718   }
2719
2720   public void removeRedundancyMenuItem_actionPerformed()
2721   {
2722     new RedundancyPanel(alignPanel);
2723   }
2724
2725   public void pairwiseAlignmentMenuItem_actionPerformed()
2726   {
2727     if (viewport.getSelectionGroup() != null
2728             && viewport.getSelectionGroup().getSize() > 1)
2729     {
2730       Frame frame = new Frame();
2731       frame.add(new PairwiseAlignPanel(alignPanel));
2732       jalview.bin.JalviewLite.addFrame(frame,
2733               MessageManager.getString("action.pairwise_alignment"), 600,
2734               500);
2735     }
2736   }
2737
2738   public void PCAMenuItem_actionPerformed()
2739   {
2740     // are the sequences aligned?
2741     if (!viewport.getAlignment().isAligned(false))
2742     {
2743       SequenceI current;
2744       int Width = viewport.getAlignment().getWidth();
2745
2746       for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2747       {
2748         current = viewport.getAlignment().getSequenceAt(i);
2749
2750         if (current.getLength() < Width)
2751         {
2752           current.insertCharAt(Width - 1, viewport.getGapCharacter());
2753         }
2754       }
2755       alignPanel.paintAlignment(true);
2756     }
2757
2758     if ((viewport.getSelectionGroup() != null
2759             && viewport.getSelectionGroup().getSize() < 4 && viewport
2760             .getSelectionGroup().getSize() > 0)
2761             || viewport.getAlignment().getHeight() < 4)
2762     {
2763       return;
2764     }
2765
2766     try
2767     {
2768       new PCAPanel(viewport);
2769     } catch (java.lang.OutOfMemoryError ex)
2770     {
2771     }
2772
2773   }
2774
2775   public void averageDistanceTreeMenuItem_actionPerformed()
2776   {
2777     NewTreePanel("AV", "PID", "Average distance tree using PID");
2778   }
2779
2780   public void neighbourTreeMenuItem_actionPerformed()
2781   {
2782     NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
2783   }
2784
2785   protected void njTreeBlosumMenuItem_actionPerformed()
2786   {
2787     NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
2788   }
2789
2790   protected void avTreeBlosumMenuItem_actionPerformed()
2791   {
2792     NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
2793   }
2794
2795   void NewTreePanel(String type, String pwType, String title)
2796   {
2797     // are the sequences aligned?
2798     if (!viewport.getAlignment().isAligned(false))
2799     {
2800       SequenceI current;
2801       int Width = viewport.getAlignment().getWidth();
2802
2803       for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2804       {
2805         current = viewport.getAlignment().getSequenceAt(i);
2806
2807         if (current.getLength() < Width)
2808         {
2809           current.insertCharAt(Width - 1, viewport.getGapCharacter());
2810         }
2811       }
2812       alignPanel.paintAlignment(true);
2813
2814     }
2815
2816     if ((viewport.getSelectionGroup() != null && viewport
2817             .getSelectionGroup().getSize() > 1)
2818             || (viewport.getAlignment().getHeight() > 1))
2819     {
2820       final TreePanel tp = new TreePanel(alignPanel, type, pwType);
2821
2822       addTreeMenuItem(tp, title);
2823
2824       jalview.bin.JalviewLite.addFrame(tp, title, 600, 500);
2825     }
2826   }
2827
2828   void loadTree_actionPerformed()
2829   {
2830     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, this);
2831     cap.setText(MessageManager.getString("label.paste_newick_tree_file"));
2832     cap.setTreeImport();
2833     Frame frame = new Frame();
2834     frame.add(cap);
2835     jalview.bin.JalviewLite.addFrame(frame,
2836             MessageManager.getString("label.paste_newick_file"), 400, 300);
2837   }
2838
2839   public void loadTree(jalview.io.NewickFile tree, String treeFile)
2840   {
2841     TreePanel tp = new TreePanel(alignPanel, treeFile,
2842             MessageManager.getString("label.load_tree_from_file"), tree);
2843     jalview.bin.JalviewLite.addFrame(tp, treeFile, 600, 500);
2844     addTreeMenuItem(tp, treeFile);
2845   }
2846
2847   /**
2848    * sort the alignment using the given treePanel
2849    * 
2850    * @param treePanel
2851    *          tree used to sort view
2852    * @param title
2853    *          string used for undo event name
2854    */
2855   public void sortByTree(TreePanel treePanel, String title)
2856   {
2857     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2858     AlignmentSorter
2859             .sortByTree(viewport.getAlignment(), treePanel.getTree());
2860     // addHistoryItem(new HistoryItem("Sort", viewport.alignment,
2861     // HistoryItem.SORT));
2862     addHistoryItem(new OrderCommand(MessageManager.formatMessage(
2863             "label.order_by_params", new String[] { title }), oldOrder,
2864             viewport.getAlignment()));
2865     alignPanel.paintAlignment(true);
2866   }
2867
2868   /**
2869    * Do any automatic reordering of the alignment and add the necessary bits to
2870    * the menu structure for the new tree
2871    * 
2872    * @param treePanel
2873    * @param title
2874    */
2875   protected void addTreeMenuItem(final TreePanel treePanel,
2876           final String title)
2877   {
2878     final MenuItem item = new MenuItem(title);
2879     sortByTreeMenu.add(item);
2880     item.addActionListener(new java.awt.event.ActionListener()
2881     {
2882       @Override
2883       public void actionPerformed(ActionEvent evt)
2884       {
2885         sortByTree(treePanel, title); // treePanel.getTitle());
2886       }
2887     });
2888
2889     treePanel.addWindowListener(new WindowAdapter()
2890     {
2891       @Override
2892       public void windowOpened(WindowEvent e)
2893       {
2894         if (viewport.sortByTree)
2895         {
2896           sortByTree(treePanel, title);
2897         }
2898         super.windowOpened(e);
2899       }
2900
2901       @Override
2902       public void windowClosing(WindowEvent e)
2903       {
2904         sortByTreeMenu.remove(item);
2905       };
2906     });
2907   }
2908
2909   public boolean sortBy(AlignmentOrder alorder, String undoname)
2910   {
2911     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2912     if (viewport.applet.debug)
2913     {
2914       System.err.println("Sorting " + alorder.getOrder().size()
2915               + " in alignment '" + getTitle() + "'");
2916     }
2917     AlignmentSorter.sortBy(viewport.getAlignment(), alorder);
2918     if (undoname != null)
2919     {
2920       addHistoryItem(new OrderCommand(undoname, oldOrder,
2921               viewport.getAlignment()));
2922     }
2923     alignPanel.paintAlignment(true);
2924     return true;
2925   }
2926
2927   protected void documentation_actionPerformed()
2928   {
2929     alignPanel.av.applet.openJalviewHelpUrl();
2930   }
2931
2932   protected void about_actionPerformed()
2933   {
2934
2935     class AboutPanel extends Canvas
2936     {
2937       String version;
2938
2939       String builddate;
2940
2941       public AboutPanel(String version, String builddate)
2942       {
2943         this.version = version;
2944         this.builddate = builddate;
2945       }
2946
2947       @Override
2948       public void paint(Graphics g)
2949       {
2950         g.setColor(Color.white);
2951         g.fillRect(0, 0, getSize().width, getSize().height);
2952         g.setFont(new Font("Helvetica", Font.PLAIN, 12));
2953         FontMetrics fm = g.getFontMetrics();
2954         int fh = fm.getHeight();
2955         int y = 5, x = 7;
2956         g.setColor(Color.black);
2957         // TODO: update this text for each release or centrally store it for
2958         // lite and application
2959         g.setFont(new Font("Helvetica", Font.BOLD, 14));
2960         g.drawString(MessageManager.formatMessage(
2961                 "label.jalviewLite_release", new String[] { version }), x,
2962                 y += fh);
2963         g.setFont(new Font("Helvetica", Font.BOLD, 12));
2964         g.drawString(MessageManager.formatMessage(
2965                 "label.jaview_build_date", new String[] { builddate }), x,
2966                 y += fh);
2967         g.setFont(new Font("Helvetica", Font.PLAIN, 12));
2968         g.drawString(MessageManager.getString("label.jalview_authors_1"),
2969                 x, y += fh * 1.5);
2970         g.drawString(MessageManager.getString("label.jalview_authors_2"),
2971                 x + 50, y += fh + 8);
2972         g.drawString(
2973                 MessageManager.getString("label.jalview_dev_managers"), x,
2974                 y += fh);
2975         g.drawString(MessageManager
2976                 .getString("label.jalview_distribution_lists"), x, y += fh);
2977         g.drawString(MessageManager.getString("label.jalview_please_cite"),
2978                 x, y += fh + 8);
2979         g.drawString(
2980                 MessageManager.getString("label.jalview_cite_1_authors"),
2981                 x, y += fh);
2982         g.drawString(
2983                 MessageManager.getString("label.jalview_cite_1_title"), x,
2984                 y += fh);
2985         g.drawString(MessageManager.getString("label.jalview_cite_1_ref"),
2986                 x, y += fh);
2987       }
2988     }
2989
2990     Frame frame = new Frame();
2991     frame.add(new AboutPanel(JalviewLite.getVersion(), JalviewLite
2992             .getBuildDate()));
2993     jalview.bin.JalviewLite.addFrame(frame,
2994             MessageManager.getString("label.jalview"), 580, 220);
2995
2996   }
2997
2998   public void showURL(String url, String target)
2999   {
3000     if (viewport.applet == null)
3001     {
3002       System.out.println("Not running as applet - no browser available.");
3003     }
3004     else
3005     {
3006       viewport.applet.showURL(url, target);
3007     }
3008   }
3009
3010   // ////////////////////////////////////////////////////////////////////////////////
3011   // JBuilder Graphics here
3012
3013   MenuBar alignFrameMenuBar = new MenuBar();
3014
3015   Menu fileMenu = new Menu(MessageManager.getString("action.file"));
3016
3017   MenuItem loadApplication = new MenuItem(
3018           MessageManager.getString("label.view_full_application"));
3019
3020   MenuItem loadTree = new MenuItem(
3021           MessageManager.getString("label.load_associated_tree"));
3022
3023   MenuItem loadAnnotations = new MenuItem(
3024           MessageManager.getString("label.load_features_annotations"));
3025
3026   MenuItem outputFeatures = new MenuItem(
3027           MessageManager.getString("label.export_features"));
3028
3029   MenuItem outputAnnotations = new MenuItem(
3030           MessageManager.getString("label.export_annotations"));
3031
3032   MenuItem closeMenuItem = new MenuItem(
3033           MessageManager.getString("action.close"));
3034
3035   MenuItem selectAllSequenceMenuItem = new MenuItem(
3036           MessageManager.getString("action.select_all"));
3037
3038   MenuItem deselectAllSequenceMenuItem = new MenuItem(
3039           MessageManager.getString("action.deselect_all"));
3040
3041   MenuItem invertSequenceMenuItem = new MenuItem(
3042           MessageManager.getString("action.invert_selection"));
3043
3044   MenuItem remove2LeftMenuItem = new MenuItem();
3045
3046   MenuItem remove2RightMenuItem = new MenuItem();
3047
3048   MenuItem removeGappedColumnMenuItem = new MenuItem();
3049
3050   MenuItem removeAllGapsMenuItem = new MenuItem();
3051
3052   CheckboxMenuItem viewBoxesMenuItem = new CheckboxMenuItem();
3053
3054   CheckboxMenuItem viewTextMenuItem = new CheckboxMenuItem();
3055
3056   MenuItem sortPairwiseMenuItem = new MenuItem();
3057
3058   MenuItem sortIDMenuItem = new MenuItem();
3059
3060   MenuItem sortLengthMenuItem = new MenuItem();
3061
3062   MenuItem sortGroupMenuItem = new MenuItem();
3063
3064   MenuItem removeRedundancyMenuItem = new MenuItem();
3065
3066   MenuItem pairwiseAlignmentMenuItem = new MenuItem();
3067
3068   MenuItem PCAMenuItem = new MenuItem();
3069
3070   MenuItem averageDistanceTreeMenuItem = new MenuItem();
3071
3072   MenuItem neighbourTreeMenuItem = new MenuItem();
3073
3074   BorderLayout borderLayout1 = new BorderLayout();
3075
3076   public Label statusBar = new Label();
3077
3078   MenuItem clustalColour = new MenuItem();
3079
3080   MenuItem zappoColour = new MenuItem();
3081
3082   MenuItem taylorColour = new MenuItem();
3083
3084   MenuItem hydrophobicityColour = new MenuItem();
3085
3086   MenuItem helixColour = new MenuItem();
3087
3088   MenuItem strandColour = new MenuItem();
3089
3090   MenuItem turnColour = new MenuItem();
3091
3092   MenuItem buriedColour = new MenuItem();
3093
3094   MenuItem purinePyrimidineColour = new MenuItem();
3095
3096   // MenuItem RNAInteractionColour = new MenuItem();
3097
3098   MenuItem RNAHelixColour = new MenuItem();
3099
3100   MenuItem userDefinedColour = new MenuItem();
3101
3102   MenuItem PIDColour = new MenuItem();
3103
3104   MenuItem BLOSUM62Colour = new MenuItem();
3105
3106   MenuItem tcoffeeColour = new MenuItem();
3107
3108   MenuItem njTreeBlosumMenuItem = new MenuItem();
3109
3110   MenuItem avDistanceTreeBlosumMenuItem = new MenuItem();
3111
3112   CheckboxMenuItem annotationPanelMenuItem = new CheckboxMenuItem();
3113
3114   CheckboxMenuItem colourTextMenuItem = new CheckboxMenuItem();
3115
3116   CheckboxMenuItem displayNonconservedMenuItem = new CheckboxMenuItem();
3117
3118   MenuItem alProperties = new MenuItem(
3119           MessageManager.getString("label.alignment_props"));
3120
3121   MenuItem overviewMenuItem = new MenuItem();
3122
3123   MenuItem undoMenuItem = new MenuItem();
3124
3125   MenuItem redoMenuItem = new MenuItem();
3126
3127   CheckboxMenuItem conservationMenuItem = new CheckboxMenuItem();
3128
3129   MenuItem noColourmenuItem = new MenuItem();
3130
3131   CheckboxMenuItem wrapMenuItem = new CheckboxMenuItem();
3132
3133   CheckboxMenuItem renderGapsMenuItem = new CheckboxMenuItem();
3134
3135   MenuItem findMenuItem = new MenuItem();
3136
3137   CheckboxMenuItem abovePIDThreshold = new CheckboxMenuItem();
3138
3139   MenuItem nucleotideColour = new MenuItem();
3140
3141   MenuItem deleteGroups = new MenuItem();
3142
3143   MenuItem grpsFromSelection = new MenuItem();
3144
3145   MenuItem createGroup = new MenuItem();
3146
3147   MenuItem unGroup = new MenuItem();
3148
3149   MenuItem delete = new MenuItem();
3150
3151   MenuItem copy = new MenuItem();
3152
3153   MenuItem cut = new MenuItem();
3154
3155   Menu pasteMenu = new Menu();
3156
3157   MenuItem pasteNew = new MenuItem();
3158
3159   MenuItem pasteThis = new MenuItem();
3160
3161   CheckboxMenuItem applyToAllGroups = new CheckboxMenuItem();
3162
3163   MenuItem font = new MenuItem();
3164
3165   CheckboxMenuItem scaleAbove = new CheckboxMenuItem();
3166
3167   CheckboxMenuItem scaleLeft = new CheckboxMenuItem();
3168
3169   CheckboxMenuItem scaleRight = new CheckboxMenuItem();
3170
3171   MenuItem modifyPID = new MenuItem();
3172
3173   MenuItem modifyConservation = new MenuItem();
3174
3175   CheckboxMenuItem autoCalculate = null;
3176
3177   CheckboxMenuItem sortByTree = new CheckboxMenuItem(
3178           "Sort Alignment With New Tree", true);
3179
3180   Menu sortByTreeMenu = new Menu();
3181
3182   MenuItem inputText = new MenuItem();
3183
3184   MenuItem documentation = new MenuItem();
3185
3186   MenuItem about = new MenuItem();
3187
3188   CheckboxMenuItem seqLimits = new CheckboxMenuItem();
3189
3190   CheckboxMenuItem centreColumnLabelFlag = new CheckboxMenuItem();
3191
3192   CheckboxMenuItem followMouseOverFlag = new CheckboxMenuItem();
3193
3194   CheckboxMenuItem showSequenceLogo = new CheckboxMenuItem();
3195
3196   CheckboxMenuItem applyAutoAnnotationSettings = new CheckboxMenuItem();
3197
3198   CheckboxMenuItem showConsensusHistogram = new CheckboxMenuItem();
3199
3200   CheckboxMenuItem showGroupConsensus = new CheckboxMenuItem();
3201
3202   CheckboxMenuItem showGroupConservation = new CheckboxMenuItem();
3203
3204   CheckboxMenuItem normSequenceLogo = new CheckboxMenuItem();
3205
3206   /**
3207    * Initialise menus and other items
3208    * 
3209    * @throws Exception
3210    */
3211   private void jbInit() throws Exception
3212   {
3213     setMenuBar(alignFrameMenuBar);
3214
3215     /*
3216      * Configure File menu items and actions
3217      */
3218     inputText
3219             .setLabel(MessageManager.getString("label.input_from_textbox"));
3220     inputText.addActionListener(this);
3221     Menu outputTextboxMenu = new Menu(
3222             MessageManager.getString("label.out_to_textbox"));
3223     for (int i = 0; i < jalview.io.AppletFormatAdapter.WRITEABLE_FORMATS.length; i++)
3224     {
3225
3226       MenuItem item = new MenuItem(
3227               jalview.io.AppletFormatAdapter.WRITEABLE_FORMATS[i]);
3228
3229       item.addActionListener(new java.awt.event.ActionListener()
3230       {
3231         @Override
3232         public void actionPerformed(ActionEvent e)
3233         {
3234           outputText_actionPerformed(e);
3235         }
3236       });
3237
3238       outputTextboxMenu.add(item);
3239     }
3240     closeMenuItem.addActionListener(this);
3241     loadApplication.addActionListener(this);
3242     loadTree.addActionListener(this);
3243     loadAnnotations.addActionListener(this);
3244     outputFeatures.addActionListener(this);
3245     outputAnnotations.addActionListener(this);
3246
3247     /*
3248      * Configure Edit menu items and actions
3249      */
3250     undoMenuItem.setEnabled(false);
3251     undoMenuItem.setLabel(MessageManager.getString("action.undo"));
3252     undoMenuItem.addActionListener(this);
3253     redoMenuItem.setEnabled(false);
3254     redoMenuItem.setLabel(MessageManager.getString("action.redo"));
3255     redoMenuItem.addActionListener(this);
3256     copy.setLabel(MessageManager.getString("action.copy"));
3257     copy.addActionListener(this);
3258     cut.setLabel(MessageManager.getString("action.cut"));
3259     cut.addActionListener(this);
3260     delete.setLabel(MessageManager.getString("action.delete"));
3261     delete.addActionListener(this);
3262     pasteMenu.setLabel(MessageManager.getString("action.paste"));
3263     pasteNew.setLabel(MessageManager.getString("label.to_new_alignment"));
3264     pasteNew.addActionListener(this);
3265     pasteThis.setLabel(MessageManager.getString("label.to_this_alignment"));
3266     pasteThis.addActionListener(this);
3267     remove2LeftMenuItem.setLabel(MessageManager
3268             .getString("action.remove_left"));
3269     remove2LeftMenuItem.addActionListener(this);
3270     remove2RightMenuItem.setLabel(MessageManager
3271             .getString("action.remove_right"));
3272     remove2RightMenuItem.addActionListener(this);
3273     removeGappedColumnMenuItem.setLabel(MessageManager
3274             .getString("action.remove_empty_columns"));
3275     removeGappedColumnMenuItem.addActionListener(this);
3276     removeAllGapsMenuItem.setLabel(MessageManager
3277             .getString("action.remove_all_gaps"));
3278     removeAllGapsMenuItem.addActionListener(this);
3279     removeRedundancyMenuItem.setLabel(MessageManager
3280             .getString("action.remove_redundancy"));
3281     removeRedundancyMenuItem.addActionListener(this);
3282
3283     /*
3284      * Configure Select menu items and actions
3285      */
3286     findMenuItem.setLabel(MessageManager.getString("action.find"));
3287     findMenuItem.addActionListener(this);
3288     selectAllSequenceMenuItem.addActionListener(this);
3289     deselectAllSequenceMenuItem.addActionListener(this);
3290     invertSequenceMenuItem.setLabel(MessageManager
3291             .getString("action.invert_sequence_selection"));
3292     invertSequenceMenuItem.addActionListener(this);
3293     invertColSel.setLabel(MessageManager
3294             .getString("action.invert_column_selection"));
3295     invertColSel.addActionListener(this);
3296     deleteGroups.setLabel(MessageManager
3297             .getString("action.undefine_groups"));
3298     deleteGroups.addActionListener(this);
3299     grpsFromSelection.setLabel(MessageManager
3300             .getString("action.make_groups_selection"));
3301     grpsFromSelection.addActionListener(this);
3302     createGroup.setLabel(MessageManager.getString("action.create_group"));
3303     unGroup.setLabel(MessageManager.getString("action.remove_group"));
3304     annotationColumnSelection.setLabel(MessageManager
3305             .getString("action.select_by_annotation"));
3306     annotationColumnSelection.addActionListener(this);
3307
3308     /*
3309      * Configure View menu items and actions
3310      */
3311     newView.setLabel(MessageManager.getString("action.new_view"));
3312     newView.addActionListener(this);
3313     Menu showMenu = new Menu(MessageManager.getString("action.show"));
3314     showColumns.setLabel(MessageManager.getString("label.all_columns"));
3315     showSeqs.setLabel(MessageManager.getString("label.all_sequences"));
3316     Menu hideMenu = new Menu(MessageManager.getString("action.hide"));
3317     hideColumns
3318             .setLabel(MessageManager.getString("label.selected_columns"));
3319     hideSequences.setLabel(MessageManager
3320             .getString("label.selected_sequences"));
3321     hideAllButSelection.setLabel(MessageManager
3322             .getString("label.all_but_selected_region"));
3323     hideAllSelection.setLabel(MessageManager
3324             .getString("label.selected_region"));
3325     showAllHidden.setLabel(MessageManager
3326             .getString("label.all_sequences_columns"));
3327     showColumns.addActionListener(this);
3328     showSeqs.addActionListener(this);
3329     hideColumns.addActionListener(this);
3330     hideSequences.addActionListener(this);
3331     hideAllButSelection.addActionListener(this);
3332     hideAllSelection.addActionListener(this);
3333     showAllHidden.addActionListener(this);
3334     featureSettings.setLabel(MessageManager
3335             .getString("action.feature_settings"));
3336     featureSettings.addActionListener(this);
3337     sequenceFeatures.setLabel(MessageManager
3338             .getString("label.show_sequence_features"));
3339     sequenceFeatures.addItemListener(this);
3340     sequenceFeatures.setState(false);
3341     followMouseOverFlag.setLabel(MessageManager
3342             .getString("label.automatic_scrolling"));
3343     followMouseOverFlag.addItemListener(this);
3344     alProperties.addActionListener(this);
3345     overviewMenuItem.setLabel(MessageManager
3346             .getString("label.overview_window"));
3347     overviewMenuItem.addActionListener(this);
3348
3349     /*
3350      * Configure Annotations menu items and actions
3351      */
3352     annotationPanelMenuItem.setLabel(MessageManager
3353             .getString("label.show_annotations"));
3354     annotationPanelMenuItem.addItemListener(this);
3355     showGroupConsensus.setLabel(MessageManager
3356             .getString("label.group_consensus"));
3357     showGroupConservation.setLabel(MessageManager
3358             .getString("label.group_conservation"));
3359     showConsensusHistogram.setLabel(MessageManager
3360             .getString("label.show_consensus_histogram"));
3361     showSequenceLogo.setLabel(MessageManager
3362             .getString("label.show_consensus_logo"));
3363     normSequenceLogo.setLabel(MessageManager
3364             .getString("label.norm_consensus_logo"));
3365     applyAutoAnnotationSettings.setLabel(MessageManager
3366             .getString("label.apply_all_groups"));
3367     applyAutoAnnotationSettings.setState(true);
3368     Menu autoAnnMenu = new Menu(
3369             MessageManager.getString("label.autocalculated_annotation"));
3370     showGroupConsensus.addItemListener(this);
3371     showGroupConservation.addItemListener(this);
3372     showConsensusHistogram.addItemListener(this);
3373     showSequenceLogo.addItemListener(this);
3374     normSequenceLogo.addItemListener(this);
3375     applyAutoAnnotationSettings.addItemListener(this);
3376     showAlignmentAnnotations = new CheckboxMenuItem(
3377             MessageManager.getString("label.show_all_al_annotations"));
3378     showSequenceAnnotations = new CheckboxMenuItem(
3379             MessageManager.getString("label.show_all_seq_annotations"));
3380     sortAnnBySequence = new CheckboxMenuItem(
3381             MessageManager.getString("label.sort_annotations_by_sequence"));
3382     sortAnnByLabel = new CheckboxMenuItem(
3383             MessageManager.getString("label.sort_annotations_by_label"));
3384     showAutoFirst = new CheckboxMenuItem(
3385             MessageManager.getString("label.show_first"));
3386     showAutoFirst.setState(false); // pending applet parameter
3387     setShowAutoCalculatedAbove(showAutoFirst.getState());
3388     showAutoLast = new CheckboxMenuItem(
3389             MessageManager.getString("label.show_last"));
3390     showAutoLast.setState(!showAutoFirst.getState());
3391     showAlignmentAnnotations.addItemListener(this);
3392     showSequenceAnnotations.addItemListener(this);
3393     sortAnnBySequence.addItemListener(this);
3394     sortAnnByLabel.addItemListener(this);
3395     showAutoFirst.addItemListener(this);
3396     showAutoLast.addItemListener(this);
3397
3398     /*
3399      * Configure Format menu items and actions
3400      */
3401     font.setLabel(MessageManager.getString("action.font"));
3402     font.addActionListener(this);
3403     scaleAbove.setLabel(MessageManager.getString("action.scale_above"));
3404     scaleAbove.setState(true);
3405     scaleAbove.setEnabled(false);
3406     scaleAbove.addItemListener(this);
3407     scaleLeft.setEnabled(false);
3408     scaleLeft.setState(true);
3409     scaleLeft.setLabel(MessageManager.getString("action.scale_left"));
3410     scaleLeft.addItemListener(this);
3411     scaleRight.setEnabled(false);
3412     scaleRight.setState(true);
3413     scaleRight.setLabel(MessageManager.getString("action.scale_right"));
3414     scaleRight.addItemListener(this);
3415     viewBoxesMenuItem.setLabel(MessageManager.getString("action.boxes"));
3416     viewBoxesMenuItem.setState(true);
3417     viewBoxesMenuItem.addItemListener(this);
3418     viewTextMenuItem.setLabel(MessageManager.getString("action.text"));
3419     viewTextMenuItem.setState(true);
3420     viewTextMenuItem.addItemListener(this);
3421     colourTextMenuItem.setLabel(MessageManager
3422             .getString("label.colour_text"));
3423     colourTextMenuItem.addItemListener(this);
3424     displayNonconservedMenuItem.setLabel(MessageManager
3425             .getString("label.show_non_conversed"));
3426     displayNonconservedMenuItem.addItemListener(this);
3427     wrapMenuItem.setLabel(MessageManager.getString("action.wrap"));
3428     wrapMenuItem.addItemListener(this);
3429     renderGapsMenuItem.setLabel(MessageManager
3430             .getString("action.show_gaps"));
3431     renderGapsMenuItem.setState(true);
3432     renderGapsMenuItem.addItemListener(this);
3433     centreColumnLabelFlag.setLabel(MessageManager
3434             .getString("label.centre_column_labels"));
3435     centreColumnLabelFlag.addItemListener(this);
3436     seqLimits.setState(true);
3437     seqLimits.setLabel(MessageManager
3438             .getString("label.show_sequence_limits"));
3439     seqLimits.addItemListener(this);
3440
3441     /*
3442      * Configure Colour menu items and actions
3443      */
3444     applyToAllGroups.setLabel(MessageManager
3445             .getString("label.apply_colour_to_all_groups"));
3446     applyToAllGroups.setState(true);
3447     applyToAllGroups.addItemListener(this);
3448     clustalColour.setLabel(MessageManager.getString("label.clustalx"));
3449     clustalColour.addActionListener(this);
3450     zappoColour.setLabel(MessageManager.getString("label.zappo"));
3451     zappoColour.addActionListener(this);
3452     taylorColour.setLabel(MessageManager.getString("label.taylor"));
3453     taylorColour.addActionListener(this);
3454     hydrophobicityColour.setLabel(MessageManager
3455             .getString("label.hydrophobicity"));
3456     hydrophobicityColour.addActionListener(this);
3457     helixColour
3458             .setLabel(MessageManager.getString("label.helix_propensity"));
3459     helixColour.addActionListener(this);
3460     strandColour.setLabel(MessageManager
3461             .getString("label.strand_propensity"));
3462     strandColour.addActionListener(this);
3463     turnColour.setLabel(MessageManager.getString("label.turn_propensity"));
3464     turnColour.addActionListener(this);
3465     buriedColour.setLabel(MessageManager.getString("label.buried_index"));
3466     buriedColour.addActionListener(this);
3467     purinePyrimidineColour.setLabel(MessageManager
3468             .getString("label.purine_pyrimidine"));
3469     purinePyrimidineColour.addActionListener(this);
3470     // RNAInteractionColour.setLabel(MessageManager
3471     // .getString("label.rna_interaction"));
3472     // RNAInteractionColour.addActionListener(this);
3473     RNAHelixColour.setLabel(MessageManager
3474             .getString("action.by_rna_helixes"));
3475     RNAHelixColour.addActionListener(this);
3476     userDefinedColour.setLabel(MessageManager
3477             .getString("action.user_defined"));
3478     userDefinedColour.addActionListener(this);
3479     PIDColour.setLabel(MessageManager
3480             .getString("label.percentage_identity"));
3481     PIDColour.addActionListener(this);
3482     BLOSUM62Colour.setLabel(MessageManager
3483             .getString("label.blosum62_score"));
3484     BLOSUM62Colour.addActionListener(this);
3485     tcoffeeColour
3486             .setLabel(MessageManager.getString("label.tcoffee_scores"));
3487     // it will be enabled only if a score file is provided
3488     tcoffeeColour.setEnabled(false);
3489     tcoffeeColour.addActionListener(this);
3490     conservationMenuItem.setLabel(MessageManager
3491             .getString("action.by_conservation"));
3492     conservationMenuItem.addItemListener(this);
3493     noColourmenuItem.setLabel(MessageManager.getString("label.none"));
3494     noColourmenuItem.addActionListener(this);
3495     abovePIDThreshold.setLabel(MessageManager
3496             .getString("label.above_identity_threshold"));
3497     abovePIDThreshold.addItemListener(this);
3498     nucleotideColour.setLabel(MessageManager.getString("label.nucleotide"));
3499     nucleotideColour.addActionListener(this);
3500     modifyPID.setLabel(MessageManager
3501             .getString("label.modify_identity_thereshold"));
3502     modifyPID.addActionListener(this);
3503     modifyConservation.setLabel(MessageManager
3504             .getString("label.modify_conservation_thereshold"));
3505     modifyConservation.addActionListener(this);
3506     annotationColour.setLabel(MessageManager
3507             .getString("action.by_annotation"));
3508     annotationColour.addActionListener(this);
3509
3510     /*
3511      * Configure Calculate menu items and actions
3512      */
3513     sortPairwiseMenuItem.setLabel(MessageManager
3514             .getString("action.by_pairwise_id"));
3515     sortPairwiseMenuItem.addActionListener(this);
3516     sortIDMenuItem.setLabel(MessageManager.getString("action.by_id"));
3517     sortIDMenuItem.addActionListener(this);
3518     sortLengthMenuItem.setLabel(MessageManager
3519             .getString("action.by_length"));
3520     sortLengthMenuItem.addActionListener(this);
3521     sortGroupMenuItem.setLabel(MessageManager.getString("action.by_group"));
3522     sortGroupMenuItem.addActionListener(this);
3523     pairwiseAlignmentMenuItem.setLabel(MessageManager
3524             .getString("action.pairwise_alignment"));
3525     pairwiseAlignmentMenuItem.addActionListener(this);
3526     PCAMenuItem.setLabel(MessageManager
3527             .getString("label.principal_component_analysis"));
3528     PCAMenuItem.addActionListener(this);
3529     autoCalculate = new CheckboxMenuItem(
3530             MessageManager.getString("label.autocalculate_consensus"), true);
3531     averageDistanceTreeMenuItem.setLabel(MessageManager
3532             .getString("label.average_distance_identity"));
3533     averageDistanceTreeMenuItem.addActionListener(this);
3534     neighbourTreeMenuItem.setLabel(MessageManager
3535             .getString("label.neighbour_joining_identity"));
3536     neighbourTreeMenuItem.addActionListener(this);
3537     avDistanceTreeBlosumMenuItem.setLabel(MessageManager
3538             .getString("label.average_distance_bloslum62"));
3539     avDistanceTreeBlosumMenuItem.addActionListener(this);
3540     njTreeBlosumMenuItem.setLabel(MessageManager
3541             .getString("label.neighbour_blosum62"));
3542     njTreeBlosumMenuItem.addActionListener(this);
3543     sortByTreeMenu.setLabel(MessageManager
3544             .getString("action.by_tree_order"));
3545     Menu sortMenu = new Menu(MessageManager.getString("action.sort"));
3546     Menu calculateTreeMenu = new Menu(
3547             MessageManager.getString("action.calculate_tree"));
3548     autoCalculate.addItemListener(this);
3549     sortByTree.addItemListener(this);
3550
3551     /*
3552      * Configure Help menu items and actions
3553      */
3554     Menu helpMenu = new Menu(MessageManager.getString("action.help"));
3555     documentation.setLabel(MessageManager.getString("label.documentation"));
3556     documentation.addActionListener(this);
3557     about.setLabel(MessageManager.getString("label.about"));
3558     about.addActionListener(this);
3559
3560     /*
3561      * Add top level menus to frame
3562      */
3563     alignFrameMenuBar.add(fileMenu);
3564     Menu editMenu = new Menu(MessageManager.getString("action.edit"));
3565     alignFrameMenuBar.add(editMenu);
3566     Menu selectMenu = new Menu(MessageManager.getString("action.select"));
3567     alignFrameMenuBar.add(selectMenu);
3568     Menu viewMenu = new Menu(MessageManager.getString("action.view"));
3569     alignFrameMenuBar.add(viewMenu);
3570     Menu annotationsMenu = new Menu(
3571             MessageManager.getString("action.annotations"));
3572     alignFrameMenuBar.add(annotationsMenu);
3573     Menu formatMenu = new Menu(MessageManager.getString("action.format"));
3574     alignFrameMenuBar.add(formatMenu);
3575     Menu colourMenu = new Menu(MessageManager.getString("action.colour"));
3576     alignFrameMenuBar.add(colourMenu);
3577     Menu calculateMenu = new Menu(
3578             MessageManager.getString("action.calculate"));
3579     alignFrameMenuBar.add(calculateMenu);
3580     alignFrameMenuBar.add(helpMenu);
3581
3582     /*
3583      * File menu
3584      */
3585     fileMenu.add(inputText);
3586     fileMenu.add(loadTree);
3587     fileMenu.add(loadAnnotations);
3588     fileMenu.addSeparator();
3589     fileMenu.add(outputTextboxMenu);
3590     fileMenu.add(outputFeatures);
3591     fileMenu.add(outputAnnotations);
3592     if (jalviewServletURL != null)
3593     {
3594       fileMenu.add(loadApplication);
3595     }
3596     fileMenu.addSeparator();
3597     fileMenu.add(closeMenuItem);
3598
3599     /*
3600      * Edit menu
3601      */
3602     editMenu.add(undoMenuItem);
3603     editMenu.add(redoMenuItem);
3604     editMenu.add(cut);
3605     editMenu.add(copy);
3606     pasteMenu.add(pasteNew);
3607     pasteMenu.add(pasteThis);
3608     editMenu.add(pasteMenu);
3609     editMenu.add(delete);
3610     editMenu.addSeparator();
3611     editMenu.add(remove2LeftMenuItem);
3612     editMenu.add(remove2RightMenuItem);
3613     editMenu.add(removeGappedColumnMenuItem);
3614     editMenu.add(removeAllGapsMenuItem);
3615     editMenu.add(removeRedundancyMenuItem);
3616
3617     /*
3618      * Select menu
3619      */
3620     selectMenu.add(findMenuItem);
3621     selectMenu.addSeparator();
3622     selectMenu.add(selectAllSequenceMenuItem);
3623     selectMenu.add(deselectAllSequenceMenuItem);
3624     selectMenu.add(invertSequenceMenuItem);
3625     selectMenu.add(invertColSel);
3626     selectMenu.add(createGroup);
3627     selectMenu.add(unGroup);
3628     selectMenu.add(grpsFromSelection);
3629     selectMenu.add(deleteGroups);
3630     selectMenu.add(annotationColumnSelection);
3631
3632     /*
3633      * View menu
3634      */
3635     viewMenu.add(newView);
3636     viewMenu.addSeparator();
3637     showMenu.add(showColumns);
3638     showMenu.add(showSeqs);
3639     showMenu.add(showAllHidden);
3640     viewMenu.add(showMenu);
3641     hideMenu.add(hideColumns);
3642     hideMenu.add(hideSequences);
3643     hideMenu.add(hideAllSelection);
3644     hideMenu.add(hideAllButSelection);
3645     viewMenu.add(hideMenu);
3646     viewMenu.addSeparator();
3647     viewMenu.add(followMouseOverFlag);
3648     viewMenu.addSeparator();
3649     viewMenu.add(sequenceFeatures);
3650     viewMenu.add(featureSettings);
3651     viewMenu.addSeparator();
3652     viewMenu.add(alProperties);
3653     viewMenu.addSeparator();
3654     viewMenu.add(overviewMenuItem);
3655
3656     /*
3657      * Annotations menu
3658      */
3659     annotationsMenu.add(annotationPanelMenuItem);
3660     annotationsMenu.addSeparator();
3661     annotationsMenu.add(showAlignmentAnnotations);
3662     annotationsMenu.add(showSequenceAnnotations);
3663     annotationsMenu.add(sortAnnBySequence);
3664     annotationsMenu.add(sortAnnByLabel);
3665     annotationsMenu.addSeparator();
3666     autoAnnMenu.add(showAutoFirst);
3667     autoAnnMenu.add(showAutoLast);
3668     autoAnnMenu.addSeparator();
3669     autoAnnMenu.add(applyAutoAnnotationSettings);
3670     autoAnnMenu.add(showConsensusHistogram);
3671     autoAnnMenu.add(showSequenceLogo);
3672     autoAnnMenu.add(normSequenceLogo);
3673     autoAnnMenu.addSeparator();
3674     autoAnnMenu.add(showGroupConservation);
3675     autoAnnMenu.add(showGroupConsensus);
3676     annotationsMenu.add(autoAnnMenu);
3677
3678     /*
3679      * Format menu
3680      */
3681     formatMenu.add(font);
3682     formatMenu.add(seqLimits);
3683     formatMenu.add(wrapMenuItem);
3684     formatMenu.add(scaleAbove);
3685     formatMenu.add(scaleLeft);
3686     formatMenu.add(scaleRight);
3687     formatMenu.add(viewBoxesMenuItem);
3688     formatMenu.add(viewTextMenuItem);
3689     formatMenu.add(colourTextMenuItem);
3690     formatMenu.add(displayNonconservedMenuItem);
3691     formatMenu.add(renderGapsMenuItem);
3692     formatMenu.add(centreColumnLabelFlag);
3693
3694     /*
3695      * Colour menu
3696      */
3697     colourMenu.add(applyToAllGroups);
3698     colourMenu.addSeparator();
3699     colourMenu.add(noColourmenuItem);
3700     colourMenu.add(clustalColour);
3701     colourMenu.add(BLOSUM62Colour);
3702     colourMenu.add(PIDColour);
3703     colourMenu.add(zappoColour);
3704     colourMenu.add(taylorColour);
3705     colourMenu.add(hydrophobicityColour);
3706     colourMenu.add(helixColour);
3707     colourMenu.add(strandColour);
3708     colourMenu.add(turnColour);
3709     colourMenu.add(buriedColour);
3710     colourMenu.add(nucleotideColour);
3711     colourMenu.add(purinePyrimidineColour);
3712     // colourMenu.add(RNAInteractionColour);
3713     colourMenu.add(tcoffeeColour);
3714     colourMenu.add(userDefinedColour);
3715     colourMenu.addSeparator();
3716     colourMenu.add(conservationMenuItem);
3717     colourMenu.add(modifyConservation);
3718     colourMenu.add(abovePIDThreshold);
3719     colourMenu.add(modifyPID);
3720     colourMenu.add(annotationColour);
3721     colourMenu.add(RNAHelixColour);
3722
3723     /*
3724      * Calculate menu
3725      */
3726     sortMenu.add(sortIDMenuItem);
3727     sortMenu.add(sortLengthMenuItem);
3728     sortMenu.add(sortByTreeMenu);
3729     sortMenu.add(sortGroupMenuItem);
3730     sortMenu.add(sortPairwiseMenuItem);
3731     calculateMenu.add(sortMenu);
3732     calculateTreeMenu.add(averageDistanceTreeMenuItem);
3733     calculateTreeMenu.add(neighbourTreeMenuItem);
3734     calculateTreeMenu.add(avDistanceTreeBlosumMenuItem);
3735     calculateTreeMenu.add(njTreeBlosumMenuItem);
3736     calculateMenu.add(calculateTreeMenu);
3737     calculateMenu.addSeparator();
3738     calculateMenu.add(pairwiseAlignmentMenuItem);
3739     calculateMenu.add(PCAMenuItem);
3740     calculateMenu.add(autoCalculate);
3741     calculateMenu.add(sortByTree);
3742
3743     /*
3744      * Help menu
3745      */
3746     helpMenu.add(documentation);
3747     helpMenu.add(about);
3748
3749     /*
3750      * Status bar
3751      */
3752     statusBar.setBackground(Color.white);
3753     statusBar.setFont(new java.awt.Font("Verdana", 0, 11));
3754     statusBar.setText(MessageManager.getString("label.status_bar"));
3755     this.add(statusBar, BorderLayout.SOUTH);
3756   }
3757
3758   public void setStatus(String string)
3759   {
3760     statusBar.setText(string);
3761   };
3762
3763   MenuItem featureSettings = new MenuItem();
3764
3765   CheckboxMenuItem sequenceFeatures = new CheckboxMenuItem();
3766
3767   MenuItem annotationColour = new MenuItem();
3768
3769   MenuItem annotationColumnSelection = new MenuItem();
3770
3771   MenuItem invertColSel = new MenuItem();
3772
3773   MenuItem showColumns = new MenuItem();
3774
3775   MenuItem showSeqs = new MenuItem();
3776
3777   MenuItem hideColumns = new MenuItem();
3778
3779   MenuItem hideSequences = new MenuItem();
3780
3781   MenuItem hideAllButSelection = new MenuItem();
3782
3783   MenuItem hideAllSelection = new MenuItem();
3784
3785   MenuItem showAllHidden = new MenuItem();
3786
3787   MenuItem newView = new MenuItem();
3788
3789   private CheckboxMenuItem showAlignmentAnnotations;
3790
3791   private CheckboxMenuItem showSequenceAnnotations;
3792
3793   private CheckboxMenuItem sortAnnBySequence;
3794
3795   private CheckboxMenuItem sortAnnByLabel;
3796
3797   private CheckboxMenuItem showAutoFirst;
3798
3799   private CheckboxMenuItem showAutoLast;
3800
3801   private SplitFrame splitFrame;
3802
3803   /**
3804    * Attach the alignFrame panels after embedding menus, if necessary. This used
3805    * to be called setEmbedded, but is now creates the dropdown menus in a
3806    * platform independent manner to avoid OSX/Mac menu appendage daftness.
3807    * 
3808    * @param reallyEmbedded
3809    *          true to attach the view to the applet area on the page rather than
3810    *          in a new window
3811    */
3812   public void createAlignFrameWindow(boolean reallyEmbedded)
3813   {
3814     if (reallyEmbedded)
3815     {
3816       embedAlignFrameInApplet(viewport.applet);
3817     }
3818     else
3819     {
3820       // //////
3821       // test and embed menu bar if necessary.
3822       //
3823       if (embedMenuIfNeeded(alignPanel))
3824       {
3825         /*
3826          * adjust for status bar height too. ? pointless as overridden by layout
3827          * manager
3828          */
3829         alignPanel.setSize(getSize().width,
3830                 getSize().height - statusBar.getHeight());
3831       }
3832       add(statusBar, BorderLayout.SOUTH);
3833       add(alignPanel, BorderLayout.CENTER);
3834       // and register with the applet so it can pass external API calls to us
3835       jalview.bin.JalviewLite.addFrame(this, this.getTitle(), frameWidth,
3836               frameHeight);
3837     }
3838   }
3839
3840   /**
3841    * Add the components of this AlignFrame to the applet container.
3842    * 
3843    * @param theApplet
3844    */
3845   public void embedAlignFrameInApplet(final JalviewLite theApplet)
3846   {
3847     // ////
3848     // Explicitly build the embedded menu panel for the on-page applet
3849     //
3850     // view cannot be closed if its actually on the page
3851     fileMenu.remove(closeMenuItem);
3852     fileMenu.remove(3); // Remove Separator
3853     // construct embedded menu, using default font
3854     embeddedMenu = makeEmbeddedPopupMenu(alignFrameMenuBar, false, false);
3855     // and actually add the components to the applet area
3856     theApplet.setLayout(new BorderLayout());
3857     theApplet.add(embeddedMenu, BorderLayout.NORTH);
3858     theApplet.add(statusBar, BorderLayout.SOUTH);
3859     // TODO should size be left to the layout manager?
3860     alignPanel.setSize(theApplet.getSize().width,
3861             theApplet.getSize().height - embeddedMenu.getHeight()
3862                     - statusBar.getHeight());
3863     theApplet.add(alignPanel, BorderLayout.CENTER);
3864     final AlignFrame me = this;
3865     theApplet.addFocusListener(new FocusListener()
3866     {
3867
3868       @Override
3869       public void focusLost(FocusEvent e)
3870       {
3871         if (theApplet.currentAlignFrame == me)
3872         {
3873           theApplet.currentAlignFrame = null;
3874         }
3875       }
3876
3877       @Override
3878       public void focusGained(FocusEvent e)
3879       {
3880         theApplet.currentAlignFrame = me;
3881       }
3882     });
3883     theApplet.validate();
3884   }
3885
3886   /**
3887    * create a new binding between structures in an existing jmol viewer instance
3888    * and an alignpanel with sequences that have existing PDBFile entries. Note,
3889    * this does not open a new Jmol window, or modify the display of the
3890    * structures in the original jmol window. Note This method doesn't work
3891    * without an additional javascript library to exchange messages between the
3892    * distinct applets. See http://issues.jalview.org/browse/JAL-621
3893    * 
3894    * @param viewer
3895    *          JmolViewer instance
3896    * @param sequenceIds
3897    *          - sequence Ids to search for associations
3898    */
3899   public SequenceStructureBinding addStructureViewInstance(
3900           Object jmolviewer, String[] sequenceIds)
3901   {
3902     Viewer viewer = null;
3903     try
3904     {
3905       viewer = (Viewer) jmolviewer;
3906     } catch (ClassCastException ex)
3907     {
3908       System.err.println("Unsupported viewer object :"
3909               + jmolviewer.getClass());
3910     }
3911     if (viewer == null)
3912     {
3913       System.err.println("Can't use this object as a structure viewer:"
3914               + jmolviewer.getClass());
3915       return null;
3916     }
3917     SequenceI[] seqs = null;
3918     if (sequenceIds == null || sequenceIds.length == 0)
3919     {
3920       seqs = viewport.getAlignment().getSequencesArray();
3921     }
3922     else
3923     {
3924       Vector sqi = new Vector();
3925       AlignmentI al = viewport.getAlignment();
3926       for (int sid = 0; sid < sequenceIds.length; sid++)
3927       {
3928         SequenceI sq = al.findName(sequenceIds[sid]);
3929         if (sq != null)
3930         {
3931           sqi.addElement(sq);
3932         }
3933       }
3934       if (sqi.size() > 0)
3935       {
3936         seqs = new SequenceI[sqi.size()];
3937         for (int sid = 0, sSize = sqi.size(); sid < sSize; sid++)
3938         {
3939           seqs[sid] = (SequenceI) sqi.elementAt(sid);
3940         }
3941       }
3942       else
3943       {
3944         return null;
3945       }
3946     }
3947     AAStructureBindingModel jmv = null;
3948     // TODO: search for a jmv that involves viewer
3949     if (jmv == null)
3950     { // create a new viewer/jalview binding.
3951       jmv = new ExtJmol(viewer, alignPanel, new SequenceI[][] { seqs });
3952     }
3953     return jmv;
3954
3955   }
3956
3957   /**
3958    * bind a pdb file to a sequence in the current view
3959    * 
3960    * @param sequenceId
3961    *          - sequenceId within the dataset.
3962    * @param pdbEntryString
3963    *          - the short name for the PDB file
3964    * @param pdbFile
3965    *          - pdb file - either a URL or a valid PDB file.
3966    * @return true if binding was as success TODO: consider making an exception
3967    *         structure for indicating when PDB parsing or sequenceId location
3968    *         fails.
3969    */
3970   public boolean addPdbFile(String sequenceId, String pdbEntryString,
3971           String pdbFile)
3972   {
3973     SequenceI toaddpdb = viewport.getAlignment().findName(sequenceId);
3974     boolean needtoadd = false;
3975     if (toaddpdb != null)
3976     {
3977       Vector pdbe = toaddpdb.getAllPDBEntries();
3978       PDBEntry pdbentry = null;
3979       if (pdbe != null && pdbe.size() > 0)
3980       {
3981         for (int pe = 0, peSize = pdbe.size(); pe < peSize; pe++)
3982         {
3983           pdbentry = (PDBEntry) pdbe.elementAt(pe);
3984           if (!pdbentry.getId().equals(pdbEntryString)
3985                   && !pdbentry.getFile().equals(pdbFile))
3986           {
3987             pdbentry = null;
3988           }
3989           else
3990           {
3991             continue;
3992           }
3993         }
3994       }
3995       if (pdbentry == null)
3996       {
3997         pdbentry = new PDBEntry();
3998         pdbentry.setId(pdbEntryString);
3999         pdbentry.setFile(pdbFile);
4000         needtoadd = true; // add this new entry to sequence.
4001       }
4002       // resolve data source
4003       // TODO: this code should be a refactored to an io package
4004       String protocol = AppletFormatAdapter.resolveProtocol(pdbFile, "PDB");
4005       if (protocol == null)
4006       {
4007         return false;
4008       }
4009       if (needtoadd)
4010       {
4011         // make a note of the access mode and add
4012         if (pdbentry.getProperty() == null)
4013         {
4014           pdbentry.setProperty(new Hashtable());
4015         }
4016         pdbentry.getProperty().put("protocol", protocol);
4017         toaddpdb.addPDBId(pdbentry);
4018         alignPanel.getStructureSelectionManager()
4019                 .registerPDBEntry(pdbentry);
4020       }
4021     }
4022     return true;
4023   }
4024
4025   private Object[] cleanSeqChainArrays(SequenceI[] seqs, String[] chains)
4026   {
4027     if (seqs != null)
4028     {
4029       Vector sequences = new Vector();
4030       for (int i = 0; i < seqs.length; i++)
4031       {
4032         if (seqs[i] != null)
4033         {
4034           sequences.addElement(new Object[] { seqs[i],
4035               (chains != null) ? chains[i] : null });
4036         }
4037       }
4038       seqs = new SequenceI[sequences.size()];
4039       chains = new String[sequences.size()];
4040       for (int i = 0, isize = sequences.size(); i < isize; i++)
4041       {
4042         Object[] oj = (Object[]) sequences.elementAt(i);
4043
4044         seqs[i] = (SequenceI) oj[0];
4045         chains[i] = (String) oj[1];
4046       }
4047     }
4048     return new Object[] { seqs, chains };
4049
4050   }
4051
4052   public void newStructureView(JalviewLite applet, PDBEntry pdb,
4053           SequenceI[] seqs, String[] chains, String protocol)
4054   {
4055     // Scrub any null sequences from the array
4056     Object[] sqch = cleanSeqChainArrays(seqs, chains);
4057     seqs = (SequenceI[]) sqch[0];
4058     chains = (String[]) sqch[1];
4059     if (seqs == null || seqs.length == 0)
4060     {
4061       System.err
4062               .println("JalviewLite.AlignFrame:newStructureView: No sequence to bind structure to.");
4063     }
4064     if (protocol == null || protocol.trim().length() == 0
4065             || protocol.equals("null"))
4066     {
4067       protocol = (String) pdb.getProperty().get("protocol");
4068       if (protocol == null)
4069       {
4070         System.err.println("Couldn't work out protocol to open structure: "
4071                 + pdb.getId());
4072         return;
4073       }
4074     }
4075     if (applet.useXtrnalSviewer)
4076     {
4077       // register the association(s) and quit, don't create any windows.
4078       if (StructureSelectionManager.getStructureSelectionManager(applet)
4079               .setMapping(seqs, chains, pdb.getFile(), protocol) == null)
4080       {
4081         System.err.println("Failed to map " + pdb.getFile() + " ("
4082                 + protocol + ") to any sequences");
4083       }
4084       return;
4085     }
4086     if (applet.isAlignPdbStructures() && applet.jmolAvailable)
4087     {
4088       // can only do alignments with Jmol
4089       // find the last jmol window assigned to this alignment
4090       jalview.appletgui.AppletJmol ajm = null, tajm;
4091       Vector jmols = applet
4092               .getAppletWindow(jalview.appletgui.AppletJmol.class);
4093       for (int i = 0, iSize = jmols.size(); i < iSize; i++)
4094       {
4095         tajm = (jalview.appletgui.AppletJmol) jmols.elementAt(i);
4096         if (tajm.ap.alignFrame == this)
4097         {
4098           ajm = tajm;
4099           break;
4100         }
4101       }
4102       if (ajm != null)
4103       {
4104         System.err
4105                 .println("Incremental adding and aligning structure to existing Jmol view not yet implemented.");
4106         // try and add the pdb structure
4107         // ajm.addS
4108         ajm = null;
4109       }
4110     }
4111     // otherwise, create a new window
4112     if (applet.jmolAvailable)
4113     {
4114       new jalview.appletgui.AppletJmol(pdb, seqs, chains, alignPanel,
4115               protocol);
4116       applet.lastFrameX += 40;
4117       applet.lastFrameY += 40;
4118     }
4119     else
4120     {
4121       new MCview.AppletPDBViewer(pdb, seqs, chains, alignPanel, protocol);
4122     }
4123
4124   }
4125
4126   public void alignedStructureView(JalviewLite applet, PDBEntry[] pdb,
4127           SequenceI[][] seqs, String[][] chains, String[] protocols)
4128   {
4129     // TODO Auto-generated method stub
4130     System.err.println("Aligned Structure View: Not yet implemented.");
4131   }
4132
4133   /**
4134    * modify the current selection, providing the user has not made a selection
4135    * already.
4136    * 
4137    * @param sel
4138    *          - sequences from this alignment
4139    * @param csel
4140    *          - columns to be selected on the alignment
4141    */
4142   public void select(SequenceGroup sel, ColumnSelection csel)
4143   {
4144     alignPanel.seqPanel.selection(sel, csel, null);
4145   }
4146
4147   public void scrollTo(int row, int column)
4148   {
4149     alignPanel.seqPanel.scrollTo(row, column);
4150   }
4151
4152   public void scrollToRow(int row)
4153   {
4154     alignPanel.seqPanel.scrollToRow(row);
4155   }
4156
4157   public void scrollToColumn(int column)
4158   {
4159     alignPanel.seqPanel.scrollToColumn(column);
4160   }
4161
4162   /**
4163    * @return the alignments unique ID.
4164    */
4165   public String getSequenceSetId()
4166   {
4167     return viewport.getSequenceSetId();
4168   }
4169
4170   /**
4171    * Load the (T-Coffee) score file from the specified url
4172    * 
4173    * @param source
4174    *          File/URL/T-COFFEE score file contents
4175    * @throws IOException
4176    * @return true if alignment was annotated with data from source
4177    */
4178   public boolean loadScoreFile(String source) throws IOException
4179   {
4180
4181     TCoffeeScoreFile file = new TCoffeeScoreFile(source,
4182             AppletFormatAdapter.checkProtocol(source));
4183     if (!file.isValid())
4184     {
4185       // TODO: raise dialog for gui
4186       System.err.println("Problems parsing T-Coffee scores: "
4187               + file.getWarningMessage());
4188       System.err.println("Origin was:\n" + source);
4189       return false;
4190     }
4191
4192     /*
4193      * check that the score matrix matches the alignment dimensions
4194      */
4195     AlignmentI aln;
4196     if ((aln = viewport.getAlignment()) != null
4197             && (aln.getHeight() != file.getHeight() || aln.getWidth() != file
4198                     .getWidth()))
4199     {
4200       // TODO: raise a dialog box here rather than bomb out.
4201       System.err
4202               .println("The scores matrix does not match the alignment dimensions");
4203
4204     }
4205
4206     // TODO add parameter to indicate if matching should be done
4207     if (file.annotateAlignment(alignPanel.getAlignment(), false))
4208     {
4209       alignPanel.fontChanged();
4210       tcoffeeColour.setEnabled(true);
4211       // switch to this color
4212       changeColour(new TCoffeeColourScheme(alignPanel.getAlignment()));
4213       return true;
4214     }
4215     else
4216     {
4217       System.err.println("Problems resolving T-Coffee scores:");
4218       if (file.getWarningMessage() != null)
4219       {
4220         System.err.println(file.getWarningMessage());
4221       }
4222     }
4223     return false;
4224   }
4225
4226   public SplitFrame getSplitFrame()
4227   {
4228     return this.splitFrame;
4229   }
4230
4231   public void setSplitFrame(SplitFrame sf)
4232   {
4233     this.splitFrame = sf;
4234   }
4235
4236   // may not need this
4237   @Override
4238   public void setShowSeqFeatures(boolean b)
4239   {
4240     // showSeqFeatures.setSelected(b);
4241     viewport.setShowSequenceFeatures(b);
4242
4243   }
4244
4245   @Override
4246   public void setMenusForViewport()
4247   {
4248     // setMenusFromViewport(viewport);
4249
4250   }
4251
4252   @Override
4253   public void refreshFeatureUI(boolean enableIfNecessary)
4254   {
4255     if (enableIfNecessary)
4256     {
4257       sequenceFeatures.setState(true);
4258       alignPanel.av.setShowSequenceFeatures(true);
4259     }
4260   }
4261
4262   @Override
4263   public FeatureSettingsControllerI getFeatureSettingsUI()
4264   {
4265     return alignPanel.av.featureSettings;
4266   }
4267
4268 }