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