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