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