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