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