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