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