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