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