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