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