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