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