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