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