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