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