JAL-1807 explicit imports (jalview.appletgui)
[jalview.git] / src / jalview / appletgui / AlignFrame.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.appletgui;
22
23 import jalview.analysis.AlignmentSorter;
24 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
25 import jalview.api.AlignViewControllerGuiI;
26 import jalview.api.AlignViewControllerI;
27 import jalview.api.AlignViewportI;
28 import jalview.api.FeatureRenderer;
29 import jalview.api.FeatureSettingsControllerI;
30 import jalview.api.SequenceStructureBinding;
31 import jalview.bin.JalviewLite;
32 import jalview.commands.CommandI;
33 import jalview.commands.EditCommand;
34 import jalview.commands.EditCommand.Action;
35 import jalview.commands.OrderCommand;
36 import jalview.commands.RemoveGapColCommand;
37 import jalview.commands.RemoveGapsCommand;
38 import jalview.commands.SlideSequencesCommand;
39 import jalview.commands.TrimRegionCommand;
40 import jalview.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.TCoffeeScoreFile;
56 import jalview.schemes.Blosum62ColourScheme;
57 import jalview.schemes.BuriedColourScheme;
58 import jalview.schemes.ClustalxColourScheme;
59 import jalview.schemes.ColourSchemeI;
60 import jalview.schemes.HelixColourScheme;
61 import jalview.schemes.HydrophobicColourScheme;
62 import jalview.schemes.NucleotideColourScheme;
63 import jalview.schemes.PIDColourScheme;
64 import jalview.schemes.PurinePyrimidineColourScheme;
65 import jalview.schemes.RNAHelicesColourChooser;
66 import jalview.schemes.RNAInteractionColourScheme;
67 import jalview.schemes.StrandColourScheme;
68 import jalview.schemes.TCoffeeColourScheme;
69 import jalview.schemes.TaylorColourScheme;
70 import jalview.schemes.TurnColourScheme;
71 import jalview.schemes.ZappoColourScheme;
72 import jalview.structure.StructureSelectionManager;
73 import jalview.structures.models.AAStructureBindingModel;
74 import jalview.util.Comparison;
75 import jalview.util.MappingUtils;
76 import jalview.util.MessageManager;
77 import jalview.viewmodel.AlignmentViewport;
78
79 import java.awt.BorderLayout;
80 import java.awt.Canvas;
81 import java.awt.CheckboxMenuItem;
82 import java.awt.Color;
83 import java.awt.Font;
84 import java.awt.FontMetrics;
85 import java.awt.Frame;
86 import java.awt.Graphics;
87 import java.awt.Label;
88 import java.awt.Menu;
89 import java.awt.MenuBar;
90 import java.awt.MenuItem;
91 import java.awt.event.ActionEvent;
92 import java.awt.event.ActionListener;
93 import java.awt.event.FocusEvent;
94 import java.awt.event.FocusListener;
95 import java.awt.event.ItemEvent;
96 import java.awt.event.ItemListener;
97 import java.awt.event.KeyEvent;
98 import java.awt.event.KeyListener;
99 import java.awt.event.WindowAdapter;
100 import java.awt.event.WindowEvent;
101 import java.io.IOException;
102 import java.net.URL;
103 import java.net.URLEncoder;
104 import java.util.Arrays;
105 import java.util.Deque;
106 import java.util.HashMap;
107 import java.util.Hashtable;
108 import java.util.List;
109 import java.util.Map;
110 import java.util.StringTokenizer;
111 import java.util.Vector;
112
113 import org.jmol.viewer.Viewer;
114
115 public class AlignFrame extends EmbmenuFrame implements ActionListener,
116         ItemListener, KeyListener, AlignViewControllerGuiI
117 {
118   public AlignViewControllerI avc;
119
120   public AlignmentPanel alignPanel;
121
122   public AlignViewport viewport;
123
124   // width and height may be overridden by applet parameters
125   int frameWidth = 700;
126
127   int frameHeight = 500;
128
129   String jalviewServletURL;
130
131   /*
132    * Flag for showing autocalculated consensus above or below other consensus
133    * rows
134    */
135   private boolean showAutoCalculatedAbove;
136
137   private SequenceAnnotationOrder annotationSortOrder;
138
139   /**
140    * Constructor that creates the frame and adds it to the display.
141    * 
142    * @param al
143    * @param applet
144    * @param title
145    * @param embedded
146    */
147   public AlignFrame(AlignmentI al, JalviewLite applet,
148           String title, boolean embedded)
149   {
150     this(al, applet, title, embedded, true);
151   }
152
153   /**
154    * Constructor that optionally allows the frame to be displayed or only
155    * created.
156    * 
157    * @param al
158    * @param applet
159    * @param title
160    * @param embedded
161    * @param addToDisplay
162    */
163   public AlignFrame(AlignmentI al, JalviewLite applet,
164           String title, boolean embedded, boolean addToDisplay)
165   {
166     this(al, null, null, applet, title, embedded, addToDisplay);
167   }
168
169   public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
170           ColumnSelection columnSelection, JalviewLite applet,
171           String title, boolean embedded)
172   {
173     this(al, hiddenSeqs, columnSelection, applet, title, embedded, true);
174   }
175
176   public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
177           ColumnSelection columnSelection, JalviewLite applet,
178           String title, boolean embedded, boolean addToDisplay)
179   {
180     if (applet != null)
181     {
182       jalviewServletURL = applet.getParameter("APPLICATION_URL");
183     }
184
185     try
186     {
187       jbInit();
188     } catch (Exception ex)
189     {
190       ex.printStackTrace();
191     }
192     // need to get window geometry before we calculate alignment layout
193     if (applet != null)
194     {
195       String param;
196       try
197       {
198         param = applet.getParameter("windowWidth");
199         if (param != null)
200         {
201           int width = Integer.parseInt(param);
202           frameWidth = width;
203         }
204         param = applet.getParameter("windowHeight");
205         if (param != null)
206         {
207           int height = Integer.parseInt(param);
208           frameHeight = height;
209         }
210       } catch (Exception ex)
211       {
212       }
213     }
214     viewport = new AlignViewport(al, applet);
215
216     if (hiddenSeqs != null && hiddenSeqs.length > 0)
217     {
218       viewport.hideSequence(hiddenSeqs);
219     }
220     if (columnSelection != null)
221     {
222       viewport.setColumnSelection(columnSelection);
223     }
224
225     alignPanel = new AlignmentPanel(this, viewport);
226     avc = new AlignViewController(this, viewport,
227             alignPanel);
228     viewport.updateConservation(alignPanel);
229     viewport.updateConsensus(alignPanel);
230
231     displayNonconservedMenuItem.setState(viewport.getShowUnconserved());
232     followMouseOverFlag.setState(viewport.isFollowHighlight());
233     showGroupConsensus.setState(viewport.isShowGroupConsensus());
234     showGroupConservation.setState(viewport.isShowGroupConservation());
235     showConsensusHistogram.setState(viewport.isShowConsensusHistogram());
236     showSequenceLogo.setState(viewport.isShowSequenceLogo());
237     normSequenceLogo.setState(viewport.isNormaliseSequenceLogo());
238     applyToAllGroups.setState(viewport.getColourAppliesToAllGroups());
239     annotationPanelMenuItem.setState(viewport.isShowAnnotation());
240     showAlignmentAnnotations.setState(viewport.isShowAnnotation());
241     showSequenceAnnotations.setState(viewport.isShowAnnotation());
242
243     seqLimits.setState(viewport.getShowJVSuffix());
244
245     if (applet != null)
246     {
247       String param = applet.getParameter("sortBy");
248       if (param != null)
249       {
250         if (param.equalsIgnoreCase("Id"))
251         {
252           sortIDMenuItem_actionPerformed();
253         }
254         else if (param.equalsIgnoreCase("Pairwise Identity"))
255         {
256           sortPairwiseMenuItem_actionPerformed();
257         }
258         else if (param.equalsIgnoreCase("Length"))
259         {
260           sortLengthMenuItem_actionPerformed();
261         }
262       }
263
264       param = applet.getParameter("wrap");
265       if (param != null)
266       {
267         if (param.equalsIgnoreCase("true"))
268         {
269           wrapMenuItem.setState(true);
270           wrapMenuItem_actionPerformed();
271         }
272       }
273       param = applet.getParameter("centrecolumnlabels");
274       if (param != null)
275       {
276         centreColumnLabelFlag.setState(true);
277         centreColumnLabelFlag_stateChanged();
278       }
279
280     }
281     if (viewport.getAlignment().isNucleotide())
282     {
283       viewport.updateStrucConsensus(alignPanel);
284       if (viewport.getAlignment().hasRNAStructure())
285       {
286         RNAHelixColour.setEnabled(true);
287       }
288       else
289       {
290         RNAHelixColour.setEnabled(false);
291       }
292     }
293     else
294     {
295       RNAHelixColour.setEnabled(false);
296       purinePyrimidineColour.setEnabled(false);
297     }
298     // Some JVMS send keyevents to Top frame or lowest panel,
299     // Havent worked out why yet. So add to both this frame and seqCanvas for
300     // now
301     this.addKeyListener(this);
302     alignPanel.seqPanel.seqCanvas.addKeyListener(this);
303     alignPanel.idPanel.idCanvas.addKeyListener(this);
304     alignPanel.scalePanel.addKeyListener(this);
305     alignPanel.annotationPanel.addKeyListener(this);
306     alignPanel.annotationPanelHolder.addKeyListener(this);
307     alignPanel.annotationSpaceFillerHolder.addKeyListener(this);
308     alignPanel.alabels.addKeyListener(this);
309
310     if (addToDisplay)
311     {
312       addToDisplay(embedded);
313     }
314   }
315
316   /**
317    * @param embedded
318    */
319   public void addToDisplay(boolean embedded)
320   {
321     createAlignFrameWindow(embedded);
322     validate();
323     alignPanel.adjustAnnotationHeight();
324     alignPanel.paintAlignment(true);
325   }
326
327   public AlignViewport getAlignViewport()
328   {
329     return viewport;
330   }
331
332   public SeqCanvas getSeqcanvas()
333   {
334     return alignPanel.seqPanel.seqCanvas;
335   }
336
337   /**
338    * Load a features file onto the alignment
339    * 
340    * @param file
341    *          file URL, content, or other resolvable path
342    * @param type
343    *          is protocol for accessing data referred to by file
344    */
345
346   public boolean parseFeaturesFile(String file, String type)
347   {
348     return parseFeaturesFile(file, type, true);
349   }
350
351   /**
352    * Load a features file onto the alignment
353    * 
354    * @param file
355    *          file URL, content, or other resolvable path
356    * @param type
357    *          is protocol for accessing data referred to by file
358    * @param autoenabledisplay
359    *          when true, display features flag will be automatically enabled if
360    *          features are loaded
361    * @return true if data parsed as a features file
362    */
363   public boolean parseFeaturesFile(String file, String type,
364           boolean autoenabledisplay)
365   {
366     // TODO: test if importing a features file onto an alignment which already
367     // has features with links overwrites the original links.
368
369     Hashtable featureLinks = new Hashtable();
370     boolean featuresFile = false;
371     try
372     {
373       featuresFile = new FeaturesFile(file, type)
374               .parse(viewport.getAlignment(), alignPanel.seqPanel.seqCanvas
375                       .getFeatureRenderer().getFeatureColours(), featureLinks,
376                       true, viewport.applet.getDefaultParameter(
377                               "relaxedidmatch", false));
378     } catch (Exception ex)
379     {
380       ex.printStackTrace();
381     }
382
383     if (featuresFile)
384     {
385       if (featureLinks.size() > 0)
386       {
387         alignPanel.seqPanel.seqCanvas.getFeatureRenderer().featureLinks = featureLinks;
388       }
389       if (autoenabledisplay)
390       {
391         viewport.setShowSequenceFeatures(true);
392         sequenceFeatures.setState(true);
393       }
394       if (alignPanel.seqPanel.seqCanvas.fr != null)
395       {
396         // update the min/max ranges where necessary
397         alignPanel.seqPanel.seqCanvas.fr.findAllFeatures(true);
398       }
399       if (viewport.featureSettings != null)
400       {
401         viewport.featureSettings.refreshTable();
402       }
403       alignPanel.paintAlignment(true);
404       statusBar.setText(MessageManager
405               .getString("label.successfully_added_features_alignment"));
406     }
407     return featuresFile;
408   }
409
410   @Override
411   public void keyPressed(KeyEvent evt)
412   {
413     if (viewport.cursorMode
414             && ((evt.getKeyCode() >= KeyEvent.VK_0 && evt.getKeyCode() <= KeyEvent.VK_9) || (evt
415                     .getKeyCode() >= KeyEvent.VK_NUMPAD0 && evt
416                     .getKeyCode() <= KeyEvent.VK_NUMPAD9))
417             && Character.isDigit(evt.getKeyChar()))
418     {
419       alignPanel.seqPanel.numberPressed(evt.getKeyChar());
420     }
421
422     switch (evt.getKeyCode())
423     {
424     case 27: // escape key
425       deselectAllSequenceMenuItem_actionPerformed();
426
427       alignPanel.alabels.cancelDrag();
428       break;
429     case KeyEvent.VK_X:
430       if (evt.isControlDown() || evt.isMetaDown())
431       {
432         cut_actionPerformed();
433       }
434       break;
435     case KeyEvent.VK_C:
436       if (viewport.cursorMode && !evt.isControlDown())
437       {
438         alignPanel.seqPanel.setCursorColumn();
439       }
440       if (evt.isControlDown() || evt.isMetaDown())
441       {
442         copy_actionPerformed();
443       }
444       break;
445     case KeyEvent.VK_V:
446       if (evt.isControlDown())
447       {
448         paste(evt.isShiftDown());
449       }
450       break;
451     case KeyEvent.VK_A:
452       if (evt.isControlDown() || evt.isMetaDown())
453       {
454         selectAllSequenceMenuItem_actionPerformed();
455       }
456       break;
457     case KeyEvent.VK_DOWN:
458       if (viewport.cursorMode)
459       {
460         alignPanel.seqPanel.moveCursor(0, 1);
461       }
462       else
463       {
464         moveSelectedSequences(false);
465       }
466       break;
467
468     case KeyEvent.VK_UP:
469       if (viewport.cursorMode)
470       {
471         alignPanel.seqPanel.moveCursor(0, -1);
472       }
473       else
474       {
475         moveSelectedSequences(true);
476       }
477       break;
478
479     case KeyEvent.VK_LEFT:
480       if (evt.isAltDown() || !viewport.cursorMode)
481       {
482         slideSequences(false, alignPanel.seqPanel.getKeyboardNo1());
483       }
484       else
485       {
486         alignPanel.seqPanel.moveCursor(-1, 0);
487       }
488       break;
489
490     case KeyEvent.VK_RIGHT:
491       if (evt.isAltDown() || !viewport.cursorMode)
492       {
493         slideSequences(true, alignPanel.seqPanel.getKeyboardNo1());
494       }
495       else
496       {
497         alignPanel.seqPanel.moveCursor(1, 0);
498       }
499       break;
500
501     case KeyEvent.VK_SPACE:
502       if (viewport.cursorMode)
503       {
504         alignPanel.seqPanel.insertGapAtCursor(evt.isControlDown()
505                 || evt.isShiftDown() || evt.isAltDown());
506       }
507       break;
508
509     case KeyEvent.VK_DELETE:
510     case KeyEvent.VK_BACK_SPACE:
511       if (viewport.cursorMode)
512       {
513         alignPanel.seqPanel.deleteGapAtCursor(evt.isControlDown()
514                 || evt.isShiftDown() || evt.isAltDown());
515       }
516       else
517       {
518         cut_actionPerformed();
519         alignPanel.seqPanel.seqCanvas.repaint();
520       }
521       break;
522
523     case KeyEvent.VK_S:
524       if (viewport.cursorMode)
525       {
526         alignPanel.seqPanel.setCursorRow();
527       }
528       break;
529     case KeyEvent.VK_P:
530       if (viewport.cursorMode)
531       {
532         alignPanel.seqPanel.setCursorPosition();
533       }
534       break;
535
536     case KeyEvent.VK_ENTER:
537     case KeyEvent.VK_COMMA:
538       if (viewport.cursorMode)
539       {
540         alignPanel.seqPanel.setCursorRowAndColumn();
541       }
542       break;
543
544     case KeyEvent.VK_Q:
545       if (viewport.cursorMode)
546       {
547         alignPanel.seqPanel.setSelectionAreaAtCursor(true);
548       }
549       break;
550     case KeyEvent.VK_M:
551       if (viewport.cursorMode)
552       {
553         alignPanel.seqPanel.setSelectionAreaAtCursor(false);
554       }
555       break;
556
557     case KeyEvent.VK_F2:
558       viewport.cursorMode = !viewport.cursorMode;
559       statusBar.setText(MessageManager.formatMessage(
560               "label.keyboard_editing_mode", new String[]
561               { (viewport.cursorMode ? "on" : "off") }));
562       if (viewport.cursorMode)
563       {
564         alignPanel.seqPanel.seqCanvas.cursorX = viewport.startRes;
565         alignPanel.seqPanel.seqCanvas.cursorY = viewport.startSeq;
566       }
567       break;
568
569     case KeyEvent.VK_F:
570       if (evt.isControlDown())
571       {
572         findMenuItem_actionPerformed();
573       }
574       break;
575
576     case KeyEvent.VK_H:
577     {
578       boolean toggleSeqs = !evt.isControlDown();
579       boolean toggleCols = !evt.isShiftDown();
580       toggleHiddenRegions(toggleSeqs, toggleCols);
581       break;
582     }
583
584     case KeyEvent.VK_PAGE_UP:
585       if (viewport.getWrapAlignment())
586       {
587         alignPanel.scrollUp(true);
588       }
589       else
590       {
591         alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
592                 - viewport.endSeq + viewport.startSeq);
593       }
594       break;
595
596     case KeyEvent.VK_PAGE_DOWN:
597       if (viewport.getWrapAlignment())
598       {
599         alignPanel.scrollUp(false);
600       }
601       else
602       {
603         alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
604                 + viewport.endSeq - viewport.startSeq);
605       }
606       break;
607
608     case KeyEvent.VK_Z:
609       if (evt.isControlDown())
610       {
611         undoMenuItem_actionPerformed();
612       }
613       break;
614
615     case KeyEvent.VK_Y:
616       if (evt.isControlDown())
617       {
618         redoMenuItem_actionPerformed();
619       }
620       break;
621
622     case KeyEvent.VK_L:
623       if (evt.isControlDown())
624       {
625         trimAlignment(true);
626       }
627       break;
628
629     case KeyEvent.VK_R:
630       if (evt.isControlDown())
631       {
632         trimAlignment(false);
633       }
634       break;
635
636     case KeyEvent.VK_E:
637       if (evt.isControlDown())
638       {
639         if (evt.isShiftDown())
640         {
641           this.removeAllGapsMenuItem_actionPerformed();
642         }
643         else
644         {
645           removeGappedColumnMenuItem_actionPerformed();
646         }
647       }
648       break;
649     case KeyEvent.VK_I:
650       if (evt.isControlDown())
651       {
652         if (evt.isAltDown())
653         {
654           invertColSel_actionPerformed();
655         }
656         else
657         {
658           invertSequenceMenuItem_actionPerformed();
659         }
660       }
661       break;
662
663     case KeyEvent.VK_G:
664       if (evt.isControlDown())
665       {
666         if (evt.isShiftDown())
667         {
668           this.unGroup_actionPerformed();
669         }
670         else
671         {
672           this.createGroup_actionPerformed();
673         }
674       }
675       break;
676
677     case KeyEvent.VK_U:
678       if (evt.isControlDown())
679       {
680         this.deleteGroups_actionPerformed();
681       }
682       break;
683
684     case KeyEvent.VK_T:
685       if (evt.isControlDown())
686       {
687         newView(null);
688       }
689       break;
690
691     }
692     alignPanel.paintAlignment(true);
693   }
694
695   /**
696    * called by key handler and the hide all/show all menu items
697    * 
698    * @param toggleSeqs
699    * @param toggleCols
700    */
701   private void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
702   {
703     boolean hide = false;
704     SequenceGroup sg = viewport.getSelectionGroup();
705     if (!toggleSeqs && !toggleCols)
706     {
707       // Hide everything by the current selection - this is a hack - we do the
708       // invert and then hide
709       // first check that there will be visible columns after the invert.
710       if ((viewport.getColumnSelection() != null
711               && viewport.getColumnSelection().getSelected() != null && viewport
712               .getColumnSelection().getSelected().size() > 0)
713               || (sg != null && sg.getSize() > 0 && sg.getStartRes() <= sg
714                       .getEndRes()))
715       {
716         // now invert the sequence set, if required - empty selection implies
717         // that no hiding is required.
718         if (sg != null)
719         {
720           invertSequenceMenuItem_actionPerformed();
721           sg = viewport.getSelectionGroup();
722           toggleSeqs = true;
723
724         }
725         viewport.expandColSelection(sg, true);
726         // finally invert the column selection and get the new sequence
727         // selection and indicate it should be hidden.
728         invertColSel_actionPerformed();
729         toggleCols = true;
730       }
731     }
732
733     if (toggleSeqs)
734     {
735       if (sg != null && sg.getSize() != viewport.getAlignment().getHeight())
736       {
737         hide = true;
738         viewport.hideAllSelectedSeqs();
739       }
740       else if (!(toggleCols && viewport.getColumnSelection().getSelected()
741               .size() > 0))
742       {
743         viewport.showAllHiddenSeqs();
744       }
745     }
746
747     if (toggleCols)
748     {
749       if (viewport.getColumnSelection().getSelected().size() > 0)
750       {
751         viewport.hideSelectedColumns();
752         if (!toggleSeqs)
753         {
754           viewport.setSelectionGroup(sg);
755         }
756       }
757       else if (!hide)
758       {
759         viewport.showAllHiddenColumns();
760       }
761     }
762   }
763
764   @Override
765   public void keyReleased(KeyEvent evt)
766   {
767   }
768
769   @Override
770   public void keyTyped(KeyEvent evt)
771   {
772   }
773
774   @Override
775   public void itemStateChanged(ItemEvent evt)
776   {
777     final Object source = evt.getSource();
778     if (source == displayNonconservedMenuItem)
779     {
780       displayNonconservedMenuItem_actionPerformed();
781     }
782     else if (source == colourTextMenuItem)
783     {
784       colourTextMenuItem_actionPerformed();
785     }
786     else if (source == wrapMenuItem)
787     {
788       wrapMenuItem_actionPerformed();
789     }
790     else if (source == scaleAbove)
791     {
792       viewport.setScaleAboveWrapped(scaleAbove.getState());
793     }
794     else if (source == scaleLeft)
795     {
796       viewport.setScaleLeftWrapped(scaleLeft.getState());
797     }
798     else if (source == scaleRight)
799     {
800       viewport.setScaleRightWrapped(scaleRight.getState());
801     }
802     else if (source == seqLimits)
803     {
804       seqLimits_itemStateChanged();
805     }
806     else if (source == viewBoxesMenuItem)
807     {
808       viewport.setShowBoxes(viewBoxesMenuItem.getState());
809     }
810     else if (source == viewTextMenuItem)
811     {
812       viewport.setShowText(viewTextMenuItem.getState());
813     }
814     else if (source == renderGapsMenuItem)
815     {
816       viewport.setRenderGaps(renderGapsMenuItem.getState());
817     }
818     else if (source == annotationPanelMenuItem)
819     {
820       viewport.setShowAnnotation(annotationPanelMenuItem.getState());
821       alignPanel.setAnnotationVisible(annotationPanelMenuItem.getState());
822     }
823     else if (source == sequenceFeatures)
824     {
825       viewport.setShowSequenceFeatures(sequenceFeatures.getState());
826       alignPanel.seqPanel.seqCanvas.repaint();
827     }
828     else if (source == showAlignmentAnnotations)
829     {
830       setAnnotationsVisibility();
831     }
832     else if (source == showSequenceAnnotations)
833     {
834       setAnnotationsVisibility();
835     }
836     else if (source == sortAnnBySequence)
837     {
838       boolean newState = sortAnnBySequence.getState();
839       sortAnnByLabel.setState(false);
840       setAnnotationSortOrder(newState ? SequenceAnnotationOrder.SEQUENCE_AND_LABEL
841               : SequenceAnnotationOrder.NONE);
842       setViewportAnnotationOrder();
843     }
844     else if (source == sortAnnByLabel)
845     {
846       boolean newState = sortAnnByLabel.getState();
847       sortAnnBySequence.setState(false);
848       setAnnotationSortOrder(newState ? SequenceAnnotationOrder.LABEL_AND_SEQUENCE
849               : SequenceAnnotationOrder.NONE);
850       setViewportAnnotationOrder();
851     }
852     else if (source == showAutoFirst)
853     {
854       showAutoLast.setState(!showAutoFirst.getState());
855       setShowAutoCalculatedAbove(showAutoFirst.getState());
856       setViewportAnnotationOrder();
857     }
858     else if (source == showAutoLast)
859     {
860       showAutoFirst.setState(!showAutoLast.getState());
861       setShowAutoCalculatedAbove(showAutoFirst.getState());
862       setViewportAnnotationOrder();
863     }
864     else if (source == conservationMenuItem)
865     {
866       conservationMenuItem_actionPerformed();
867     }
868     else if (source == abovePIDThreshold)
869     {
870       abovePIDThreshold_actionPerformed();
871     }
872     else if (source == applyToAllGroups)
873     {
874       viewport.setColourAppliesToAllGroups(applyToAllGroups.getState());
875     }
876     else if (source == autoCalculate)
877     {
878       viewport.autoCalculateConsensus = autoCalculate.getState();
879     }
880     else if (source == sortByTree)
881     {
882       viewport.sortByTree = sortByTree.getState();
883     }
884     else if (source == this.centreColumnLabelFlag)
885     {
886       centreColumnLabelFlag_stateChanged();
887     }
888     else if (source == this.followMouseOverFlag)
889     {
890       mouseOverFlag_stateChanged();
891     }
892     else if (source == showGroupConsensus)
893     {
894       showGroupConsensus_actionPerformed();
895     }
896     else if (source == showGroupConservation)
897     {
898       showGroupConservation_actionPerformed();
899     }
900     else if (source == showSequenceLogo)
901     {
902       showSequenceLogo_actionPerformed();
903     }
904     else if (source == normSequenceLogo)
905     {
906       normSequenceLogo_actionPerformed();
907     }
908     else if (source == showConsensusHistogram)
909     {
910       showConsensusHistogram_actionPerformed();
911     }
912     else if (source == applyAutoAnnotationSettings)
913     {
914       applyAutoAnnotationSettings_actionPerformed();
915     }
916     alignPanel.paintAlignment(true);
917   }
918
919   /**
920    * Set the visibility state of sequence-related and/or alignment-related
921    * annotations depending on checkbox selections. Repaint after calling.
922    * 
923    * @param visible
924    */
925   private void setAnnotationsVisibility()
926   {
927     boolean showForAlignment = showAlignmentAnnotations.getState();
928     boolean showForSequences = showSequenceAnnotations.getState();
929     for (AlignmentAnnotation aa : alignPanel.getAlignment()
930             .getAlignmentAnnotation())
931     {
932       boolean visible = (aa.sequenceRef == null ? showForAlignment
933               : showForSequences);
934         aa.visible = visible;
935     }
936     alignPanel.validateAnnotationDimensions(true);
937     validate();
938     repaint();
939   }
940
941   private void setAnnotationSortOrder(SequenceAnnotationOrder order)
942   {
943     this.annotationSortOrder = order;
944   }
945
946   /**
947    * Set flags on the viewport that control annotation ordering
948    */
949   private void setViewportAnnotationOrder()
950   {
951     this.alignPanel.av.setSortAnnotationsBy(this.annotationSortOrder);
952     this.alignPanel.av
953             .setShowAutocalculatedAbove(this.showAutoCalculatedAbove);
954   }
955
956   private void setShowAutoCalculatedAbove(boolean showAbove)
957   {
958     this.showAutoCalculatedAbove = showAbove;
959   }
960
961   private void mouseOverFlag_stateChanged()
962   {
963     viewport.setFollowHighlight(followMouseOverFlag.getState());
964     // TODO: could kick the scrollTo mechanism to reset view for current
965     // searchresults.
966   }
967
968   private void centreColumnLabelFlag_stateChanged()
969   {
970     viewport.centreColumnLabels = centreColumnLabelFlag.getState();
971     this.alignPanel.annotationPanel.repaint();
972   }
973
974   @Override
975   public void actionPerformed(ActionEvent evt)
976   {
977     Object source = evt.getSource();
978
979     if (source == inputText)
980     {
981       inputText_actionPerformed();
982     }
983     else if (source == loadTree)
984     {
985       loadTree_actionPerformed();
986     }
987     else if (source == loadApplication)
988     {
989       launchFullApplication();
990     }
991     else if (source == loadAnnotations)
992     {
993       loadAnnotations();
994     }
995     else if (source == outputAnnotations)
996     {
997       outputAnnotations(true);
998     }
999     else if (source == outputFeatures)
1000     {
1001       outputFeatures(true, "Jalview");
1002     }
1003     else if (source == closeMenuItem)
1004     {
1005       closeMenuItem_actionPerformed();
1006     }
1007     else if (source == copy)
1008     {
1009       copy_actionPerformed();
1010     }
1011     else if (source == undoMenuItem)
1012     {
1013       undoMenuItem_actionPerformed();
1014     }
1015     else if (source == redoMenuItem)
1016     {
1017       redoMenuItem_actionPerformed();
1018     }
1019     else if (source == inputText)
1020     {
1021       inputText_actionPerformed();
1022     }
1023     else if (source == closeMenuItem)
1024     {
1025       closeMenuItem_actionPerformed();
1026     }
1027     else if (source == undoMenuItem)
1028     {
1029       undoMenuItem_actionPerformed();
1030     }
1031     else if (source == redoMenuItem)
1032     {
1033       redoMenuItem_actionPerformed();
1034     }
1035     else if (source == copy)
1036     {
1037       copy_actionPerformed();
1038     }
1039     else if (source == pasteNew)
1040     {
1041       pasteNew_actionPerformed();
1042     }
1043     else if (source == pasteThis)
1044     {
1045       pasteThis_actionPerformed();
1046     }
1047     else if (source == cut)
1048     {
1049       cut_actionPerformed();
1050     }
1051     else if (source == delete)
1052     {
1053       delete_actionPerformed();
1054     }
1055     else if (source == grpsFromSelection)
1056     {
1057       makeGrpsFromSelection_actionPerformed();
1058     }
1059     else if (source == deleteGroups)
1060     {
1061       deleteGroups_actionPerformed();
1062     }
1063     else if (source == selectAllSequenceMenuItem)
1064     {
1065       selectAllSequenceMenuItem_actionPerformed();
1066     }
1067     else if (source == deselectAllSequenceMenuItem)
1068     {
1069       deselectAllSequenceMenuItem_actionPerformed();
1070     }
1071     else if (source == invertSequenceMenuItem)
1072     {
1073       invertSequenceMenuItem_actionPerformed();
1074     }
1075     else if (source == invertColSel)
1076     {
1077       viewport.invertColumnSelection();
1078       alignPanel.paintAlignment(true);
1079     }
1080     else if (source == remove2LeftMenuItem)
1081     {
1082       trimAlignment(true);
1083     }
1084     else if (source == remove2RightMenuItem)
1085     {
1086       trimAlignment(false);
1087     }
1088     else if (source == removeGappedColumnMenuItem)
1089     {
1090       removeGappedColumnMenuItem_actionPerformed();
1091     }
1092     else if (source == removeAllGapsMenuItem)
1093     {
1094       removeAllGapsMenuItem_actionPerformed();
1095     }
1096     else if (source == findMenuItem)
1097     {
1098       findMenuItem_actionPerformed();
1099     }
1100     else if (source == font)
1101     {
1102       new FontChooser(alignPanel);
1103     }
1104     else if (source == newView)
1105     {
1106       newView(null);
1107     }
1108     else if (source == showColumns)
1109     {
1110       viewport.showAllHiddenColumns();
1111       alignPanel.paintAlignment(true);
1112     }
1113     else if (source == showSeqs)
1114     {
1115       viewport.showAllHiddenSeqs();
1116       alignPanel.paintAlignment(true);
1117     }
1118     else if (source == hideColumns)
1119     {
1120       viewport.hideSelectedColumns();
1121       alignPanel.paintAlignment(true);
1122     }
1123     else if (source == hideSequences
1124             && viewport.getSelectionGroup() != null)
1125     {
1126       viewport.hideAllSelectedSeqs();
1127       alignPanel.paintAlignment(true);
1128     }
1129     else if (source == hideAllButSelection)
1130     {
1131       toggleHiddenRegions(false, false);
1132       alignPanel.paintAlignment(true);
1133     }
1134     else if (source == hideAllSelection)
1135     {
1136       SequenceGroup sg = viewport.getSelectionGroup();
1137       viewport.expandColSelection(sg, false);
1138       viewport.hideAllSelectedSeqs();
1139       viewport.hideSelectedColumns();
1140       alignPanel.paintAlignment(true);
1141     }
1142     else if (source == showAllHidden)
1143     {
1144       viewport.showAllHiddenColumns();
1145       viewport.showAllHiddenSeqs();
1146       alignPanel.paintAlignment(true);
1147     }
1148     else if (source == showGroupConsensus)
1149     {
1150       showGroupConsensus_actionPerformed();
1151     }
1152     else if (source == showGroupConservation)
1153     {
1154       showGroupConservation_actionPerformed();
1155     }
1156     else if (source == showSequenceLogo)
1157     {
1158       showSequenceLogo_actionPerformed();
1159     }
1160     else if (source == normSequenceLogo)
1161     {
1162       normSequenceLogo_actionPerformed();
1163     }
1164     else if (source == showConsensusHistogram)
1165     {
1166       showConsensusHistogram_actionPerformed();
1167     }
1168     else if (source == applyAutoAnnotationSettings)
1169     {
1170       applyAutoAnnotationSettings_actionPerformed();
1171     }
1172     else if (source == featureSettings)
1173     {
1174       new FeatureSettings(alignPanel);
1175     }
1176     else if (source == alProperties)
1177     {
1178       StringBuffer contents = new AlignmentProperties(
1179               viewport.getAlignment()).formatAsString();
1180       CutAndPasteTransfer cap = new CutAndPasteTransfer(false, this);
1181       cap.setText(contents.toString());
1182       Frame frame = new Frame();
1183       frame.add(cap);
1184       JalviewLite.addFrame(frame, MessageManager.formatMessage(
1185               "label.alignment_properties", new String[]
1186               { getTitle() }), 400, 250);
1187     }
1188     else if (source == overviewMenuItem)
1189     {
1190       overviewMenuItem_actionPerformed();
1191     }
1192     else if (source == noColourmenuItem)
1193     {
1194       changeColour(null);
1195     }
1196     else if (source == clustalColour)
1197     {
1198       abovePIDThreshold.setState(false);
1199       changeColour(new ClustalxColourScheme(viewport.getAlignment(), null));
1200     }
1201     else if (source == zappoColour)
1202     {
1203       changeColour(new ZappoColourScheme());
1204     }
1205     else if (source == taylorColour)
1206     {
1207       changeColour(new TaylorColourScheme());
1208     }
1209     else if (source == hydrophobicityColour)
1210     {
1211       changeColour(new HydrophobicColourScheme());
1212     }
1213     else if (source == helixColour)
1214     {
1215       changeColour(new HelixColourScheme());
1216     }
1217     else if (source == strandColour)
1218     {
1219       changeColour(new StrandColourScheme());
1220     }
1221     else if (source == turnColour)
1222     {
1223       changeColour(new TurnColourScheme());
1224     }
1225     else if (source == buriedColour)
1226     {
1227       changeColour(new BuriedColourScheme());
1228     }
1229     else if (source == nucleotideColour)
1230     {
1231       changeColour(new NucleotideColourScheme());
1232     }
1233     else if (source == purinePyrimidineColour)
1234     {
1235       changeColour(new PurinePyrimidineColourScheme());
1236     }
1237     else if (source == RNAInteractionColour)
1238     {
1239       changeColour(new RNAInteractionColourScheme());
1240     }
1241     else if (source == RNAHelixColour)
1242     {
1243       new RNAHelicesColourChooser(viewport, alignPanel);
1244     }
1245     else if (source == modifyPID)
1246     {
1247       modifyPID_actionPerformed();
1248     }
1249     else if (source == modifyConservation)
1250     {
1251       modifyConservation_actionPerformed();
1252     }
1253     else if (source == userDefinedColour)
1254     {
1255       new UserDefinedColours(alignPanel, null);
1256     }
1257     else if (source == PIDColour)
1258     {
1259       changeColour(new PIDColourScheme());
1260     }
1261     else if (source == BLOSUM62Colour)
1262     {
1263       changeColour(new Blosum62ColourScheme());
1264     }
1265     else if (source == tcoffeeColour)
1266     {
1267       changeColour(new TCoffeeColourScheme(alignPanel.getAlignment()));
1268     }
1269     else if (source == annotationColour)
1270     {
1271       new AnnotationColourChooser(viewport, alignPanel);
1272     }
1273     else if (source == annotationColumnSelection)
1274     {
1275       new AnnotationColumnChooser(viewport, alignPanel);
1276     }
1277     else if (source == sortPairwiseMenuItem)
1278     {
1279       sortPairwiseMenuItem_actionPerformed();
1280     }
1281     else if (source == sortIDMenuItem)
1282     {
1283       sortIDMenuItem_actionPerformed();
1284     }
1285     else if (source == sortLengthMenuItem)
1286     {
1287       sortLengthMenuItem_actionPerformed();
1288     }
1289     else if (source == sortGroupMenuItem)
1290     {
1291       sortGroupMenuItem_actionPerformed();
1292     }
1293     else if (source == removeRedundancyMenuItem)
1294     {
1295       removeRedundancyMenuItem_actionPerformed();
1296     }
1297     else if (source == pairwiseAlignmentMenuItem)
1298     {
1299       pairwiseAlignmentMenuItem_actionPerformed();
1300     }
1301     else if (source == PCAMenuItem)
1302     {
1303       PCAMenuItem_actionPerformed();
1304     }
1305     else if (source == averageDistanceTreeMenuItem)
1306     {
1307       averageDistanceTreeMenuItem_actionPerformed();
1308     }
1309     else if (source == neighbourTreeMenuItem)
1310     {
1311       neighbourTreeMenuItem_actionPerformed();
1312     }
1313     else if (source == njTreeBlosumMenuItem)
1314     {
1315       njTreeBlosumMenuItem_actionPerformed();
1316     }
1317     else if (source == avDistanceTreeBlosumMenuItem)
1318     {
1319       avTreeBlosumMenuItem_actionPerformed();
1320     }
1321     else if (source == documentation)
1322     {
1323       documentation_actionPerformed();
1324     }
1325     else if (source == about)
1326     {
1327       about_actionPerformed();
1328     }
1329
1330   }
1331
1332   public void inputText_actionPerformed()
1333   {
1334     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, this);
1335     Frame frame = new Frame();
1336     frame.add(cap);
1337     JalviewLite.addFrame(frame,
1338             MessageManager.getString("label.input_cut_paste"), 500, 500);
1339   }
1340
1341   protected void outputText_actionPerformed(ActionEvent e)
1342   {
1343     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, this);
1344     Frame frame = new Frame();
1345     frame.add(cap);
1346     JalviewLite.addFrame(frame, MessageManager.formatMessage(
1347             "label.alignment_output_command", new Object[]
1348             { e.getActionCommand() }), 600, 500);
1349
1350     FeatureRenderer fr = this.alignPanel.cloneFeatureRenderer();
1351     cap.setText(new AppletFormatAdapter(alignPanel).formatSequences(
1352             e.getActionCommand(), viewport.getAlignment(),
1353             viewport.getShowJVSuffix()));
1354   }
1355
1356   public void loadAnnotations()
1357   {
1358     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, this);
1359     cap.setText(MessageManager
1360             .getString("label.paste_features_annotations_Tcoffee_here"));
1361     cap.setAnnotationImport();
1362     Frame frame = new Frame();
1363     frame.add(cap);
1364     JalviewLite.addFrame(frame,
1365             MessageManager.getString("action.paste_annotations"), 400, 300);
1366
1367   }
1368
1369   public String outputAnnotations(boolean displayTextbox)
1370   {
1371     String annotation = new AnnotationFile()
1372             .printAnnotationsForView(viewport);
1373
1374     if (displayTextbox)
1375     {
1376       CutAndPasteTransfer cap = new CutAndPasteTransfer(false, this);
1377       Frame frame = new Frame();
1378       frame.add(cap);
1379       JalviewLite.addFrame(frame,
1380               MessageManager.getString("label.annotations"), 600, 500);
1381       cap.setText(annotation);
1382     }
1383
1384     return annotation;
1385   }
1386
1387   private Map<String,Object> getDisplayedFeatureCols()
1388   {
1389     if (alignPanel.getFeatureRenderer() != null
1390             && viewport.getFeaturesDisplayed()!= null)
1391     {
1392       return alignPanel.getFeatureRenderer().getDisplayedFeatureCols();
1393       
1394     }
1395     return null;
1396   }
1397
1398   public String outputFeatures(boolean displayTextbox, String format)
1399   {
1400     String features;
1401     if (format.equalsIgnoreCase("Jalview"))
1402     {
1403       features = new FeaturesFile().printJalviewFormat(viewport
1404               .getAlignment().getSequencesArray(),
1405               getDisplayedFeatureCols());
1406     }
1407     else
1408     {
1409       features = new FeaturesFile().printGFFFormat(viewport.getAlignment()
1410               .getSequencesArray(), getDisplayedFeatureCols());
1411     }
1412
1413     if (displayTextbox)
1414     {
1415       boolean frimport = false;
1416       if (features == null || features.equals("No Features Visible"))
1417       {
1418         features = "# No features visible - paste some and import them here.";
1419         frimport = true;
1420       }
1421
1422       CutAndPasteTransfer cap = new CutAndPasteTransfer(frimport, this);
1423       if (frimport)
1424       {
1425         cap.setAnnotationImport();
1426       }
1427       Frame frame = new Frame();
1428       frame.add(cap);
1429       JalviewLite.addFrame(frame,
1430               MessageManager.getString("label.features"), 600, 500);
1431       cap.setText(features);
1432     }
1433     else
1434     {
1435       if (features == null)
1436       {
1437         features = "";
1438       }
1439     }
1440
1441     return features;
1442   }
1443
1444   void launchFullApplication()
1445   {
1446     StringBuffer url = new StringBuffer(jalviewServletURL);
1447
1448     // allow servlet parameters to be passed in applet parameter
1449     String firstSep = url.lastIndexOf("?") > url.lastIndexOf("/") ? "&"
1450             : "?";
1451     url.append(firstSep);
1452
1453     url.append("open="
1454             + appendProtocol(viewport.applet.getParameter("file")));
1455
1456     if (viewport.applet.getParameter("features") != null)
1457     {
1458       url.append("&features=");
1459       url.append(appendProtocol(viewport.applet.getParameter("features")));
1460     }
1461
1462     if (viewport.applet.getParameter("annotations") != null)
1463     {
1464       url.append("&annotations=");
1465       url.append(appendProtocol(viewport.applet.getParameter("annotations")));
1466     }
1467
1468     if (viewport.applet.getParameter("jnetfile") != null)
1469     {
1470       url.append("&annotations=");
1471       url.append(appendProtocol(viewport.applet.getParameter("jnetfile")));
1472     }
1473
1474     if (viewport.applet.getParameter("defaultColour") != null)
1475     {
1476       url.append("&colour="
1477               + removeWhiteSpace(viewport.applet
1478                       .getParameter("defaultColour")));
1479     }
1480
1481     if (viewport.applet.getParameter("userDefinedColour") != null)
1482     {
1483       url.append("&colour="
1484               + removeWhiteSpace(viewport.applet
1485                       .getParameter("userDefinedColour")));
1486     }
1487     if (viewport.applet.getParameter("tree") != null)
1488     {
1489       url.append("&tree="
1490               + appendProtocol(viewport.applet.getParameter("tree")));
1491     }
1492     if (viewport.applet.getParameter("treeFile") != null)
1493     {
1494       url.append("&tree="
1495               + appendProtocol(viewport.applet.getParameter("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       statusBar.setText(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     statusBar.setText(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 paint(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         g.drawString(MessageManager.formatMessage(
2942                 "label.jalviewLite_release", new String[]
2943                 { version }), x, y += fh);
2944         g.setFont(new Font("Helvetica", Font.BOLD, 12));
2945         g.drawString(MessageManager.formatMessage(
2946                 "label.jaview_build_date", new String[]
2947                 { builddate }), x, y += fh);
2948         g.setFont(new Font("Helvetica", Font.PLAIN, 12));
2949         g.drawString(MessageManager.getString("label.jalview_authors_1"),
2950                 x, y += fh * 1.5);
2951         g.drawString(MessageManager.getString("label.jalview_authors_2"),
2952                 x + 50, y += fh + 8);
2953         g.drawString(
2954                 MessageManager.getString("label.jalview_dev_managers"), x,
2955                 y += fh);
2956         g.drawString(MessageManager
2957                 .getString("label.jalview_distribution_lists"), x, y += fh);
2958         g.drawString(MessageManager.getString("label.jalview_please_cite"),
2959                 x, y += fh + 8);
2960         g.drawString(
2961                 MessageManager.getString("label.jalview_cite_1_authors"),
2962                 x, y += fh);
2963         g.drawString(
2964                 MessageManager.getString("label.jalview_cite_1_title"), x,
2965                 y += fh);
2966         g.drawString(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   public 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     statusBar.setText(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(
3877           Object jmolviewer, String[] sequenceIds)
3878   {
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   {
4034     // Scrub any null sequences from the array
4035     Object[] sqch = cleanSeqChainArrays(seqs, chains);
4036     seqs = (SequenceI[]) sqch[0];
4037     chains = (String[]) sqch[1];
4038     if (seqs == null || seqs.length == 0)
4039     {
4040       System.err
4041               .println("JalviewLite.AlignFrame:newStructureView: No sequence to bind structure to.");
4042     }
4043     if (protocol == null || protocol.trim().length() == 0
4044             || protocol.equals("null"))
4045     {
4046       protocol = (String) pdb.getProperty().get("protocol");
4047       if (protocol == null)
4048       {
4049         System.err.println("Couldn't work out protocol to open structure: "
4050                 + pdb.getId());
4051         return;
4052       }
4053     }
4054     if (applet.useXtrnalSviewer)
4055     {
4056       // register the association(s) and quit, don't create any windows.
4057       if (StructureSelectionManager.getStructureSelectionManager(applet)
4058               .setMapping(seqs, chains, pdb.getFile(), protocol) == null)
4059       {
4060         System.err.println("Failed to map " + pdb.getFile() + " ("
4061                 + protocol + ") to any sequences");
4062       }
4063       return;
4064     }
4065     if (applet.isAlignPdbStructures() && applet.jmolAvailable)
4066     {
4067       // can only do alignments with Jmol
4068       // find the last jmol window assigned to this alignment
4069       AppletJmol ajm = null, tajm;
4070       Vector jmols = applet
4071 .getAppletWindow(AppletJmol.class);
4072       for (int i = 0, iSize = jmols.size(); i < iSize; i++)
4073       {
4074         tajm = (AppletJmol) jmols.elementAt(i);
4075         if (tajm.ap.alignFrame == this)
4076         {
4077           ajm = tajm;
4078           break;
4079         }
4080       }
4081       if (ajm != null)
4082       {
4083         System.err
4084                 .println("Incremental adding and aligning structure to existing Jmol view not yet implemented.");
4085         // try and add the pdb structure
4086         // ajm.addS
4087         ajm = null;
4088       }
4089     }
4090     // otherwise, create a new window
4091     if (applet.jmolAvailable)
4092     {
4093       new AppletJmol(pdb, seqs, chains, alignPanel, protocol);
4094       applet.lastFrameX += 40;
4095       applet.lastFrameY += 40;
4096     }
4097     else
4098     {
4099       new MCview.AppletPDBViewer(pdb, seqs, chains, alignPanel, protocol);
4100     }
4101
4102   }
4103
4104   public void alignedStructureView(JalviewLite applet, PDBEntry[] pdb,
4105           SequenceI[][] seqs, String[][] chains, String[] protocols)
4106   {
4107     // TODO Auto-generated method stub
4108     System.err.println("Aligned Structure View: Not yet implemented.");
4109   }
4110
4111   /**
4112    * modify the current selection, providing the user has not made a selection
4113    * already.
4114    * 
4115    * @param sel
4116    *          - sequences from this alignment
4117    * @param csel
4118    *          - columns to be selected on the alignment
4119    */
4120   public void select(SequenceGroup sel, ColumnSelection csel)
4121   {
4122     alignPanel.seqPanel.selection(sel, csel, null);
4123   }
4124
4125   public void scrollTo(int row, int column)
4126   {
4127     alignPanel.seqPanel.scrollTo(row, column);
4128   }
4129
4130   public void scrollToRow(int row)
4131   {
4132     alignPanel.seqPanel.scrollToRow(row);
4133   }
4134
4135   public void scrollToColumn(int column)
4136   {
4137     alignPanel.seqPanel.scrollToColumn(column);
4138   }
4139
4140   /**
4141    * @return the alignments unique ID.
4142    */
4143   public String getSequenceSetId()
4144   {
4145     return viewport.getSequenceSetId();
4146   }
4147
4148   /**
4149    * Load the (T-Coffee) score file from the specified url
4150    * 
4151    * @param source
4152    *          File/URL/T-COFFEE score file contents
4153    * @throws IOException
4154    * @return true if alignment was annotated with data from source
4155    */
4156   public boolean loadScoreFile(String source) throws IOException
4157   {
4158
4159     TCoffeeScoreFile file = new TCoffeeScoreFile(source,
4160             AppletFormatAdapter.checkProtocol(source));
4161     if (!file.isValid())
4162     {
4163       // TODO: raise dialog for gui
4164       System.err.println("Problems parsing T-Coffee scores: "
4165               + file.getWarningMessage());
4166       System.err.println("Origin was:\n" + source);
4167       return false;
4168     }
4169
4170     /*
4171      * check that the score matrix matches the alignment dimensions
4172      */
4173     AlignmentI aln;
4174     if ((aln = viewport.getAlignment()) != null
4175             && (aln.getHeight() != file.getHeight() || aln.getWidth() != file
4176                     .getWidth()))
4177     {
4178       // TODO: raise a dialog box here rather than bomb out.
4179       System.err
4180               .println("The scores matrix does not match the alignment dimensions");
4181
4182     }
4183
4184     // TODO add parameter to indicate if matching should be done
4185     if (file.annotateAlignment(alignPanel.getAlignment(), false))
4186     {
4187       alignPanel.fontChanged();
4188       tcoffeeColour.setEnabled(true);
4189       // switch to this color
4190       changeColour(new TCoffeeColourScheme(alignPanel.getAlignment()));
4191       return true;
4192     }
4193     else
4194     {
4195       System.err.println("Problems resolving T-Coffee scores:");
4196       if (file.getWarningMessage() != null)
4197       {
4198         System.err.println(file.getWarningMessage());
4199       }
4200     }
4201     return false;
4202   }
4203
4204   public SplitFrame getSplitFrame()
4205   {
4206     return this.splitFrame;
4207   }
4208
4209   public void setSplitFrame(SplitFrame sf)
4210   {
4211     this.splitFrame = sf;
4212   }
4213
4214     // may not need this
4215   @Override
4216   public void setShowSeqFeatures(boolean b)
4217   {
4218     // showSeqFeatures.setSelected(b);
4219     viewport.setShowSequenceFeatures(b);
4220
4221   }
4222
4223   @Override
4224   public void setMenusForViewport()
4225   {
4226     // setMenusFromViewport(viewport);
4227
4228   }
4229   @Override
4230   public void refreshFeatureUI(boolean enableIfNecessary)
4231   {
4232     if (enableIfNecessary)
4233     {
4234       sequenceFeatures.setState(true);
4235       alignPanel.av.setShowSequenceFeatures(true);
4236     }
4237   }
4238
4239   @Override
4240   public FeatureSettingsControllerI getFeatureSettingsUI()
4241   {
4242     return alignPanel.av.featureSettings;
4243   }
4244
4245 }