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