relaxed ID matching parameter JAL-753 and sortBy JAL-754
[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.net.*;
21 import java.util.*;
22
23 import java.awt.*;
24 import java.awt.event.*;
25
26 import jalview.analysis.*;
27 import jalview.api.SequenceStructureBinding;
28 import jalview.bin.JalviewLite;
29 import jalview.commands.*;
30 import jalview.datamodel.*;
31 import jalview.io.*;
32 import jalview.schemes.*;
33
34 public class AlignFrame extends EmbmenuFrame implements ActionListener,
35         ItemListener, KeyListener
36 {
37   public AlignmentPanel alignPanel;
38
39   public AlignViewport viewport;
40
41   int DEFAULT_WIDTH = 700;
42
43   int DEFAULT_HEIGHT = 500;
44
45   String jalviewServletURL;
46
47   public AlignFrame(AlignmentI al, jalview.bin.JalviewLite applet,
48           String title, boolean embedded)
49   {
50
51     if (applet != null)
52     {
53       jalviewServletURL = applet.getParameter("APPLICATION_URL");
54     }
55
56     try
57     {
58       jbInit();
59     } catch (Exception ex)
60     {
61       ex.printStackTrace();
62     }
63
64     viewport = new AlignViewport(al, applet);
65     alignPanel = new AlignmentPanel(this, viewport);
66
67     viewport.updateConservation(alignPanel);
68     viewport.updateConsensus(alignPanel);
69
70     annotationPanelMenuItem.setState(viewport.showAnnotation);
71     displayNonconservedMenuItem.setState(viewport.getShowunconserved());
72     followMouseOverFlag.setState(viewport.getFollowHighlight());
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, viewport.applet.getDefaultParameter("relaxedidmatch", false));
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   public boolean sortBy(AlignmentOrder alorder, String undoname)
2457   {
2458     SequenceI[] oldOrder = viewport.getAlignment()
2459     .getSequencesArray();
2460     if (viewport.applet.debug)
2461     {
2462       System.err.println("Sorting "+alorder.getOrder().size()+" in alignment '"+getTitle()+"'");
2463     }
2464     AlignmentSorter.sortBy(viewport.getAlignment(), alorder);
2465     if (undoname!=null)
2466     {
2467       addHistoryItem(new OrderCommand(undoname, oldOrder, viewport.alignment));
2468     }
2469     alignPanel.paintAlignment(true);
2470     return true;
2471   }
2472   protected void documentation_actionPerformed()
2473   {
2474     showURL("http://www.jalview.org/help.html", "HELP");
2475   }
2476
2477   protected void about_actionPerformed()
2478   {
2479
2480     class AboutPanel extends Canvas
2481     {
2482       String version;
2483
2484       String builddate;
2485
2486       public AboutPanel(String version, String builddate)
2487       {
2488         this.version = version;
2489         this.builddate = builddate;
2490       }
2491
2492       public void paint(Graphics g)
2493       {
2494         g.setColor(Color.white);
2495         g.fillRect(0, 0, getSize().width, getSize().height);
2496         g.setFont(new Font("Helvetica", Font.PLAIN, 12));
2497         FontMetrics fm = g.getFontMetrics();
2498         int fh = fm.getHeight();
2499         int y = 5, x = 7;
2500         g.setColor(Color.black);
2501         // TODO: update this text for each release or centrally store it for
2502         // lite and application
2503         g.setFont(new Font("Helvetica", Font.BOLD, 14));
2504         g.drawString("JalviewLite - Release " + version, x, y += fh);
2505         g.setFont(new Font("Helvetica", Font.BOLD, 12));
2506         g.drawString("Build date: " + builddate, x, y += fh);
2507         g.setFont(new Font("Helvetica", Font.PLAIN, 12));
2508         g.drawString(
2509                 "Authors:  Jim Procter, Andrew Waterhouse, Michele Clamp, James Cuff, Steve Searle,",
2510                 x, y += fh * 1.5);
2511         g.drawString("David Martin & Geoff Barton.", x + 50, y += fh);
2512         g.drawString(
2513                 "Development managed by The Barton Group, University of Dundee, Scotland, UK.",
2514                 x, y += fh);
2515         g.drawString(
2516                 "For help, see the FAQ at www.jalview.org and/or join the jalview-discuss@jalview.org mailing list",
2517                 x, y += fh);
2518         g.drawString("If  you use Jalview, please cite:", x, y += fh + 8);
2519         g.drawString(
2520                 "Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)",
2521                 x, y += fh);
2522         g.drawString(
2523                 "Jalview Version 2 - a multiple sequence alignment editor and analysis workbench",
2524                 x, y += fh);
2525         g.drawString("Bioinformatics doi: 10.1093/bioinformatics/btp033",
2526                 x, y += fh);
2527       }
2528     }
2529
2530     Frame frame = new Frame();
2531     frame.add(new AboutPanel(JalviewLite.getVersion(), JalviewLite
2532             .getBuildDate()));
2533     jalview.bin.JalviewLite.addFrame(frame, "Jalview", 580, 220);
2534
2535   }
2536
2537   public void showURL(String url, String target)
2538   {
2539     if (viewport.applet == null)
2540     {
2541       System.out.println("Not running as applet - no browser available.");
2542     }
2543     else
2544     {
2545       try
2546       {
2547         if (url.indexOf(":") == -1)
2548         {
2549           // TODO: verify (Bas Vroling bug) prepend codebase or server URL to
2550           // form valid URL
2551           if (url.indexOf("/") == 0)
2552           {
2553             String codebase = viewport.applet.getCodeBase().toString();
2554             url = codebase.substring(0, codebase.length()
2555                     - viewport.applet.getCodeBase().getFile().length())
2556                     + url;
2557           }
2558           else
2559           {
2560             url = viewport.applet.getCodeBase() + url;
2561           }
2562           System.out.println("Show url (prepended codebase): " + url);
2563         }
2564         else
2565         {
2566           System.out.println("Show url: " + url);
2567         }
2568         if (url.indexOf("javascript:") == 0)
2569         {
2570           // no target for the javascript context
2571           viewport.applet.getAppletContext().showDocument(
2572                   new java.net.URL(url));
2573         }
2574         else
2575         {
2576           viewport.applet.getAppletContext().showDocument(
2577                   new java.net.URL(url), target);
2578         }
2579       } catch (Exception ex)
2580       {
2581         ex.printStackTrace();
2582       }
2583     }
2584   }
2585
2586   // ////////////////////////////////////////////////////////////////////////////////
2587   // JBuilder Graphics here
2588
2589   MenuBar alignFrameMenuBar = new MenuBar();
2590
2591   Menu fileMenu = new Menu("File");
2592
2593   MenuItem loadApplication = new MenuItem("View in Full Application");
2594
2595   MenuItem loadTree = new MenuItem("Load Associated Tree ...");
2596
2597   MenuItem loadAnnotations = new MenuItem("Load Features/Annotations ...");
2598
2599   MenuItem outputFeatures = new MenuItem("Export Features ...");
2600
2601   MenuItem outputAnnotations = new MenuItem("Export Annotations ...");
2602
2603   MenuItem closeMenuItem = new MenuItem("Close");
2604
2605   Menu editMenu = new Menu("Edit");
2606
2607   Menu viewMenu = new Menu("View");
2608
2609   Menu colourMenu = new Menu("Colour");
2610
2611   Menu calculateMenu = new Menu("Calculate");
2612
2613   MenuItem selectAllSequenceMenuItem = new MenuItem("Select all");
2614
2615   MenuItem deselectAllSequenceMenuItem = new MenuItem("Deselect All");
2616
2617   MenuItem invertSequenceMenuItem = new MenuItem("Invert Selection");
2618
2619   MenuItem remove2LeftMenuItem = new MenuItem();
2620
2621   MenuItem remove2RightMenuItem = new MenuItem();
2622
2623   MenuItem removeGappedColumnMenuItem = new MenuItem();
2624
2625   MenuItem removeAllGapsMenuItem = new MenuItem();
2626
2627   CheckboxMenuItem viewBoxesMenuItem = new CheckboxMenuItem();
2628
2629   CheckboxMenuItem viewTextMenuItem = new CheckboxMenuItem();
2630
2631   MenuItem sortPairwiseMenuItem = new MenuItem();
2632
2633   MenuItem sortIDMenuItem = new MenuItem();
2634
2635   MenuItem sortLengthMenuItem = new MenuItem();
2636
2637   MenuItem sortGroupMenuItem = new MenuItem();
2638
2639   MenuItem removeRedundancyMenuItem = new MenuItem();
2640
2641   MenuItem pairwiseAlignmentMenuItem = new MenuItem();
2642
2643   MenuItem PCAMenuItem = new MenuItem();
2644
2645   MenuItem averageDistanceTreeMenuItem = new MenuItem();
2646
2647   MenuItem neighbourTreeMenuItem = new MenuItem();
2648
2649   BorderLayout borderLayout1 = new BorderLayout();
2650
2651   public Label statusBar = new Label();
2652
2653   Menu outputTextboxMenu = new Menu();
2654
2655   MenuItem clustalColour = new MenuItem();
2656
2657   MenuItem zappoColour = new MenuItem();
2658
2659   MenuItem taylorColour = new MenuItem();
2660
2661   MenuItem hydrophobicityColour = new MenuItem();
2662
2663   MenuItem helixColour = new MenuItem();
2664
2665   MenuItem strandColour = new MenuItem();
2666
2667   MenuItem turnColour = new MenuItem();
2668
2669   MenuItem buriedColour = new MenuItem();
2670
2671   MenuItem userDefinedColour = new MenuItem();
2672
2673   MenuItem PIDColour = new MenuItem();
2674
2675   MenuItem BLOSUM62Colour = new MenuItem();
2676
2677   MenuItem njTreeBlosumMenuItem = new MenuItem();
2678
2679   MenuItem avDistanceTreeBlosumMenuItem = new MenuItem();
2680
2681   CheckboxMenuItem annotationPanelMenuItem = new CheckboxMenuItem();
2682
2683   CheckboxMenuItem colourTextMenuItem = new CheckboxMenuItem();
2684
2685   CheckboxMenuItem displayNonconservedMenuItem = new CheckboxMenuItem();
2686
2687   MenuItem alProperties = new MenuItem("Alignment Properties...");
2688
2689   MenuItem overviewMenuItem = new MenuItem();
2690
2691   MenuItem undoMenuItem = new MenuItem();
2692
2693   MenuItem redoMenuItem = new MenuItem();
2694
2695   CheckboxMenuItem conservationMenuItem = new CheckboxMenuItem();
2696
2697   MenuItem noColourmenuItem = new MenuItem();
2698
2699   CheckboxMenuItem wrapMenuItem = new CheckboxMenuItem();
2700
2701   CheckboxMenuItem renderGapsMenuItem = new CheckboxMenuItem();
2702
2703   MenuItem findMenuItem = new MenuItem();
2704
2705   CheckboxMenuItem abovePIDThreshold = new CheckboxMenuItem();
2706
2707   MenuItem nucleotideColour = new MenuItem();
2708
2709   MenuItem deleteGroups = new MenuItem();
2710
2711   MenuItem grpsFromSelection = new MenuItem();
2712
2713   MenuItem delete = new MenuItem();
2714
2715   MenuItem copy = new MenuItem();
2716
2717   MenuItem cut = new MenuItem();
2718
2719   Menu pasteMenu = new Menu();
2720
2721   MenuItem pasteNew = new MenuItem();
2722
2723   MenuItem pasteThis = new MenuItem();
2724
2725   CheckboxMenuItem applyToAllGroups = new CheckboxMenuItem();
2726
2727   MenuItem font = new MenuItem();
2728
2729   CheckboxMenuItem scaleAbove = new CheckboxMenuItem();
2730
2731   CheckboxMenuItem scaleLeft = new CheckboxMenuItem();
2732
2733   CheckboxMenuItem scaleRight = new CheckboxMenuItem();
2734
2735   MenuItem modifyPID = new MenuItem();
2736
2737   MenuItem modifyConservation = new MenuItem();
2738
2739   CheckboxMenuItem autoCalculate = new CheckboxMenuItem(
2740           "Autocalculate Consensus", true);
2741
2742   Menu sortByTreeMenu = new Menu();
2743
2744   Menu sort = new Menu();
2745
2746   Menu calculate = new Menu();
2747
2748   MenuItem inputText = new MenuItem();
2749
2750   Menu helpMenu = new Menu();
2751
2752   MenuItem documentation = new MenuItem();
2753
2754   MenuItem about = new MenuItem();
2755
2756   CheckboxMenuItem seqLimits = new CheckboxMenuItem();
2757
2758   CheckboxMenuItem centreColumnLabelFlag = new CheckboxMenuItem();
2759
2760   CheckboxMenuItem followMouseOverFlag = new CheckboxMenuItem();
2761
2762   private void jbInit() throws Exception
2763   {
2764
2765     setMenuBar(alignFrameMenuBar);
2766
2767     MenuItem item;
2768
2769     // dynamically fill save as menu with available formats
2770     for (int i = 0; i < jalview.io.AppletFormatAdapter.WRITEABLE_FORMATS.length; i++)
2771     {
2772
2773       item = new MenuItem(
2774               jalview.io.AppletFormatAdapter.WRITEABLE_FORMATS[i]);
2775
2776       item.addActionListener(new java.awt.event.ActionListener()
2777       {
2778         public void actionPerformed(ActionEvent e)
2779         {
2780           outputText_actionPerformed(e);
2781         }
2782       });
2783
2784       outputTextboxMenu.add(item);
2785     }
2786     closeMenuItem.addActionListener(this);
2787     loadApplication.addActionListener(this);
2788
2789     loadTree.addActionListener(this);
2790     loadAnnotations.addActionListener(this);
2791     outputFeatures.addActionListener(this);
2792     outputAnnotations.addActionListener(this);
2793     selectAllSequenceMenuItem.addActionListener(this);
2794     deselectAllSequenceMenuItem.addActionListener(this);
2795     invertSequenceMenuItem.addActionListener(this);
2796     remove2LeftMenuItem.setLabel("Remove Left");
2797     remove2LeftMenuItem.addActionListener(this);
2798     remove2RightMenuItem.setLabel("Remove Right");
2799     remove2RightMenuItem.addActionListener(this);
2800     removeGappedColumnMenuItem.setLabel("Remove Empty Columns");
2801     removeGappedColumnMenuItem.addActionListener(this);
2802     removeAllGapsMenuItem.setLabel("Remove All Gaps");
2803     removeAllGapsMenuItem.addActionListener(this);
2804     viewBoxesMenuItem.setLabel("Boxes");
2805     viewBoxesMenuItem.setState(true);
2806     viewBoxesMenuItem.addItemListener(this);
2807     viewTextMenuItem.setLabel("Text");
2808     viewTextMenuItem.setState(true);
2809     viewTextMenuItem.addItemListener(this);
2810     sortPairwiseMenuItem.setLabel("by Pairwise Identity");
2811     sortPairwiseMenuItem.addActionListener(this);
2812     sortIDMenuItem.setLabel("by ID");
2813     sortIDMenuItem.addActionListener(this);
2814     sortLengthMenuItem.setLabel("by Length");
2815     sortLengthMenuItem.addActionListener(this);
2816     sortGroupMenuItem.setLabel("by Group");
2817     sortGroupMenuItem.addActionListener(this);
2818     removeRedundancyMenuItem.setLabel("Remove Redundancy...");
2819     removeRedundancyMenuItem.addActionListener(this);
2820     pairwiseAlignmentMenuItem.setLabel("Pairwise Alignments...");
2821     pairwiseAlignmentMenuItem.addActionListener(this);
2822     PCAMenuItem.setLabel("Principal Component Analysis");
2823     PCAMenuItem.addActionListener(this);
2824     averageDistanceTreeMenuItem
2825             .setLabel("Average Distance Using % Identity");
2826     averageDistanceTreeMenuItem.addActionListener(this);
2827     neighbourTreeMenuItem.setLabel("Neighbour Joining Using % Identity");
2828     neighbourTreeMenuItem.addActionListener(this);
2829     statusBar.setBackground(Color.white);
2830     statusBar.setFont(new java.awt.Font("Verdana", 0, 11));
2831     statusBar.setText("Status bar");
2832     outputTextboxMenu.setLabel("Output to Textbox");
2833     clustalColour.setLabel("Clustalx");
2834
2835     clustalColour.addActionListener(this);
2836     zappoColour.setLabel("Zappo");
2837     zappoColour.addActionListener(this);
2838     taylorColour.setLabel("Taylor");
2839     taylorColour.addActionListener(this);
2840     hydrophobicityColour.setLabel("Hydrophobicity");
2841     hydrophobicityColour.addActionListener(this);
2842     helixColour.setLabel("Helix Propensity");
2843     helixColour.addActionListener(this);
2844     strandColour.setLabel("Strand Propensity");
2845     strandColour.addActionListener(this);
2846     turnColour.setLabel("Turn Propensity");
2847     turnColour.addActionListener(this);
2848     buriedColour.setLabel("Buried Index");
2849     buriedColour.addActionListener(this);
2850     userDefinedColour.setLabel("User Defined...");
2851     userDefinedColour.addActionListener(this);
2852     PIDColour.setLabel("Percentage Identity");
2853     PIDColour.addActionListener(this);
2854     BLOSUM62Colour.setLabel("BLOSUM62 Score");
2855     BLOSUM62Colour.addActionListener(this);
2856     avDistanceTreeBlosumMenuItem
2857             .setLabel("Average Distance Using BLOSUM62");
2858     avDistanceTreeBlosumMenuItem.addActionListener(this);
2859     njTreeBlosumMenuItem.setLabel("Neighbour Joining Using BLOSUM62");
2860     njTreeBlosumMenuItem.addActionListener(this);
2861     annotationPanelMenuItem.setLabel("Show Annotations");
2862     annotationPanelMenuItem.addItemListener(this);
2863     colourTextMenuItem.setLabel("Colour Text");
2864     colourTextMenuItem.addItemListener(this);
2865     displayNonconservedMenuItem.setLabel("Show nonconserved");
2866     displayNonconservedMenuItem.addItemListener(this);
2867     alProperties.addActionListener(this);
2868     overviewMenuItem.setLabel("Overview Window");
2869     overviewMenuItem.addActionListener(this);
2870     undoMenuItem.setEnabled(false);
2871     undoMenuItem.setLabel("Undo");
2872     undoMenuItem.addActionListener(this);
2873     redoMenuItem.setEnabled(false);
2874     redoMenuItem.setLabel("Redo");
2875     redoMenuItem.addActionListener(this);
2876     conservationMenuItem.setLabel("by Conservation");
2877     conservationMenuItem.addItemListener(this);
2878     noColourmenuItem.setLabel("None");
2879     noColourmenuItem.addActionListener(this);
2880     wrapMenuItem.setLabel("Wrap");
2881     wrapMenuItem.addItemListener(this);
2882     renderGapsMenuItem.setLabel("Show Gaps");
2883     renderGapsMenuItem.setState(true);
2884     renderGapsMenuItem.addItemListener(this);
2885     findMenuItem.setLabel("Find...");
2886     findMenuItem.addActionListener(this);
2887     abovePIDThreshold.setLabel("Above Identity Threshold");
2888     abovePIDThreshold.addItemListener(this);
2889     nucleotideColour.setLabel("Nucleotide");
2890     nucleotideColour.addActionListener(this);
2891     deleteGroups.setLabel("Undefine Groups");
2892     deleteGroups.addActionListener(this);
2893     grpsFromSelection.setLabel("Make Groups for selection");
2894     grpsFromSelection.addActionListener(this);
2895     copy.setLabel("Copy");
2896     copy.addActionListener(this);
2897     cut.setLabel("Cut");
2898     cut.addActionListener(this);
2899     delete.setLabel("Delete");
2900     delete.addActionListener(this);
2901     pasteMenu.setLabel("Paste");
2902     pasteNew.setLabel("To New Alignment");
2903     pasteNew.addActionListener(this);
2904     pasteThis.setLabel("Add To This Alignment");
2905     pasteThis.addActionListener(this);
2906     applyToAllGroups.setLabel("Apply Colour To All Groups");
2907     applyToAllGroups.setState(true);
2908     applyToAllGroups.addItemListener(this);
2909     font.setLabel("Font...");
2910     font.addActionListener(this);
2911     scaleAbove.setLabel("Scale Above");
2912     scaleAbove.setState(true);
2913     scaleAbove.setEnabled(false);
2914     scaleAbove.addItemListener(this);
2915     scaleLeft.setEnabled(false);
2916     scaleLeft.setState(true);
2917     scaleLeft.setLabel("Scale Left");
2918     scaleLeft.addItemListener(this);
2919     scaleRight.setEnabled(false);
2920     scaleRight.setState(true);
2921     scaleRight.setLabel("Scale Right");
2922     scaleRight.addItemListener(this);
2923     modifyPID.setLabel("Modify Identity Threshold...");
2924     modifyPID.addActionListener(this);
2925     modifyConservation.setLabel("Modify Conservation Threshold...");
2926     modifyConservation.addActionListener(this);
2927     sortByTreeMenu.setLabel("By Tree Order");
2928     sort.setLabel("Sort");
2929     calculate.setLabel("Calculate Tree");
2930     autoCalculate.addItemListener(this);
2931     inputText.setLabel("Input from textbox");
2932     inputText.addActionListener(this);
2933     centreColumnLabelFlag.setLabel("Centre column labels");
2934     centreColumnLabelFlag.addItemListener(this);
2935     followMouseOverFlag.setLabel("Automatic Scrolling");
2936     followMouseOverFlag.addItemListener(this);
2937     helpMenu.setLabel("Help");
2938     documentation.setLabel("Documentation");
2939     documentation.addActionListener(this);
2940
2941     about.setLabel("About...");
2942     about.addActionListener(this);
2943     seqLimits.setState(true);
2944     seqLimits.setLabel("Show Sequence Limits");
2945     seqLimits.addItemListener(this);
2946     featureSettings.setLabel("Feature Settings...");
2947     featureSettings.addActionListener(this);
2948     sequenceFeatures.setLabel("Sequence Features");
2949     sequenceFeatures.addItemListener(this);
2950     sequenceFeatures.setState(false);
2951     annotationColour.setLabel("by Annotation...");
2952     annotationColour.addActionListener(this);
2953     invertSequenceMenuItem.setLabel("Invert Sequence Selection");
2954     invertColSel.setLabel("Invert Column Selection");
2955     menu1.setLabel("Show");
2956     showColumns.setLabel("All Columns ");
2957     showSeqs.setLabel("All Sequences");
2958     menu2.setLabel("Hide");
2959     hideColumns.setLabel("Selected Columns");
2960     hideSequences.setLabel("Selected Sequences");
2961     hideAllButSelection.setLabel("All but Selected Region (Shift+Ctrl+H)");
2962     hideAllSelection.setLabel("Selected Region");
2963     showAllHidden.setLabel("All Sequences and Columns");
2964     invertColSel.addActionListener(this);
2965     showColumns.addActionListener(this);
2966     showSeqs.addActionListener(this);
2967     hideColumns.addActionListener(this);
2968     hideSequences.addActionListener(this);
2969     hideAllButSelection.addActionListener(this);
2970     hideAllSelection.addActionListener(this);
2971     showAllHidden.addActionListener(this);
2972     formatMenu.setLabel("Format");
2973     selectMenu.setLabel("Select");
2974     newView.setLabel("New View");
2975     newView.addActionListener(this);
2976     alignFrameMenuBar.add(fileMenu);
2977     alignFrameMenuBar.add(editMenu);
2978     alignFrameMenuBar.add(selectMenu);
2979     alignFrameMenuBar.add(viewMenu);
2980     alignFrameMenuBar.add(formatMenu);
2981     alignFrameMenuBar.add(colourMenu);
2982     alignFrameMenuBar.add(calculateMenu);
2983     alignFrameMenuBar.add(helpMenu);
2984
2985     fileMenu.add(inputText);
2986     fileMenu.add(loadTree);
2987     fileMenu.add(loadAnnotations);
2988
2989     fileMenu.addSeparator();
2990     fileMenu.add(outputTextboxMenu);
2991     fileMenu.add(outputFeatures);
2992     fileMenu.add(outputAnnotations);
2993
2994     if (jalviewServletURL != null)
2995     {
2996       fileMenu.add(loadApplication);
2997     }
2998
2999     fileMenu.addSeparator();
3000     fileMenu.add(closeMenuItem);
3001
3002     editMenu.add(undoMenuItem);
3003     editMenu.add(redoMenuItem);
3004     editMenu.add(cut);
3005     editMenu.add(copy);
3006     editMenu.add(pasteMenu);
3007     editMenu.add(delete);
3008     editMenu.addSeparator();
3009     editMenu.add(remove2LeftMenuItem);
3010     editMenu.add(remove2RightMenuItem);
3011     editMenu.add(removeGappedColumnMenuItem);
3012     editMenu.add(removeAllGapsMenuItem);
3013     editMenu.add(removeRedundancyMenuItem);
3014     viewMenu.add(newView);
3015     viewMenu.addSeparator();
3016     viewMenu.add(menu1);
3017     viewMenu.add(menu2);
3018     viewMenu.addSeparator();
3019     viewMenu.add(followMouseOverFlag);
3020     viewMenu.add(annotationPanelMenuItem);
3021     viewMenu.addSeparator();
3022     viewMenu.add(sequenceFeatures);
3023     viewMenu.add(featureSettings);
3024     viewMenu.addSeparator();
3025     viewMenu.add(alProperties);
3026     viewMenu.addSeparator();
3027     viewMenu.add(overviewMenuItem);
3028     colourMenu.add(applyToAllGroups);
3029     colourMenu.addSeparator();
3030     colourMenu.add(noColourmenuItem);
3031     colourMenu.add(clustalColour);
3032     colourMenu.add(BLOSUM62Colour);
3033     colourMenu.add(PIDColour);
3034     colourMenu.add(zappoColour);
3035     colourMenu.add(taylorColour);
3036     colourMenu.add(hydrophobicityColour);
3037     colourMenu.add(helixColour);
3038     colourMenu.add(strandColour);
3039     colourMenu.add(turnColour);
3040     colourMenu.add(buriedColour);
3041     colourMenu.add(nucleotideColour);
3042     colourMenu.add(userDefinedColour);
3043     colourMenu.addSeparator();
3044     colourMenu.add(conservationMenuItem);
3045     colourMenu.add(modifyConservation);
3046     colourMenu.add(abovePIDThreshold);
3047     colourMenu.add(modifyPID);
3048     colourMenu.add(annotationColour);
3049     calculateMenu.add(sort);
3050     calculateMenu.add(calculate);
3051     calculateMenu.addSeparator();
3052     calculateMenu.add(pairwiseAlignmentMenuItem);
3053     calculateMenu.add(PCAMenuItem);
3054     calculateMenu.add(autoCalculate);
3055     this.add(statusBar, BorderLayout.SOUTH);
3056     pasteMenu.add(pasteNew);
3057     pasteMenu.add(pasteThis);
3058     sort.add(sortIDMenuItem);
3059     sort.add(sortLengthMenuItem);
3060     sort.add(sortByTreeMenu);
3061     sort.add(sortGroupMenuItem);
3062     sort.add(sortPairwiseMenuItem);
3063     calculate.add(averageDistanceTreeMenuItem);
3064     calculate.add(neighbourTreeMenuItem);
3065     calculate.add(avDistanceTreeBlosumMenuItem);
3066     calculate.add(njTreeBlosumMenuItem);
3067     helpMenu.add(documentation);
3068     helpMenu.add(about);
3069     menu1.add(showColumns);
3070     menu1.add(showSeqs);
3071     menu1.add(showAllHidden);
3072     menu2.add(hideColumns);
3073     menu2.add(hideSequences);
3074     menu2.add(hideAllSelection);
3075     menu2.add(hideAllButSelection);
3076     formatMenu.add(font);
3077     formatMenu.add(seqLimits);
3078     formatMenu.add(wrapMenuItem);
3079     formatMenu.add(scaleAbove);
3080     formatMenu.add(scaleLeft);
3081     formatMenu.add(scaleRight);
3082     formatMenu.add(viewBoxesMenuItem);
3083     formatMenu.add(viewTextMenuItem);
3084     formatMenu.add(colourTextMenuItem);
3085     formatMenu.add(displayNonconservedMenuItem);
3086     formatMenu.add(renderGapsMenuItem);
3087     formatMenu.add(centreColumnLabelFlag);
3088     selectMenu.add(findMenuItem);
3089     selectMenu.addSeparator();
3090     selectMenu.add(selectAllSequenceMenuItem);
3091     selectMenu.add(deselectAllSequenceMenuItem);
3092     selectMenu.add(invertSequenceMenuItem);
3093     selectMenu.add(invertColSel);
3094     selectMenu.add(grpsFromSelection);
3095     selectMenu.add(deleteGroups);
3096
3097   }
3098
3099   MenuItem featureSettings = new MenuItem();
3100
3101   CheckboxMenuItem sequenceFeatures = new CheckboxMenuItem();
3102
3103   MenuItem annotationColour = new MenuItem();
3104
3105   MenuItem invertColSel = new MenuItem();
3106
3107   Menu menu1 = new Menu();
3108
3109   MenuItem showColumns = new MenuItem();
3110
3111   MenuItem showSeqs = new MenuItem();
3112
3113   Menu menu2 = new Menu();
3114
3115   MenuItem hideColumns = new MenuItem();
3116
3117   MenuItem hideSequences = new MenuItem();
3118
3119   MenuItem hideAllButSelection = new MenuItem();
3120
3121   MenuItem hideAllSelection = new MenuItem();
3122
3123   MenuItem showAllHidden = new MenuItem();
3124
3125   Menu formatMenu = new Menu();
3126
3127   Menu selectMenu = new Menu();
3128
3129   MenuItem newView = new MenuItem();
3130
3131   /**
3132    * Attach the alignFrame panels after embedding menus, if necessary. This used
3133    * to be called setEmbedded, but is now creates the dropdown menus in a
3134    * platform independent manner to avoid OSX/Mac menu appendage daftness.
3135    * 
3136    * @param reallyEmbedded
3137    *          true to attach the view to the applet area on the page rather than
3138    *          in a new window
3139    */
3140   public void createAlignFrameWindow(boolean reallyEmbedded, String title)
3141   {
3142     if (reallyEmbedded)
3143     {
3144       // ////
3145       // Explicly build the embedded menu panel for the on-page applet
3146       //
3147       // view cannot be closed if its actually on the page
3148       fileMenu.remove(closeMenuItem);
3149       fileMenu.remove(3); // Remove Seperator
3150       embeddedMenu = makeEmbeddedPopupMenu(alignFrameMenuBar, "Arial",
3151               Font.PLAIN, 10, false); // use our own fonts.
3152       // and actually add the components to the applet area
3153       viewport.applet.setLayout(new BorderLayout());
3154       viewport.applet.add(embeddedMenu, BorderLayout.NORTH);
3155       viewport.applet.add(statusBar, BorderLayout.SOUTH);
3156       alignPanel.setSize(viewport.applet.getSize().width,
3157               viewport.applet.getSize().height - embeddedMenu.HEIGHT
3158                       - statusBar.HEIGHT);
3159       viewport.applet.add(alignPanel, BorderLayout.CENTER);
3160       final AlignFrame me = this;
3161       viewport.applet.addFocusListener(new FocusListener()
3162       {
3163         
3164         @Override
3165         public void focusLost(FocusEvent e)
3166         {
3167           if (me.viewport.applet.currentAlignFrame==me) {
3168                   me.viewport.applet.currentAlignFrame = null;
3169         }}
3170         
3171         @Override
3172         public void focusGained(FocusEvent e)
3173         {
3174           me.viewport.applet.currentAlignFrame = me;
3175         }
3176       });
3177       viewport.applet.validate();
3178     }
3179     else
3180     {
3181       // //////
3182       // test and embed menu bar if necessary.
3183       //
3184       if (embedMenuIfNeeded(alignPanel))
3185       {
3186         // adjust for status bar height too
3187         alignPanel.setSize(getSize().width, getSize().height
3188                 - statusBar.HEIGHT);
3189       }
3190       add(statusBar, BorderLayout.SOUTH);
3191       add(alignPanel, BorderLayout.CENTER);
3192       // and register with the applet so it can pass external API calls to us
3193       jalview.bin.JalviewLite.addFrame(this, title, DEFAULT_WIDTH,
3194               DEFAULT_HEIGHT);
3195     }
3196   }
3197
3198   /**
3199    * create a new binding between structures in an existing jmol viewer instance
3200    * and an alignpanel with sequences that have existing PDBFile entries. Note,
3201    * this does not open a new Jmol window, or modify the display of the
3202    * structures in the original jmol window. Note This method doesn't work
3203    * without an additional javascript library to exchange messages between the
3204    * distinct applets. See http://issues.jalview.org/browse/JAL-621
3205    * 
3206    * @param viewer
3207    *          JmolViewer instance
3208    * @param sequenceIds
3209    *          - sequence Ids to search for associations
3210    */
3211   public SequenceStructureBinding addStructureViewInstance(
3212           Object jmolviewer, String[] sequenceIds)
3213   {
3214     org.jmol.api.JmolViewer viewer = null;
3215     try
3216     {
3217       viewer = (org.jmol.api.JmolViewer) jmolviewer;
3218     } catch (ClassCastException ex)
3219     {
3220       System.err.println("Unsupported viewer object :"
3221               + jmolviewer.getClass());
3222     }
3223     if (viewer == null)
3224     {
3225       System.err.println("Can't use this object as a structure viewer:"
3226               + jmolviewer.getClass());
3227       return null;
3228     }
3229     SequenceI[] seqs = null;
3230     if (sequenceIds == null || sequenceIds.length == 0)
3231     {
3232       seqs = viewport.getAlignment().getSequencesArray();
3233     }
3234     else
3235     {
3236       Vector sqi = new Vector();
3237       AlignmentI al = viewport.getAlignment();
3238       for (int sid = 0; sid < sequenceIds.length; sid++)
3239       {
3240         SequenceI sq = al.findName(sequenceIds[sid]);
3241         if (sq != null)
3242         {
3243           sqi.addElement(sq);
3244         }
3245       }
3246       if (sqi.size() > 0)
3247       {
3248         seqs = new SequenceI[sqi.size()];
3249         for (int sid = 0, sSize = sqi.size(); sid < sSize; sid++)
3250         {
3251           seqs[sid] = (SequenceI) sqi.elementAt(sid);
3252         }
3253       }
3254       else
3255       {
3256         return null;
3257       }
3258     }
3259     ExtJmol jmv = null;
3260     // TODO: search for a jmv that involves viewer
3261     if (jmv == null)
3262     { // create a new viewer/jalview binding.
3263       jmv = new ExtJmol(viewer, alignPanel, new SequenceI[][] {seqs});
3264     }
3265     return jmv;
3266
3267   }
3268
3269   public boolean addPdbFile(String sequenceId, String pdbEntryString,
3270           String pdbFile)
3271   {
3272     SequenceI toaddpdb = viewport.getAlignment().findName(sequenceId);
3273     boolean needtoadd = false;
3274     if (toaddpdb != null)
3275     {
3276       Vector pdbe = toaddpdb.getPDBId();
3277       PDBEntry pdbentry = null;
3278       if (pdbe != null && pdbe.size() > 0)
3279       {
3280         for (int pe = 0, peSize = pdbe.size(); pe < peSize; pe++)
3281         {
3282           pdbentry = (PDBEntry) pdbe.elementAt(pe);
3283           if (!pdbentry.getId().equals(pdbEntryString)
3284                   && !pdbentry.getFile().equals(pdbFile))
3285           {
3286             pdbentry = null;
3287           }
3288           else
3289           {
3290             continue;
3291           }
3292         }
3293       }
3294       if (pdbentry == null)
3295       {
3296         pdbentry = new PDBEntry();
3297         pdbentry.setId(pdbEntryString);
3298         pdbentry.setFile(pdbFile);
3299         needtoadd = true; // add this new entry to sequence.
3300       }
3301       // resolve data source
3302       // TODO: this code should be a refactored to an io package
3303       String protocol = AppletFormatAdapter.resolveProtocol(pdbFile, "PDB");
3304       if (protocol == null)
3305       {
3306         return false;
3307       }
3308       if (needtoadd)
3309       {
3310         // make a note of the access mode and add
3311         if (pdbentry.getProperty() == null)
3312         {
3313           pdbentry.setProperty(new Hashtable());
3314         }
3315         pdbentry.getProperty().put("protocol", protocol);
3316         toaddpdb.addPDBId(pdbentry);
3317       }
3318     }
3319     return true;
3320   }
3321
3322   private Object[] cleanSeqChainArrays(SequenceI[] seqs, String[] chains)
3323   {
3324     if (seqs != null)
3325     {
3326       Vector sequences = new Vector();
3327       for (int i = 0; i < seqs.length; i++)
3328       {
3329         if (seqs[i] != null)
3330         {
3331           sequences.addElement(new Object[]
3332           { seqs[i], (chains != null) ? chains[i] : null });
3333         }
3334       }
3335       seqs = new SequenceI[sequences.size()];
3336       chains = new String[sequences.size()];
3337       for (int i = 0, isize = sequences.size(); i < isize; i++)
3338       {
3339         Object[] oj = (Object[]) sequences.elementAt(i);
3340
3341         seqs[i] = (SequenceI) oj[0];
3342         chains[i] = (String) oj[1];
3343       }
3344     }
3345     return new Object[]
3346     { seqs, chains };
3347
3348   }
3349
3350   public void newStructureView(JalviewLite applet, PDBEntry pdb,
3351           SequenceI[] seqs, String[] chains, String protocol)
3352   {
3353     // Scrub any null sequences from the array
3354     Object[] sqch = cleanSeqChainArrays(seqs, chains);
3355     seqs = (SequenceI[]) sqch[0];
3356     chains = (String[]) sqch[1];
3357     if (seqs == null || seqs.length == 0)
3358     {
3359       System.err
3360               .println("JalviewLite.AlignFrame:newStructureView: No sequence to bind structure to.");
3361     }
3362     if (protocol == null || protocol.trim().length() == 0
3363             || protocol.equals("null"))
3364     {
3365       protocol = (String) pdb.getProperty().get("protocol");
3366       if (protocol == null)
3367       {
3368         System.err.println("Couldn't work out protocol to open structure: "
3369                 + pdb.getId());
3370         return;
3371       }
3372     }
3373     if (applet.isAlignPdbStructures() && applet.jmolAvailable)
3374     {
3375       // can only do alignments with Jmol
3376       // find the last jmol window assigned to this alignment
3377       jalview.appletgui.AppletJmol ajm = null, tajm;
3378       Vector jmols = applet
3379               .getAppletWindow(jalview.appletgui.AppletJmol.class);
3380       for (int i = 0, iSize = jmols.size(); i < iSize; i++)
3381       {
3382         tajm = (jalview.appletgui.AppletJmol) jmols.elementAt(i);
3383         if (tajm.ap.alignFrame == this)
3384         {
3385           ajm = tajm;
3386           break;
3387         }
3388       }
3389       if (ajm != null)
3390       {
3391         System.err
3392                 .println("Incremental adding and aligning structure to existing Jmol view not yet implemented.");
3393         // try and add the pdb structure
3394         // ajm.addS
3395         ajm = null;
3396       }
3397     }
3398     // otherwise, create a new window
3399     if (applet.jmolAvailable)
3400     {
3401       new jalview.appletgui.AppletJmol(pdb, seqs, chains, alignPanel,
3402               protocol);
3403       applet.lastFrameX += 40;
3404       applet.lastFrameY += 40;
3405     }
3406     else
3407     {
3408       new MCview.AppletPDBViewer(pdb, seqs, chains, alignPanel, protocol);
3409     }
3410
3411   }
3412
3413   public void alignedStructureView(JalviewLite applet, PDBEntry[] pdb,
3414           SequenceI[][] seqs, String[][] chains, String[] protocols)
3415   {
3416     // TODO Auto-generated method stub
3417     System.err.println("Aligned Structure View: Not yet implemented.");
3418   }
3419
3420   /**
3421    * modify the current selection, providing the user has not made a selection already.
3422    * @param sel - sequences from this alignment 
3423    * @param csel - columns to be selected on the alignment
3424    */
3425   public void select(SequenceGroup sel, ColumnSelection csel)
3426   {
3427     alignPanel.seqPanel.selection(sel, csel, null);
3428   }
3429 }