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