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