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