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