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