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