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