b281767cccb65d502338fe9ef8ec9e67eb8f8429
[jalview.git] / src / jalview / gui / AlignFrame.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Softwarechang
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.gui;
20
21 import java.beans.*;
22 import java.io.*;
23 import java.util.*;
24
25 import java.awt.*;
26 import java.awt.datatransfer.*;
27 import java.awt.dnd.*;
28 import java.awt.event.*;
29 import java.awt.print.*;
30 import javax.swing.*;
31
32 import jalview.analysis.*;
33 import jalview.commands.*;
34 import jalview.datamodel.*;
35 import jalview.io.*;
36 import jalview.jbgui.*;
37 import jalview.schemes.*;
38 import jalview.ws.*;
39
40 /**
41  * DOCUMENT ME!
42  *
43  * @author $author$
44  * @version $Revision$
45  */
46 public class AlignFrame
47     extends GAlignFrame implements DropTargetListener
48 {
49   /** DOCUMENT ME!! */
50   public static final int DEFAULT_WIDTH = 700;
51
52   /** DOCUMENT ME!! */
53   public static final int DEFAULT_HEIGHT = 500;
54   public AlignmentPanel alignPanel;
55
56   AlignViewport viewport;
57
58   Vector alignPanels = new Vector();
59
60   /** DOCUMENT ME!! */
61   String currentFileFormat = null;
62
63   String fileName = null;
64
65   /**
66    * Creates a new AlignFrame object.
67    *
68    * @param al DOCUMENT ME!
69    */
70   public AlignFrame(AlignmentI al, int width, int height)
71   {
72     this(al, null, width, height);
73   }
74
75   /**
76    * new alignment window with hidden columns
77    * @param al AlignmentI
78    * @param hiddenColumns ColumnSelection or null
79    */
80   public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
81                     int width, int height)
82   {
83     this.setSize(width, height);
84     viewport = new AlignViewport(al, hiddenColumns);
85
86     alignPanel = new AlignmentPanel(this, viewport);
87
88     if (al.getDataset() == null)
89     {
90       al.setDataset(null);
91     }
92
93     addAlignmentPanel(alignPanel, true);
94     init();
95   }
96
97   /**
98    * Make a new AlignFrame from exisiting alignmentPanels
99    * @param ap AlignmentPanel
100    * @param av AlignViewport
101    */
102   public AlignFrame(AlignmentPanel ap)
103   {
104     viewport = ap.av;
105     alignPanel = ap;
106     addAlignmentPanel(ap, false);
107     init();
108   }
109
110   void init()
111   {
112     this.setDropTarget(new java.awt.dnd.DropTarget(this, this));
113
114     if (viewport.conservation == null)
115     {
116       BLOSUM62Colour.setEnabled(false);
117       conservationMenuItem.setEnabled(false);
118       modifyConservation.setEnabled(false);
119       //  PIDColour.setEnabled(false);
120       //  abovePIDThreshold.setEnabled(false);
121       //  modifyPID.setEnabled(false);
122     }
123
124     String sortby = jalview.bin.Cache.getDefault("SORT_ALIGNMENT", "No sort");
125
126     if (sortby.equals("Id"))
127     {
128       sortIDMenuItem_actionPerformed(null);
129     }
130     else if (sortby.equals("Pairwise Identity"))
131     {
132       sortPairwiseMenuItem_actionPerformed(null);
133     }
134
135     if (Desktop.desktop != null)
136     {
137       addServiceListeners();
138       setGUINucleotide(viewport.alignment.isNucleotide());
139     }
140
141     setMenusFromViewport(viewport);
142
143     if (viewport.wrapAlignment)
144     {
145       wrapMenuItem_actionPerformed(null);
146     }
147
148     addKeyListener();
149
150   }
151
152   public void setFileName(String file, String format)
153   {
154     fileName = file;
155     currentFileFormat = format;
156     reload.setEnabled(true);
157   }
158
159   void addKeyListener()
160   {
161     addKeyListener(new KeyAdapter()
162     {
163       public void keyPressed(KeyEvent evt)
164       {
165         if (viewport.cursorMode
166             && evt.getKeyCode() >= KeyEvent.VK_0
167             && evt.getKeyCode() <= KeyEvent.VK_9)
168         {
169           alignPanel.seqPanel.numberPressed(evt.getKeyChar());
170         }
171
172         switch (evt.getKeyCode())
173         {
174
175           case 27: // escape key
176             deselectAllSequenceMenuItem_actionPerformed(null);
177
178             break;
179
180           case KeyEvent.VK_DOWN:
181             if (viewport.cursorMode)
182             {
183               alignPanel.seqPanel.moveCursor(0, 1);
184             }
185             else
186             {
187               moveSelectedSequences(false);
188             }
189             break;
190
191           case KeyEvent.VK_UP:
192             if (viewport.cursorMode)
193             {
194               alignPanel.seqPanel.moveCursor(0, -1);
195             }
196             else
197             {
198               moveSelectedSequences(true);
199             }
200             break;
201
202           case KeyEvent.VK_LEFT:
203             if (viewport.cursorMode)
204             {
205               alignPanel.seqPanel.moveCursor( -1, 0);
206             }
207             break;
208
209           case KeyEvent.VK_RIGHT:
210             if (viewport.cursorMode)
211             {
212               alignPanel.seqPanel.moveCursor(1, 0);
213             }
214             break;
215
216           case KeyEvent.VK_SPACE:
217             if (viewport.cursorMode)
218             {
219               alignPanel.seqPanel.insertGapAtCursor(evt.isControlDown()
220                   || evt.isShiftDown()
221                   || evt.isAltDown());
222             }
223             break;
224
225           case KeyEvent.VK_DELETE:
226           case KeyEvent.VK_BACK_SPACE:
227             if (!viewport.cursorMode)
228             {
229               cut_actionPerformed(null);
230             }
231             else
232             {
233               alignPanel.seqPanel.deleteGapAtCursor(evt.isControlDown()
234                   || evt.isShiftDown()
235                   || evt.isAltDown());
236             }
237
238             break;
239
240           case KeyEvent.VK_S:
241             if (viewport.cursorMode)
242             {
243               alignPanel.seqPanel.setCursorRow();
244             }
245             break;
246           case KeyEvent.VK_C:
247             if (viewport.cursorMode && !evt.isControlDown())
248             {
249               alignPanel.seqPanel.setCursorColumn();
250             }
251             break;
252           case KeyEvent.VK_P:
253             if (viewport.cursorMode)
254             {
255               alignPanel.seqPanel.setCursorPosition();
256             }
257             break;
258
259           case KeyEvent.VK_ENTER:
260           case KeyEvent.VK_COMMA:
261             if (viewport.cursorMode)
262             {
263               alignPanel.seqPanel.setCursorRowAndColumn();
264             }
265             break;
266
267           case KeyEvent.VK_Q:
268             if (viewport.cursorMode)
269             {
270               alignPanel.seqPanel.setSelectionAreaAtCursor(true);
271             }
272             break;
273           case KeyEvent.VK_M:
274             if (viewport.cursorMode)
275             {
276               alignPanel.seqPanel.setSelectionAreaAtCursor(false);
277             }
278             break;
279
280           case KeyEvent.VK_F2:
281             viewport.cursorMode = !viewport.cursorMode;
282             statusBar.setText("Keyboard editing mode is " +
283                               (viewport.cursorMode ? "on" : "off"));
284             if (viewport.cursorMode)
285             {
286               alignPanel.seqPanel.seqCanvas.cursorX = viewport.startRes;
287               alignPanel.seqPanel.seqCanvas.cursorY = viewport.startSeq;
288             }
289             alignPanel.seqPanel.seqCanvas.repaint();
290             break;
291
292           case KeyEvent.VK_F1:
293             try
294             {
295               ClassLoader cl = jalview.gui.Desktop.class.getClassLoader();
296               java.net.URL url = javax.help.HelpSet.findHelpSet(cl, "help/help");
297               javax.help.HelpSet hs = new javax.help.HelpSet(cl, url);
298
299               javax.help.HelpBroker hb = hs.createHelpBroker();
300               hb.setCurrentID("home");
301               hb.setDisplayed(true);
302             }
303             catch (Exception ex)
304             {
305               ex.printStackTrace();
306             }
307             break
308                 ;
309           case KeyEvent.VK_H:
310           {
311             boolean toggleSeqs = !evt.isControlDown();
312             boolean toggleCols = !evt.isShiftDown();
313
314             boolean hide = false;
315
316             SequenceGroup sg = viewport.getSelectionGroup();
317             if (toggleSeqs)
318             {
319               if (sg != null && sg.getSize() != viewport.alignment.getHeight())
320               {
321                 hideSelSequences_actionPerformed(null);
322                 hide = true;
323               }
324               else if (! (toggleCols &&
325                           viewport.colSel.getSelected().size() > 0))
326               {
327                 showAllSeqs_actionPerformed(null);
328               }
329             }
330
331             if (toggleCols)
332             {
333               if (viewport.colSel.getSelected().size() > 0)
334               {
335                 hideSelColumns_actionPerformed(null);
336                 if (!toggleSeqs)
337                 {
338                   viewport.selectionGroup = sg;
339                 }
340               }
341               else if (!hide)
342               {
343                 showAllColumns_actionPerformed(null);
344               }
345             }
346             break;
347           }
348           case KeyEvent.VK_PAGE_UP:
349             if (viewport.wrapAlignment)
350             {
351               alignPanel.scrollUp(true);
352             }
353             else
354             {
355               alignPanel.setScrollValues(viewport.startRes,
356                                          viewport.startSeq
357                                          - viewport.endSeq + viewport.startSeq);
358             }
359             break;
360           case KeyEvent.VK_PAGE_DOWN:
361             if (viewport.wrapAlignment)
362             {
363               alignPanel.scrollUp(false);
364             }
365             else
366             {
367               alignPanel.setScrollValues(viewport.startRes,
368                                          viewport.startSeq
369                                          + viewport.endSeq - viewport.startSeq);
370             }
371             break;
372         }
373       }
374     });
375   }
376
377   public void addAlignmentPanel(final AlignmentPanel ap,
378                                 boolean newPanel)
379   {
380     ap.alignFrame = this;
381
382     alignPanels.addElement(ap);
383
384     PaintRefresher.Register(ap, ap.av.getSequenceSetId());
385
386     int aSize = alignPanels.size();
387
388     tabbedPane.setVisible(aSize > 1 || ap.av.viewName != null);
389
390     if (aSize == 1 && ap.av.viewName == null)
391     {
392       this.getContentPane().add(ap, BorderLayout.CENTER);
393     }
394     else
395     {
396       if (aSize == 2)
397       {
398         setInitialTabVisible();
399       }
400
401       expandViews.setEnabled(true);
402       gatherViews.setEnabled(true);
403       tabbedPane.addTab(ap.av.viewName, ap);
404
405       ap.setVisible(false);
406     }
407
408     if (newPanel)
409     {
410       if (ap.av.padGaps)
411       {
412         ap.av.alignment.padGaps();
413       }
414       ap.av.updateConservation(ap);
415       ap.av.updateConsensus(ap);
416     }
417   }
418
419   public void setInitialTabVisible()
420   {
421     expandViews.setEnabled(true);
422     gatherViews.setEnabled(true);
423     tabbedPane.setVisible(true);
424     AlignmentPanel first = (AlignmentPanel) alignPanels.firstElement();
425     tabbedPane.addTab(first.av.viewName, first);
426     this.getContentPane().add(tabbedPane, BorderLayout.CENTER);
427   }
428
429   public AlignViewport getViewport()
430   {
431     return viewport;
432   }
433
434   /* Set up intrinsic listeners for dynamically generated GUI bits. */
435   private void addServiceListeners()
436   {
437     final java.beans.PropertyChangeListener thisListener;
438     // Do this once to get current state
439     BuildWebServiceMenu();
440     Desktop.discoverer.addPropertyChangeListener(
441         thisListener = new java.beans.PropertyChangeListener()
442     {
443       public void propertyChange(PropertyChangeEvent evt)
444       {
445         // System.out.println("Discoverer property change.");
446         if (evt.getPropertyName().equals("services"))
447         {
448           // System.out.println("Rebuilding web service menu");
449           BuildWebServiceMenu();
450         }
451       }
452     });
453
454     addInternalFrameListener(new javax.swing.event.
455                              InternalFrameAdapter()
456     {
457       public void internalFrameClosed(
458           javax.swing.event.InternalFrameEvent evt)
459       {
460         // System.out.println("deregistering discoverer listener");
461         Desktop.discoverer.removePropertyChangeListener(thisListener);
462         closeMenuItem_actionPerformed(true);
463       }
464       ;
465     });
466   }
467
468   public void setGUINucleotide(boolean nucleotide)
469   {
470     showTranslation.setVisible(nucleotide);
471     conservationMenuItem.setEnabled(!nucleotide);
472     modifyConservation.setEnabled(!nucleotide);
473
474     //Remember AlignFrame always starts as protein
475     if (!nucleotide)
476     {
477       calculateMenu.remove(calculateMenu.getItemCount() - 2);
478     }
479   }
480
481   /**
482    * Need to call this method when tabs are selected for multiple views,
483    * or when loading from Jalview2XML.java
484    * @param av AlignViewport
485    */
486   void setMenusFromViewport(AlignViewport av)
487   {
488     padGapsMenuitem.setSelected(av.padGaps);
489     colourTextMenuItem.setSelected(av.showColourText);
490     abovePIDThreshold.setSelected(av.getAbovePIDThreshold());
491     conservationMenuItem.setSelected(av.getConservationSelected());
492     seqLimits.setSelected(av.getShowJVSuffix());
493     idRightAlign.setSelected(av.rightAlignIds);
494     renderGapsMenuItem.setSelected(av.renderGaps);
495     wrapMenuItem.setSelected(av.wrapAlignment);
496     scaleAbove.setVisible(av.wrapAlignment);
497     scaleLeft.setVisible(av.wrapAlignment);
498     scaleRight.setVisible(av.wrapAlignment);
499     annotationPanelMenuItem.setState(av.showAnnotation);
500     viewBoxesMenuItem.setSelected(av.showBoxes);
501     viewTextMenuItem.setSelected(av.showText);
502
503     setColourSelected(ColourSchemeProperty.
504                       getColourName(av.getGlobalColourScheme()));
505
506     showSeqFeatures.setSelected(av.showSequenceFeatures);
507     hiddenMarkers.setState(av.showHiddenMarkers);
508     applyToAllGroups.setState(av.colourAppliesToAllGroups);
509
510     updateEditMenuBar();
511   }
512
513   Hashtable progressBars;
514   public void setProgressBar(String message, long id)
515   {
516     if (progressBars == null)
517     {
518       progressBars = new Hashtable();
519     }
520
521     JPanel progressPanel;
522     GridLayout layout = (GridLayout) statusPanel.getLayout();
523     if (progressBars.get(new Long(id)) != null)
524     {
525       progressPanel = (JPanel) progressBars.get(new Long(id));
526       statusPanel.remove(progressPanel);
527       progressBars.remove(progressPanel);
528       progressPanel = null;
529       if (message != null)
530       {
531         statusBar.setText(message);
532       }
533
534       layout.setRows(layout.getRows() - 1);
535     }
536     else
537     {
538       progressPanel = new JPanel(new BorderLayout(10, 5));
539
540       JProgressBar progressBar = new JProgressBar();
541       progressBar.setIndeterminate(true);
542
543       progressPanel.add(new JLabel(message), BorderLayout.WEST);
544       progressPanel.add(progressBar, BorderLayout.CENTER);
545
546       layout.setRows(layout.getRows() + 1);
547       statusPanel.add(progressPanel);
548
549       progressBars.put(new Long(id), progressPanel);
550     }
551
552     validate();
553   }
554
555   /*
556    Added so Castor Mapping file can obtain Jalview Version
557    */
558   public String getVersion()
559   {
560     return jalview.bin.Cache.getProperty("VERSION");
561   }
562
563   public FeatureRenderer getFeatureRenderer()
564   {
565     return alignPanel.seqPanel.seqCanvas.getFeatureRenderer();
566   }
567
568   public void fetchSequence_actionPerformed(ActionEvent e)
569   {
570     new SequenceFetcher(this);
571   }
572
573   public void addFromFile_actionPerformed(ActionEvent e)
574   {
575     Desktop.instance.inputLocalFileMenuItem_actionPerformed(viewport);
576   }
577
578   public void reload_actionPerformed(ActionEvent e)
579   {
580     if (fileName != null)
581     {
582       if (currentFileFormat.equals("Jalview"))
583       {
584         JInternalFrame[] frames = Desktop.desktop.getAllFrames();
585         for (int i = 0; i < frames.length; i++)
586         {
587           if (frames[i] instanceof AlignFrame
588               && frames[i] != this
589               && ( (AlignFrame) frames[i]).fileName.equals(fileName))
590           {
591             try
592             {
593               frames[i].setSelected(true);
594               Desktop.instance.closeAssociatedWindows();
595             }
596             catch (java.beans.PropertyVetoException ex)
597             {}
598           }
599
600         }
601         Desktop.instance.closeAssociatedWindows();
602
603       }
604       else
605       {
606         Rectangle bounds = this.getBounds();
607
608         FileLoader loader = new FileLoader();
609         String protocol = fileName.startsWith("http:") ? "URL" : "File";
610         AlignFrame newframe =
611             loader.LoadFileWaitTillLoaded(fileName, protocol, currentFileFormat);
612
613         newframe.setBounds(bounds);
614
615         this.closeMenuItem_actionPerformed(true);
616       }
617     }
618   }
619
620   public void addFromText_actionPerformed(ActionEvent e)
621   {
622     Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport);
623   }
624
625   public void addFromURL_actionPerformed(ActionEvent e)
626   {
627     Desktop.instance.inputURLMenuItem_actionPerformed(viewport);
628   }
629
630   public void save_actionPerformed(ActionEvent e)
631   {
632     if (fileName == null
633         || currentFileFormat == null
634         || fileName.startsWith("http")
635         )
636     {
637       saveAs_actionPerformed(null);
638     }
639     else
640     {
641       saveAlignment(fileName, currentFileFormat);
642     }
643   }
644
645   /**
646    * DOCUMENT ME!
647    *
648    * @param e DOCUMENT ME!
649    */
650   public void saveAs_actionPerformed(ActionEvent e)
651   {
652     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
653         getProperty("LAST_DIRECTORY"),
654         new String[]
655         {"fa, fasta, fastq", "aln", "pfam", "msf", "pir", "blc", "jar"},
656         new String[]
657         {"Fasta", "Clustal", "PFAM", "MSF", "PIR", "BLC", "Jalview"},
658         currentFileFormat,
659         false);
660
661     chooser.setFileView(new JalviewFileView());
662     chooser.setDialogTitle("Save Alignment to file");
663     chooser.setToolTipText("Save");
664
665     int value = chooser.showSaveDialog(this);
666
667     if (value == JalviewFileChooser.APPROVE_OPTION)
668     {
669       currentFileFormat = chooser.getSelectedFormat();
670       if (currentFileFormat == null)
671       {
672         JOptionPane.showInternalMessageDialog(Desktop.desktop,
673                                               "You must select a file format before saving!",
674                                               "File format not specified",
675                                               JOptionPane.WARNING_MESSAGE);
676         value = chooser.showSaveDialog(this);
677         return;
678       }
679
680       fileName = chooser.getSelectedFile().getPath();
681
682       jalview.bin.Cache.setProperty("DEFAULT_FILE_FORMAT",
683                                     currentFileFormat);
684
685       jalview.bin.Cache.setProperty("LAST_DIRECTORY", fileName);
686
687       saveAlignment(fileName, currentFileFormat);
688     }
689   }
690
691   public boolean saveAlignment(String file, String format)
692   {
693     boolean success = true;
694
695     if (format.equalsIgnoreCase("Jalview"))
696     {
697       String shortName = title;
698
699       if (shortName.indexOf(java.io.File.separatorChar) > -1)
700       {
701         shortName = shortName.substring(shortName.lastIndexOf(
702             java.io.File.separatorChar) + 1);
703       }
704
705       success = new Jalview2XML().SaveAlignment(this, file, shortName);
706
707       statusBar.setText("Successfully saved to file: "
708                         + fileName + " in "
709                         + format + " format.");
710
711     }
712     else
713     {
714
715       String[] omitHidden = null;
716
717       if (viewport.hasHiddenColumns)
718       {
719         int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop,
720             "The Alignment contains hidden columns."
721             + "\nDo you want to save only the visible alignment?",
722             "Save / Omit Hidden Columns",
723             JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
724
725         if (reply == JOptionPane.YES_OPTION)
726         {
727           omitHidden = viewport.getViewAsString(false);
728         }
729       }
730
731       String output = new FormatAdapter().formatSequences(
732           format,
733           viewport.alignment.getSequencesArray(),
734           omitHidden);
735
736       if (output == null)
737       {
738         success = false;
739       }
740       else
741       {
742         try
743         {
744           java.io.PrintWriter out = new java.io.PrintWriter(
745               new java.io.FileWriter(file));
746
747           out.print(output);
748           out.close();
749           this.setTitle(file);
750           statusBar.setText("Successfully saved to file: "
751                             + fileName + " in "
752                             + format + " format.");
753         }
754         catch (Exception ex)
755         {
756           success = false;
757           ex.printStackTrace();
758         }
759       }
760     }
761
762     if (!success)
763     {
764       JOptionPane.showInternalMessageDialog(
765           this, "Couldn't save file: " + fileName,
766           "Error Saving File",
767           JOptionPane.WARNING_MESSAGE);
768     }
769
770     return success;
771   }
772
773   /**
774    * DOCUMENT ME!
775    *
776    * @param e DOCUMENT ME!
777    */
778   protected void outputText_actionPerformed(ActionEvent e)
779   {
780     String[] omitHidden = null;
781
782     if (viewport.hasHiddenColumns)
783     {
784       int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop,
785           "The Alignment contains hidden columns."
786           + "\nDo you want to output only the visible alignment?",
787           "Save / Omit Hidden Columns",
788           JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
789
790       if (reply == JOptionPane.YES_OPTION)
791       {
792         omitHidden = viewport.getViewAsString(false);
793       }
794     }
795
796     CutAndPasteTransfer cap = new CutAndPasteTransfer();
797     cap.setForInput(null);
798     Desktop.addInternalFrame(cap,
799                              "Alignment output - " + e.getActionCommand(), 600,
800                              500);
801
802     cap.setText(new FormatAdapter().formatSequences(
803         e.getActionCommand(),
804         viewport.alignment.getSequencesArray(),
805         omitHidden));
806   }
807
808   /**
809    * DOCUMENT ME!
810    *
811    * @param e DOCUMENT ME!
812    */
813   protected void htmlMenuItem_actionPerformed(ActionEvent e)
814   {
815     new HTMLOutput(viewport,
816                    alignPanel.seqPanel.seqCanvas.getSequenceRenderer(),
817                    alignPanel.seqPanel.seqCanvas.getFeatureRenderer());
818   }
819
820   public void createImageMap(File file, String image)
821   {
822     alignPanel.makePNGImageMap(file, image);
823   }
824
825   /**
826    * DOCUMENT ME!
827    *
828    * @param e DOCUMENT ME!
829    */
830   public void createPNG(File f)
831   {
832     alignPanel.makePNG(f);
833   }
834
835   /**
836    * DOCUMENT ME!
837    *
838    * @param e DOCUMENT ME!
839    */
840   public void createEPS(File f)
841   {
842     alignPanel.makeEPS(f);
843   }
844
845   public void pageSetup_actionPerformed(ActionEvent e)
846   {
847     PrinterJob printJob = PrinterJob.getPrinterJob();
848     PrintThread.pf = printJob.pageDialog(printJob.defaultPage());
849   }
850
851   /**
852    * DOCUMENT ME!
853    *
854    * @param e DOCUMENT ME!
855    */
856   public void printMenuItem_actionPerformed(ActionEvent e)
857   {
858     //Putting in a thread avoids Swing painting problems
859     PrintThread thread = new PrintThread(alignPanel);
860     thread.start();
861   }
862
863   public void exportFeatures_actionPerformed(ActionEvent e)
864   {
865     new AnnotationExporter().exportFeatures(alignPanel);
866   }
867
868   public void exportAnnotations_actionPerformed(ActionEvent e)
869   {
870     new AnnotationExporter().exportAnnotations(
871         alignPanel,
872         viewport.showAnnotation ? viewport.alignment.getAlignmentAnnotation() : null,
873         viewport.alignment.getGroups()
874         );
875   }
876
877   public void associatedData_actionPerformed(ActionEvent e)
878   {
879     // Pick the tree file
880     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
881         getProperty(
882             "LAST_DIRECTORY"));
883     chooser.setFileView(new JalviewFileView());
884     chooser.setDialogTitle("Load Jalview Annotations or Features File");
885     chooser.setToolTipText("Load Jalview Annotations / Features file");
886
887     int value = chooser.showOpenDialog(null);
888
889     if (value == JalviewFileChooser.APPROVE_OPTION)
890     {
891       String choice = chooser.getSelectedFile().getPath();
892       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
893       loadJalviewDataFile(choice);
894     }
895
896   }
897
898   /**
899    * DOCUMENT ME!
900    *
901    * @param e DOCUMENT ME!
902    */
903   public void closeMenuItem_actionPerformed(boolean closeAllTabs)
904   {
905     if (alignPanels != null && alignPanels.size() < 2)
906     {
907       closeAllTabs = true;
908     }
909
910     try
911     {
912       if (alignPanels != null)
913       {
914         if (closeAllTabs)
915         {
916           for (int i = 0; i < alignPanels.size(); i++)
917           {
918             AlignmentPanel ap = (AlignmentPanel) alignPanels.elementAt(i);
919             PaintRefresher.RemoveComponent(ap.seqPanel.seqCanvas);
920             PaintRefresher.RemoveComponent(ap.idPanel.idCanvas);
921             PaintRefresher.RemoveComponent(ap);
922           }
923         }
924         else
925         {
926           int index = tabbedPane.getSelectedIndex();
927
928           alignPanels.removeElement(alignPanel);
929           PaintRefresher.RemoveComponent(alignPanel.seqPanel.seqCanvas);
930           PaintRefresher.RemoveComponent(alignPanel.idPanel.idCanvas);
931           PaintRefresher.RemoveComponent(alignPanel);
932           alignPanel = null;
933           viewport = null;
934
935           tabbedPane.removeTabAt(index);
936           tabbedPane.validate();
937
938           if (index == tabbedPane.getTabCount())
939           {
940             index--;
941           }
942
943           this.tabSelectionChanged(index);
944         }
945       }
946
947       if (closeAllTabs)
948       {
949         this.setClosed(true);
950       }
951     }
952     catch (Exception ex)
953     {
954       ex.printStackTrace();
955     }
956   }
957
958   /**
959    * DOCUMENT ME!
960    */
961   void updateEditMenuBar()
962   {
963
964     if (viewport.historyList.size() > 0)
965     {
966       undoMenuItem.setEnabled(true);
967       CommandI command = (CommandI) viewport.historyList.peek();
968       undoMenuItem.setText("Undo " + command.getDescription());
969     }
970     else
971     {
972       undoMenuItem.setEnabled(false);
973       undoMenuItem.setText("Undo");
974     }
975
976     if (viewport.redoList.size() > 0)
977     {
978       redoMenuItem.setEnabled(true);
979
980       CommandI command = (CommandI) viewport.redoList.peek();
981       redoMenuItem.setText("Redo " + command.getDescription());
982     }
983     else
984     {
985       redoMenuItem.setEnabled(false);
986       redoMenuItem.setText("Redo");
987     }
988   }
989
990   public void addHistoryItem(CommandI command)
991   {
992     if (command.getSize() > 0)
993     {
994       viewport.historyList.push(command);
995       viewport.redoList.clear();
996       updateEditMenuBar();
997       viewport.hasHiddenColumns = viewport.colSel.getHiddenColumns() != null;
998     }
999   }
1000
1001   /**
1002    * DOCUMENT ME!
1003    *
1004    * @param e DOCUMENT ME!
1005    */
1006   protected void undoMenuItem_actionPerformed(ActionEvent e)
1007   {
1008     CommandI command = (CommandI) viewport.historyList.pop();
1009     viewport.redoList.push(command);
1010     command.undoCommand();
1011
1012     AlignViewport originalSource = getOriginatingSource(command);
1013     updateEditMenuBar();
1014
1015     if (originalSource != null)
1016     {
1017       originalSource.hasHiddenColumns = viewport.colSel.getHiddenColumns() != null;
1018       originalSource.firePropertyChange("alignment",
1019                                         null,
1020                                         originalSource.alignment.getSequences());
1021     }
1022   }
1023
1024   /**
1025    * DOCUMENT ME!
1026    *
1027    * @param e DOCUMENT ME!
1028    */
1029   protected void redoMenuItem_actionPerformed(ActionEvent e)
1030   {
1031     if (viewport.redoList.size() < 1)
1032     {
1033       return;
1034     }
1035
1036     CommandI command = (CommandI) viewport.redoList.pop();
1037     viewport.historyList.push(command);
1038     command.doCommand();
1039
1040     AlignViewport originalSource = getOriginatingSource(command);
1041     updateEditMenuBar();
1042
1043     if (originalSource != null)
1044     {
1045       originalSource.hasHiddenColumns = viewport.colSel.getHiddenColumns() != null;
1046       originalSource.firePropertyChange("alignment",
1047                                         null,
1048                                         originalSource.alignment.getSequences());
1049     }
1050   }
1051
1052   AlignViewport getOriginatingSource(CommandI command)
1053   {
1054     AlignViewport originalSource = null;
1055     //For sequence removal and addition, we need to fire
1056     //the property change event FROM the viewport where the
1057     //original alignment was altered
1058     AlignmentI al = null;
1059     if (command instanceof EditCommand)
1060     {
1061       EditCommand editCommand = (EditCommand) command;
1062       al = editCommand.getAlignment();
1063       Vector comps = (Vector) PaintRefresher.components
1064           .get(viewport.getSequenceSetId());
1065
1066       for (int i = 0; i < comps.size(); i++)
1067       {
1068         if (comps.elementAt(i) instanceof AlignmentPanel)
1069         {
1070           if (al == ( (AlignmentPanel) comps.elementAt(i)).av.alignment)
1071           {
1072             originalSource = ( (AlignmentPanel) comps.elementAt(i)).av;
1073             break;
1074           }
1075         }
1076       }
1077     }
1078
1079     if (originalSource == null)
1080     {
1081       //The original view is closed, we must validate
1082       //the current view against the closed view first
1083       if (al != null)
1084       {
1085         PaintRefresher.validateSequences(al, viewport.alignment);
1086       }
1087
1088       originalSource = viewport;
1089     }
1090
1091     return originalSource;
1092   }
1093
1094   /**
1095    * DOCUMENT ME!
1096    *
1097    * @param up DOCUMENT ME!
1098    */
1099   public void moveSelectedSequences(boolean up)
1100   {
1101     SequenceGroup sg = viewport.getSelectionGroup();
1102
1103     if (sg == null)
1104     {
1105       return;
1106     }
1107
1108     if (up)
1109     {
1110       for (int i = 1; i < viewport.alignment.getHeight(); i++)
1111       {
1112         SequenceI seq = viewport.alignment.getSequenceAt(i);
1113
1114         if (!sg.getSequences(null).contains(seq))
1115         {
1116           continue;
1117         }
1118
1119         SequenceI temp = viewport.alignment.getSequenceAt(i - 1);
1120
1121         if (sg.getSequences(null).contains(temp))
1122         {
1123           continue;
1124         }
1125
1126         viewport.alignment.getSequences().setElementAt(temp, i);
1127         viewport.alignment.getSequences().setElementAt(seq, i - 1);
1128       }
1129     }
1130     else
1131     {
1132       for (int i = viewport.alignment.getHeight() - 2; i > -1; i--)
1133       {
1134         SequenceI seq = viewport.alignment.getSequenceAt(i);
1135
1136         if (!sg.getSequences(null).contains(seq))
1137         {
1138           continue;
1139         }
1140
1141         SequenceI temp = viewport.alignment.getSequenceAt(i + 1);
1142
1143         if (sg.getSequences(null).contains(temp))
1144         {
1145           continue;
1146         }
1147
1148         viewport.alignment.getSequences().setElementAt(temp, i);
1149         viewport.alignment.getSequences().setElementAt(seq, i + 1);
1150       }
1151     }
1152
1153     alignPanel.repaint();
1154   }
1155
1156   /**
1157    * DOCUMENT ME!
1158    *
1159    * @param e DOCUMENT ME!
1160    */
1161   protected void copy_actionPerformed(ActionEvent e)
1162   {
1163     System.gc();
1164     if (viewport.getSelectionGroup() == null)
1165     {
1166       return;
1167     }
1168
1169     SequenceI[] seqs = viewport.getSelectionAsNewSequence();
1170     String[] omitHidden = null;
1171
1172     if (viewport.hasHiddenColumns)
1173     {
1174       omitHidden = viewport.getViewAsString(true);
1175     }
1176
1177     String output = new FormatAdapter().formatSequences(
1178         "Fasta",
1179         seqs,
1180         omitHidden);
1181
1182     StringSelection ss = new StringSelection(output);
1183
1184     try
1185     {
1186       jalview.gui.Desktop.internalCopy = true;
1187       //Its really worth setting the clipboard contents
1188       //to empty before setting the large StringSelection!!
1189       Toolkit.getDefaultToolkit().getSystemClipboard()
1190           .setContents(new StringSelection(""), null);
1191
1192       Toolkit.getDefaultToolkit().getSystemClipboard()
1193           .setContents(ss, Desktop.instance);
1194     }
1195     catch (OutOfMemoryError er)
1196     {
1197       er.printStackTrace();
1198       javax.swing.SwingUtilities.invokeLater(new Runnable()
1199       {
1200         public void run()
1201         {
1202           javax.swing.JOptionPane.showInternalMessageDialog(Desktop.desktop,
1203               "Out of memory copying region!!"
1204               +
1205               "\nSee help files for increasing Java Virtual Machine memory."
1206               , "Out of memory",
1207               javax.swing.JOptionPane.WARNING_MESSAGE);
1208         }
1209       });
1210
1211       return;
1212     }
1213
1214     Vector hiddenColumns = null;
1215     if (viewport.hasHiddenColumns)
1216     {
1217       hiddenColumns = new Vector();
1218       int hiddenOffset = viewport.getSelectionGroup().getStartRes();
1219       for (int i = 0; i < viewport.getColumnSelection().getHiddenColumns().size();
1220            i++)
1221       {
1222         int[] region = (int[])
1223             viewport.getColumnSelection().getHiddenColumns().elementAt(i);
1224
1225         hiddenColumns.addElement(new int[]
1226                                  {region[0] - hiddenOffset,
1227                                  region[1] - hiddenOffset});
1228       }
1229     }
1230
1231     Desktop.jalviewClipboard = new Object[]
1232         {
1233         seqs,
1234         viewport.alignment.getDataset(),
1235         hiddenColumns};
1236     statusBar.setText("Copied " + seqs.length + " sequences to clipboard.");
1237   }
1238
1239   /**
1240    * DOCUMENT ME!
1241    *
1242    * @param e DOCUMENT ME!
1243    */
1244   protected void pasteNew_actionPerformed(ActionEvent e)
1245   {
1246     paste(true);
1247   }
1248
1249   /**
1250    * DOCUMENT ME!
1251    *
1252    * @param e DOCUMENT ME!
1253    */
1254   protected void pasteThis_actionPerformed(ActionEvent e)
1255   {
1256     paste(false);
1257   }
1258
1259   /**
1260    * DOCUMENT ME!
1261    *
1262    * @param newAlignment DOCUMENT ME!
1263    */
1264   void paste(boolean newAlignment)
1265   {
1266     try
1267     {
1268       Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
1269       Transferable contents = c.getContents(this);
1270
1271       if (contents == null)
1272       {
1273         return;
1274       }
1275
1276       String str, format;
1277       try
1278       {
1279         str = (String) contents.getTransferData(DataFlavor.stringFlavor);
1280         if (str.length() < 1)
1281         {
1282           return;
1283         }
1284
1285         format = new IdentifyFile().Identify(str, "Paste");
1286
1287       }
1288       catch (OutOfMemoryError er)
1289       {
1290         er.printStackTrace();
1291         javax.swing.SwingUtilities.invokeLater(new Runnable()
1292         {
1293           public void run()
1294           {
1295             javax.swing.JOptionPane.showInternalMessageDialog(Desktop.desktop,
1296                 "Out of memory pasting sequences!!"
1297                 +
1298                 "\nSee help files for increasing Java Virtual Machine memory."
1299                 , "Out of memory",
1300                 javax.swing.JOptionPane.WARNING_MESSAGE);
1301           }
1302         });
1303
1304         return;
1305       }
1306
1307       SequenceI[] sequences;
1308
1309       if (Desktop.jalviewClipboard != null)
1310       {
1311         // The clipboard was filled from within Jalview, we must use the sequences
1312         // And dataset from the copied alignment
1313         sequences = (SequenceI[]) Desktop.jalviewClipboard[0];
1314       }
1315       else
1316       {
1317         sequences = new FormatAdapter().readFile(str, "Paste", format).
1318             getSequencesArray();
1319       }
1320
1321       AlignmentI alignment = null;
1322
1323       if (newAlignment)
1324       {
1325         alignment = new Alignment(sequences);
1326
1327         if (Desktop.jalviewClipboard != null)
1328         {
1329           alignment.setDataset( (Alignment) Desktop.jalviewClipboard[1]);
1330         }
1331         else
1332         {
1333           alignment.setDataset(null);
1334         }
1335       }
1336       else
1337       {
1338         alignment = viewport.getAlignment();
1339
1340         //!newAlignment
1341         SequenceI[] newseqs = new SequenceI[sequences.length];
1342         for (int i = 0; i < sequences.length; i++)
1343         {
1344           newseqs[i] = new Sequence(sequences[i].getName(),
1345                                     sequences[i].getSequence(),
1346                                     sequences[i].getStart(),
1347                                     sequences[i].getEnd());
1348
1349           alignment.addSequence(newseqs[i]);
1350         }
1351
1352         /*
1353          //ADD HISTORY ITEM
1354          */
1355         addHistoryItem(new EditCommand(
1356             "Add sequences",
1357             EditCommand.PASTE,
1358             newseqs,
1359             0,
1360             alignment.getWidth(),
1361             alignment)
1362             );
1363
1364         viewport.setEndSeq(alignment.getHeight());
1365         alignment.getWidth();
1366         viewport.firePropertyChange("alignment", null, alignment.getSequences());
1367       }
1368
1369       // Add any annotations attached to sequences
1370       for (int i = 0; i < sequences.length; i++)
1371       {
1372         if (sequences[i].getAnnotation() != null)
1373         {
1374           for (int a = 0; a < sequences[i].getAnnotation().length; a++)
1375           {
1376             AlignmentAnnotation newAnnot =
1377                 new AlignmentAnnotation(
1378                     sequences[i].getAnnotation()[a].label,
1379                     sequences[i].getAnnotation()[a].description,
1380                     sequences[i].getAnnotation()[a].annotations,
1381                     sequences[i].getAnnotation()[a].graphMin,
1382                     sequences[i].getAnnotation()[a].graphMax,
1383                     sequences[i].getAnnotation()[a].graph);
1384
1385             sequences[i].getAnnotation()[a] = newAnnot;
1386             newAnnot.sequenceMapping = sequences[i].getAnnotation()[a].
1387                 sequenceMapping;
1388             newAnnot.sequenceRef = sequences[i];
1389             newAnnot.adjustForAlignment();
1390             alignment.addAnnotation(newAnnot);
1391             alignment.setAnnotationIndex(newAnnot, a);
1392           }
1393
1394           alignPanel.annotationPanel.adjustPanelHeight();
1395         }
1396       }
1397
1398       if (newAlignment)
1399       {
1400         AlignFrame af = new AlignFrame(alignment, DEFAULT_WIDTH, DEFAULT_HEIGHT);
1401         String newtitle = new String("Copied sequences");
1402
1403         if (Desktop.jalviewClipboard != null && Desktop.jalviewClipboard[2] != null)
1404         {
1405           Vector hc = (Vector) Desktop.jalviewClipboard[2];
1406           for (int i = 0; i < hc.size(); i++)
1407           {
1408             int[] region = (int[]) hc.elementAt(i);
1409             af.viewport.hideColumns(region[0], region[1]);
1410           }
1411         }
1412
1413         //>>>This is a fix for the moment, until a better solution is found!!<<<
1414         af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().transferSettings(
1415             alignPanel.seqPanel.seqCanvas.getFeatureRenderer());
1416
1417         if (title.startsWith("Copied sequences"))
1418         {
1419           newtitle = title;
1420         }
1421         else
1422         {
1423           newtitle = newtitle.concat("- from " + title);
1424         }
1425
1426         Desktop.addInternalFrame(af, newtitle, DEFAULT_WIDTH,
1427                                  DEFAULT_HEIGHT);
1428
1429       }
1430
1431     }
1432     catch (Exception ex)
1433     {
1434       ex.printStackTrace();
1435       System.out.println("Exception whilst pasting: " + ex);
1436       // could be anything being pasted in here
1437     }
1438
1439   }
1440
1441   /**
1442    * DOCUMENT ME!
1443    *
1444    * @param e DOCUMENT ME!
1445    */
1446   protected void cut_actionPerformed(ActionEvent e)
1447   {
1448     copy_actionPerformed(null);
1449     delete_actionPerformed(null);
1450   }
1451
1452   /**
1453    * DOCUMENT ME!
1454    *
1455    * @param e DOCUMENT ME!
1456    */
1457   protected void delete_actionPerformed(ActionEvent evt)
1458   {
1459
1460     SequenceGroup sg = viewport.getSelectionGroup();
1461     if (sg == null)
1462     {
1463       return;
1464     }
1465
1466     Vector seqs = new Vector();
1467     SequenceI seq;
1468     for (int i = 0; i < sg.getSize(); i++)
1469     {
1470       seq = sg.getSequenceAt(i);
1471       seqs.addElement(seq);
1472     }
1473
1474     // If the cut affects all sequences, remove highlighted columns
1475     if (sg.getSize() == viewport.alignment.getHeight())
1476     {
1477       viewport.getColumnSelection().removeElements(sg.getStartRes(),
1478           sg.getEndRes() + 1);
1479     }
1480
1481     SequenceI[] cut = new SequenceI[seqs.size()];
1482     for (int i = 0; i < seqs.size(); i++)
1483     {
1484       cut[i] = (SequenceI) seqs.elementAt(i);
1485     }
1486
1487     /*
1488          //ADD HISTORY ITEM
1489      */
1490     addHistoryItem(new EditCommand("Cut Sequences",
1491                                    EditCommand.CUT,
1492                                    cut,
1493                                    sg.getStartRes(),
1494                                    sg.getEndRes() - sg.getStartRes() + 1,
1495                                    viewport.alignment));
1496
1497     viewport.setSelectionGroup(null);
1498     viewport.alignment.deleteGroup(sg);
1499
1500     viewport.firePropertyChange("alignment", null,
1501                                 viewport.getAlignment().getSequences());
1502
1503     if (viewport.getAlignment().getHeight() < 1)
1504     {
1505       try
1506       {
1507         this.setClosed(true);
1508       }
1509       catch (Exception ex)
1510       {
1511       }
1512     }
1513   }
1514
1515   /**
1516    * DOCUMENT ME!
1517    *
1518    * @param e DOCUMENT ME!
1519    */
1520   protected void deleteGroups_actionPerformed(ActionEvent e)
1521   {
1522     viewport.alignment.deleteAllGroups();
1523     viewport.sequenceColours = null;
1524     viewport.setSelectionGroup(null);
1525     PaintRefresher.Refresh(this, viewport.getSequenceSetId());
1526     alignPanel.repaint();
1527   }
1528
1529   /**
1530    * DOCUMENT ME!
1531    *
1532    * @param e DOCUMENT ME!
1533    */
1534   public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)
1535   {
1536     SequenceGroup sg = new SequenceGroup();
1537
1538     for (int i = 0; i < viewport.getAlignment().getSequences().size();
1539          i++)
1540     {
1541       sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
1542     }
1543
1544     sg.setEndRes(viewport.alignment.getWidth() - 1);
1545     viewport.setSelectionGroup(sg);
1546     alignPanel.repaint();
1547     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
1548   }
1549
1550   /**
1551    * DOCUMENT ME!
1552    *
1553    * @param e DOCUMENT ME!
1554    */
1555   public void deselectAllSequenceMenuItem_actionPerformed(ActionEvent e)
1556   {
1557     if (viewport.cursorMode)
1558     {
1559       alignPanel.seqPanel.keyboardNo1 = null;
1560       alignPanel.seqPanel.keyboardNo2 = null;
1561     }
1562     viewport.setSelectionGroup(null);
1563     viewport.getColumnSelection().clear();
1564     viewport.setSelectionGroup(null);
1565     alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);
1566     alignPanel.idPanel.idCanvas.searchResults = null;
1567     alignPanel.repaint();
1568     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
1569   }
1570
1571   /**
1572    * DOCUMENT ME!
1573    *
1574    * @param e DOCUMENT ME!
1575    */
1576   public void invertSequenceMenuItem_actionPerformed(ActionEvent e)
1577   {
1578     SequenceGroup sg = viewport.getSelectionGroup();
1579
1580     if (sg == null)
1581     {
1582       selectAllSequenceMenuItem_actionPerformed(null);
1583
1584       return;
1585     }
1586
1587     for (int i = 0; i < viewport.getAlignment().getSequences().size();
1588          i++)
1589     {
1590       sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
1591     }
1592
1593     alignPanel.repaint();
1594
1595     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
1596   }
1597
1598   public void invertColSel_actionPerformed(ActionEvent e)
1599   {
1600     viewport.invertColumnSelection();
1601     alignPanel.repaint();
1602   }
1603
1604   /**
1605    * DOCUMENT ME!
1606    *
1607    * @param e DOCUMENT ME!
1608    */
1609   public void remove2LeftMenuItem_actionPerformed(ActionEvent e)
1610   {
1611     trimAlignment(true);
1612   }
1613
1614   /**
1615    * DOCUMENT ME!
1616    *
1617    * @param e DOCUMENT ME!
1618    */
1619   public void remove2RightMenuItem_actionPerformed(ActionEvent e)
1620   {
1621     trimAlignment(false);
1622   }
1623
1624   void trimAlignment(boolean trimLeft)
1625   {
1626     ColumnSelection colSel = viewport.getColumnSelection();
1627     int column;
1628
1629     if (colSel.size() > 0)
1630     {
1631       if (trimLeft)
1632       {
1633         column = colSel.getMin();
1634       }
1635       else
1636       {
1637         column = colSel.getMax();
1638       }
1639
1640       SequenceI[] seqs;
1641       if (viewport.getSelectionGroup() != null)
1642       {
1643         seqs = viewport.getSelectionGroup().getSequencesAsArray(viewport.
1644             hiddenRepSequences);
1645       }
1646       else
1647       {
1648         seqs = viewport.alignment.getSequencesArray();
1649       }
1650
1651       TrimRegionCommand trimRegion;
1652       if (trimLeft)
1653       {
1654         trimRegion = new TrimRegionCommand("Remove Left",
1655                                            TrimRegionCommand.TRIM_LEFT,
1656                                            seqs,
1657                                            column,
1658                                            viewport.alignment,
1659                                            viewport.colSel,
1660                                            viewport.selectionGroup);
1661         viewport.setStartRes(0);
1662       }
1663       else
1664       {
1665         trimRegion = new TrimRegionCommand("Remove Right",
1666                                            TrimRegionCommand.TRIM_RIGHT,
1667                                            seqs,
1668                                            column,
1669                                            viewport.alignment,
1670                                            viewport.colSel,
1671                                            viewport.selectionGroup);
1672       }
1673
1674       statusBar.setText("Removed " + trimRegion.getSize() + " columns.");
1675
1676       addHistoryItem(trimRegion);
1677
1678       Vector groups = viewport.alignment.getGroups();
1679
1680       for (int i = 0; i < groups.size(); i++)
1681       {
1682         SequenceGroup sg = (SequenceGroup) groups.get(i);
1683
1684         if ( (trimLeft && !sg.adjustForRemoveLeft(column))
1685             || (!trimLeft && !sg.adjustForRemoveRight(column)))
1686         {
1687           viewport.alignment.deleteGroup(sg);
1688         }
1689       }
1690
1691       viewport.firePropertyChange("alignment", null,
1692                                   viewport.getAlignment().getSequences());
1693     }
1694   }
1695
1696   /**
1697    * DOCUMENT ME!
1698    *
1699    * @param e DOCUMENT ME!
1700    */
1701   public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e)
1702   {
1703     int start = 0, end = viewport.alignment.getWidth() - 1;
1704
1705     SequenceI[] seqs;
1706     if (viewport.getSelectionGroup() != null)
1707     {
1708       seqs = viewport.getSelectionGroup().getSequencesAsArray(viewport.
1709           hiddenRepSequences);
1710       start = viewport.getSelectionGroup().getStartRes();
1711       end = viewport.getSelectionGroup().getEndRes();
1712     }
1713     else
1714     {
1715       seqs = viewport.alignment.getSequencesArray();
1716     }
1717
1718     RemoveGapColCommand removeGapCols =
1719         new RemoveGapColCommand("Remove Gapped Columns",
1720                                 seqs,
1721                                 start, end,
1722                                 viewport.alignment);
1723
1724     addHistoryItem(removeGapCols);
1725
1726     statusBar.setText("Removed " + removeGapCols.getSize() + " empty columns.");
1727
1728     //This is to maintain viewport position on first residue
1729     //of first sequence
1730     SequenceI seq = viewport.alignment.getSequenceAt(0);
1731     int startRes = seq.findPosition(viewport.startRes);
1732     // ShiftList shifts;
1733     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
1734     // edit.alColumnChanges=shifts.getInverse();
1735     // if (viewport.hasHiddenColumns)
1736     //   viewport.getColumnSelection().compensateForEdits(shifts);
1737     viewport.setStartRes(seq.findIndex(startRes) - 1);
1738     viewport.firePropertyChange("alignment", null,
1739                                 viewport.getAlignment().getSequences());
1740
1741   }
1742
1743   /**
1744    * DOCUMENT ME!
1745    *
1746    * @param e DOCUMENT ME!
1747    */
1748   public void removeAllGapsMenuItem_actionPerformed(ActionEvent e)
1749   {
1750     int start = 0, end = viewport.alignment.getWidth() - 1;
1751
1752     SequenceI[] seqs;
1753     if (viewport.getSelectionGroup() != null)
1754     {
1755       seqs = viewport.getSelectionGroup().getSequencesAsArray(viewport.
1756           hiddenRepSequences);
1757       start = viewport.getSelectionGroup().getStartRes();
1758       end = viewport.getSelectionGroup().getEndRes();
1759     }
1760     else
1761     {
1762       seqs = viewport.alignment.getSequencesArray();
1763     }
1764
1765     //This is to maintain viewport position on first residue
1766     //of first sequence
1767     SequenceI seq = viewport.alignment.getSequenceAt(0);
1768     int startRes = seq.findPosition(viewport.startRes);
1769
1770     addHistoryItem(new RemoveGapsCommand("Remove Gaps",
1771                                          seqs,
1772                                          start, end,
1773                                          viewport.alignment));
1774
1775     viewport.setStartRes(seq.findIndex(startRes) - 1);
1776
1777     viewport.firePropertyChange("alignment", null,
1778                                 viewport.getAlignment().getSequences());
1779
1780   }
1781
1782   /**
1783    * DOCUMENT ME!
1784    *
1785    * @param e DOCUMENT ME!
1786    */
1787   public void padGapsMenuitem_actionPerformed(ActionEvent e)
1788   {
1789     viewport.padGaps = padGapsMenuitem.isSelected();
1790
1791     viewport.firePropertyChange("alignment",
1792                                 null,
1793                                 viewport.getAlignment().getSequences());
1794   }
1795
1796   /**
1797    * DOCUMENT ME!
1798    *
1799    * @param e DOCUMENT ME!
1800    */
1801   public void findMenuItem_actionPerformed(ActionEvent e)
1802   {
1803     new Finder();
1804   }
1805
1806   public void newView_actionPerformed(ActionEvent e)
1807   {
1808     AlignmentPanel newap =
1809         new Jalview2XML().copyAlignPanel(alignPanel, true);
1810
1811     if (viewport.viewName == null)
1812     {
1813       viewport.viewName = "Original";
1814     }
1815
1816     newap.av.historyList = viewport.historyList;
1817     newap.av.redoList = viewport.redoList;
1818
1819     int index = Desktop.getViewCount(viewport.getSequenceSetId());
1820     String newViewName = "View " + index;
1821
1822     Vector comps = (Vector) PaintRefresher.components.get(viewport.
1823         getSequenceSetId());
1824     Vector existingNames = new Vector();
1825     for (int i = 0; i < comps.size(); i++)
1826     {
1827       if (comps.elementAt(i) instanceof AlignmentPanel)
1828       {
1829         AlignmentPanel ap = (AlignmentPanel) comps.elementAt(i);
1830         if (!existingNames.contains(ap.av.viewName))
1831         {
1832           existingNames.addElement(ap.av.viewName);
1833         }
1834       }
1835     }
1836
1837     while (existingNames.contains(newViewName))
1838     {
1839       newViewName = "View " + (++index);
1840     }
1841
1842     newap.av.viewName = newViewName;
1843
1844     addAlignmentPanel(newap, false);
1845
1846     if (alignPanels.size() == 2)
1847     {
1848       viewport.gatherViewsHere = true;
1849     }
1850     tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
1851   }
1852
1853   public void expandViews_actionPerformed(ActionEvent e)
1854   {
1855     Desktop.instance.explodeViews(this);
1856   }
1857
1858   public void gatherViews_actionPerformed(ActionEvent e)
1859   {
1860     Desktop.instance.gatherViews(this);
1861   }
1862
1863   /**
1864    * DOCUMENT ME!
1865    *
1866    * @param e DOCUMENT ME!
1867    */
1868   public void font_actionPerformed(ActionEvent e)
1869   {
1870     new FontChooser(alignPanel);
1871   }
1872
1873   /**
1874    * DOCUMENT ME!
1875    *
1876    * @param e DOCUMENT ME!
1877    */
1878   protected void seqLimit_actionPerformed(ActionEvent e)
1879   {
1880     viewport.setShowJVSuffix(seqLimits.isSelected());
1881
1882     alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel.calculateIdWidth());
1883     alignPanel.repaint();
1884   }
1885
1886   public void idRightAlign_actionPerformed(ActionEvent e)
1887   {
1888     viewport.rightAlignIds = idRightAlign.isSelected();
1889     alignPanel.repaint();
1890   }
1891
1892   /**
1893    * DOCUMENT ME!
1894    *
1895    * @param e DOCUMENT ME!
1896    */
1897   protected void colourTextMenuItem_actionPerformed(ActionEvent e)
1898   {
1899     viewport.setColourText(colourTextMenuItem.isSelected());
1900     alignPanel.repaint();
1901   }
1902
1903   /**
1904    * DOCUMENT ME!
1905    *
1906    * @param e DOCUMENT ME!
1907    */
1908   public void wrapMenuItem_actionPerformed(ActionEvent e)
1909   {
1910     scaleAbove.setVisible(wrapMenuItem.isSelected());
1911     scaleLeft.setVisible(wrapMenuItem.isSelected());
1912     scaleRight.setVisible(wrapMenuItem.isSelected());
1913     viewport.setWrapAlignment(wrapMenuItem.isSelected());
1914     alignPanel.setWrapAlignment(wrapMenuItem.isSelected());
1915   }
1916
1917   public void showAllSeqs_actionPerformed(ActionEvent e)
1918   {
1919     viewport.showAllHiddenSeqs();
1920   }
1921
1922   public void showAllColumns_actionPerformed(ActionEvent e)
1923   {
1924     viewport.showAllHiddenColumns();
1925     repaint();
1926   }
1927
1928   public void hideSelSequences_actionPerformed(ActionEvent e)
1929   {
1930     viewport.hideAllSelectedSeqs();
1931     alignPanel.repaint();
1932   }
1933
1934   public void hideSelColumns_actionPerformed(ActionEvent e)
1935   {
1936     viewport.hideSelectedColumns();
1937     alignPanel.repaint();
1938   }
1939
1940   public void hiddenMarkers_actionPerformed(ActionEvent e)
1941   {
1942     viewport.setShowHiddenMarkers(hiddenMarkers.isSelected());
1943     repaint();
1944   }
1945
1946   /**
1947    * DOCUMENT ME!
1948    *
1949    * @param e DOCUMENT ME!
1950    */
1951   protected void scaleAbove_actionPerformed(ActionEvent e)
1952   {
1953     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
1954     alignPanel.repaint();
1955   }
1956
1957   /**
1958    * DOCUMENT ME!
1959    *
1960    * @param e DOCUMENT ME!
1961    */
1962   protected void scaleLeft_actionPerformed(ActionEvent e)
1963   {
1964     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
1965     alignPanel.repaint();
1966   }
1967
1968   /**
1969    * DOCUMENT ME!
1970    *
1971    * @param e DOCUMENT ME!
1972    */
1973   protected void scaleRight_actionPerformed(ActionEvent e)
1974   {
1975     viewport.setScaleRightWrapped(scaleRight.isSelected());
1976     alignPanel.repaint();
1977   }
1978
1979   /**
1980    * DOCUMENT ME!
1981    *
1982    * @param e DOCUMENT ME!
1983    */
1984   public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
1985   {
1986     viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
1987     alignPanel.repaint();
1988   }
1989
1990   /**
1991    * DOCUMENT ME!
1992    *
1993    * @param e DOCUMENT ME!
1994    */
1995   public void viewTextMenuItem_actionPerformed(ActionEvent e)
1996   {
1997     viewport.setShowText(viewTextMenuItem.isSelected());
1998     alignPanel.repaint();
1999   }
2000
2001   /**
2002    * DOCUMENT ME!
2003    *
2004    * @param e DOCUMENT ME!
2005    */
2006   protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
2007   {
2008     viewport.setRenderGaps(renderGapsMenuItem.isSelected());
2009     alignPanel.repaint();
2010   }
2011
2012   public FeatureSettings featureSettings;
2013   public void featureSettings_actionPerformed(ActionEvent e)
2014   {
2015     if (featureSettings != null)
2016     {
2017       featureSettings.close();
2018       featureSettings = null;
2019     }
2020     featureSettings = new FeatureSettings(this);
2021   }
2022
2023   /**
2024    * DOCUMENT ME!
2025    *
2026    * @param evt DOCUMENT ME!
2027    */
2028   public void showSeqFeatures_actionPerformed(ActionEvent evt)
2029   {
2030     viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
2031     alignPanel.repaint();
2032     if (alignPanel.getOverviewPanel() != null)
2033     {
2034       alignPanel.getOverviewPanel().updateOverviewImage();
2035     }
2036   }
2037
2038   /**
2039    * DOCUMENT ME!
2040    *
2041    * @param e DOCUMENT ME!
2042    */
2043   public void annotationPanelMenuItem_actionPerformed(ActionEvent e)
2044   {
2045     viewport.setShowAnnotation(annotationPanelMenuItem.isSelected());
2046     alignPanel.setAnnotationVisible(annotationPanelMenuItem.isSelected());
2047   }
2048
2049   /**
2050    * DOCUMENT ME!
2051    *
2052    * @param e DOCUMENT ME!
2053    */
2054   public void overviewMenuItem_actionPerformed(ActionEvent e)
2055   {
2056     if (alignPanel.overviewPanel != null)
2057     {
2058       return;
2059     }
2060
2061     JInternalFrame frame = new JInternalFrame();
2062     OverviewPanel overview = new OverviewPanel(alignPanel);
2063     frame.setContentPane(overview);
2064     Desktop.addInternalFrame(frame, "Overview " + this.getTitle(),
2065                              frame.getWidth(), frame.getHeight());
2066     frame.pack();
2067     frame.setLayer(JLayeredPane.PALETTE_LAYER);
2068     frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
2069     {
2070       public void internalFrameClosed(
2071           javax.swing.event.InternalFrameEvent evt)
2072       {
2073         alignPanel.setOverviewPanel(null);
2074       }
2075       ;
2076     });
2077
2078     alignPanel.setOverviewPanel(overview);
2079   }
2080
2081   public void textColour_actionPerformed(ActionEvent e)
2082   {
2083     new TextColourChooser().chooseColour(alignPanel, null);
2084   }
2085
2086   /**
2087    * DOCUMENT ME!
2088    *
2089    * @param e DOCUMENT ME!
2090    */
2091   protected void noColourmenuItem_actionPerformed(ActionEvent e)
2092   {
2093     changeColour(null);
2094   }
2095
2096   /**
2097    * DOCUMENT ME!
2098    *
2099    * @param e DOCUMENT ME!
2100    */
2101   public void clustalColour_actionPerformed(ActionEvent e)
2102   {
2103     changeColour(new ClustalxColourScheme(
2104         viewport.alignment.getSequences(), viewport.alignment.getWidth()));
2105   }
2106
2107   /**
2108    * DOCUMENT ME!
2109    *
2110    * @param e DOCUMENT ME!
2111    */
2112   public void zappoColour_actionPerformed(ActionEvent e)
2113   {
2114     changeColour(new ZappoColourScheme());
2115   }
2116
2117   /**
2118    * DOCUMENT ME!
2119    *
2120    * @param e DOCUMENT ME!
2121    */
2122   public void taylorColour_actionPerformed(ActionEvent e)
2123   {
2124     changeColour(new TaylorColourScheme());
2125   }
2126
2127   /**
2128    * DOCUMENT ME!
2129    *
2130    * @param e DOCUMENT ME!
2131    */
2132   public void hydrophobicityColour_actionPerformed(ActionEvent e)
2133   {
2134     changeColour(new HydrophobicColourScheme());
2135   }
2136
2137   /**
2138    * DOCUMENT ME!
2139    *
2140    * @param e DOCUMENT ME!
2141    */
2142   public void helixColour_actionPerformed(ActionEvent e)
2143   {
2144     changeColour(new HelixColourScheme());
2145   }
2146
2147   /**
2148    * DOCUMENT ME!
2149    *
2150    * @param e DOCUMENT ME!
2151    */
2152   public void strandColour_actionPerformed(ActionEvent e)
2153   {
2154     changeColour(new StrandColourScheme());
2155   }
2156
2157   /**
2158    * DOCUMENT ME!
2159    *
2160    * @param e DOCUMENT ME!
2161    */
2162   public void turnColour_actionPerformed(ActionEvent e)
2163   {
2164     changeColour(new TurnColourScheme());
2165   }
2166
2167   /**
2168    * DOCUMENT ME!
2169    *
2170    * @param e DOCUMENT ME!
2171    */
2172   public void buriedColour_actionPerformed(ActionEvent e)
2173   {
2174     changeColour(new BuriedColourScheme());
2175   }
2176
2177   /**
2178    * DOCUMENT ME!
2179    *
2180    * @param e DOCUMENT ME!
2181    */
2182   public void nucleotideColour_actionPerformed(ActionEvent e)
2183   {
2184     changeColour(new NucleotideColourScheme());
2185   }
2186
2187   public void annotationColour_actionPerformed(ActionEvent e)
2188   {
2189     new AnnotationColourChooser(viewport, alignPanel);
2190   }
2191
2192   /**
2193    * DOCUMENT ME!
2194    *
2195    * @param e DOCUMENT ME!
2196    */
2197   protected void applyToAllGroups_actionPerformed(ActionEvent e)
2198   {
2199     viewport.setColourAppliesToAllGroups(applyToAllGroups.isSelected());
2200   }
2201
2202   /**
2203    * DOCUMENT ME!
2204    *
2205    * @param cs DOCUMENT ME!
2206    */
2207   public void changeColour(ColourSchemeI cs)
2208   {
2209     int threshold = 0;
2210
2211     if (cs != null)
2212     {
2213       if (viewport.getAbovePIDThreshold())
2214       {
2215         threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
2216             "Background");
2217
2218         cs.setThreshold(threshold,
2219                         viewport.getIgnoreGapsConsensus());
2220
2221         viewport.setGlobalColourScheme(cs);
2222       }
2223       else
2224       {
2225         cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
2226       }
2227
2228       if (viewport.getConservationSelected())
2229       {
2230
2231         Alignment al = (Alignment) viewport.alignment;
2232         Conservation c = new Conservation("All",
2233                                           ResidueProperties.propHash, 3,
2234                                           al.getSequences(), 0,
2235                                           al.getWidth() - 1);
2236
2237         c.calculate();
2238         c.verdict(false, viewport.ConsPercGaps);
2239
2240         cs.setConservation(c);
2241
2242         cs.setConservationInc(SliderPanel.setConservationSlider(alignPanel, cs,
2243             "Background"));
2244       }
2245       else
2246       {
2247         cs.setConservation(null);
2248       }
2249
2250       cs.setConsensus(viewport.hconsensus);
2251     }
2252
2253     viewport.setGlobalColourScheme(cs);
2254
2255     if (viewport.getColourAppliesToAllGroups())
2256     {
2257       Vector groups = viewport.alignment.getGroups();
2258
2259       for (int i = 0; i < groups.size(); i++)
2260       {
2261         SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
2262
2263         if (cs == null)
2264         {
2265           sg.cs = null;
2266           continue;
2267         }
2268
2269         if (cs instanceof ClustalxColourScheme)
2270         {
2271           sg.cs = new ClustalxColourScheme(
2272               sg.getSequences(viewport.hiddenRepSequences), sg.getWidth());
2273         }
2274         else if (cs instanceof UserColourScheme)
2275         {
2276           sg.cs = new UserColourScheme( ( (UserColourScheme) cs).getColours());
2277         }
2278         else
2279         {
2280           try
2281           {
2282             sg.cs = (ColourSchemeI) cs.getClass().newInstance();
2283           }
2284           catch (Exception ex)
2285           {
2286           }
2287         }
2288
2289         if (viewport.getAbovePIDThreshold()
2290             || cs instanceof PIDColourScheme
2291             || cs instanceof Blosum62ColourScheme)
2292         {
2293           sg.cs.setThreshold(threshold,
2294                              viewport.getIgnoreGapsConsensus());
2295
2296           sg.cs.setConsensus(AAFrequency.calculate(
2297               sg.getSequences(viewport.hiddenRepSequences), sg.getStartRes(),
2298               sg.getEndRes() + 1));
2299         }
2300         else
2301         {
2302           sg.cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
2303         }
2304
2305         if (viewport.getConservationSelected())
2306         {
2307           Conservation c = new Conservation("Group",
2308                                             ResidueProperties.propHash, 3,
2309                                             sg.getSequences(viewport.
2310               hiddenRepSequences),
2311                                             sg.getStartRes(),
2312                                             sg.getEndRes() + 1);
2313           c.calculate();
2314           c.verdict(false, viewport.ConsPercGaps);
2315           sg.cs.setConservation(c);
2316         }
2317         else
2318         {
2319           sg.cs.setConservation(null);
2320         }
2321       }
2322     }
2323
2324     if (alignPanel.getOverviewPanel() != null)
2325     {
2326       alignPanel.getOverviewPanel().updateOverviewImage();
2327     }
2328
2329     alignPanel.repaint();
2330   }
2331
2332   /**
2333    * DOCUMENT ME!
2334    *
2335    * @param e DOCUMENT ME!
2336    */
2337   protected void modifyPID_actionPerformed(ActionEvent e)
2338   {
2339     if (viewport.getAbovePIDThreshold() && viewport.globalColourScheme != null)
2340     {
2341       SliderPanel.setPIDSliderSource(alignPanel,
2342                                      viewport.getGlobalColourScheme(),
2343                                      "Background");
2344       SliderPanel.showPIDSlider();
2345     }
2346   }
2347
2348   /**
2349    * DOCUMENT ME!
2350    *
2351    * @param e DOCUMENT ME!
2352    */
2353   protected void modifyConservation_actionPerformed(ActionEvent e)
2354   {
2355     if (viewport.getConservationSelected() && viewport.globalColourScheme != null)
2356     {
2357       SliderPanel.setConservationSlider(alignPanel,
2358                                         viewport.globalColourScheme,
2359                                         "Background");
2360       SliderPanel.showConservationSlider();
2361     }
2362   }
2363
2364   /**
2365    * DOCUMENT ME!
2366    *
2367    * @param e DOCUMENT ME!
2368    */
2369   protected void conservationMenuItem_actionPerformed(ActionEvent e)
2370   {
2371     viewport.setConservationSelected(conservationMenuItem.isSelected());
2372
2373     viewport.setAbovePIDThreshold(false);
2374     abovePIDThreshold.setSelected(false);
2375
2376     changeColour(viewport.getGlobalColourScheme());
2377
2378     modifyConservation_actionPerformed(null);
2379   }
2380
2381   /**
2382    * DOCUMENT ME!
2383    *
2384    * @param e DOCUMENT ME!
2385    */
2386   public void abovePIDThreshold_actionPerformed(ActionEvent e)
2387   {
2388     viewport.setAbovePIDThreshold(abovePIDThreshold.isSelected());
2389
2390     conservationMenuItem.setSelected(false);
2391     viewport.setConservationSelected(false);
2392
2393     changeColour(viewport.getGlobalColourScheme());
2394
2395     modifyPID_actionPerformed(null);
2396   }
2397
2398   /**
2399    * DOCUMENT ME!
2400    *
2401    * @param e DOCUMENT ME!
2402    */
2403   public void userDefinedColour_actionPerformed(ActionEvent e)
2404   {
2405     if (e.getActionCommand().equals("User Defined..."))
2406     {
2407       new UserDefinedColours(alignPanel, null);
2408     }
2409     else
2410     {
2411       UserColourScheme udc = (UserColourScheme) UserDefinedColours.
2412           getUserColourSchemes().get(e.getActionCommand());
2413
2414       changeColour(udc);
2415     }
2416   }
2417
2418   public void updateUserColourMenu()
2419   {
2420
2421     Component[] menuItems = colourMenu.getMenuComponents();
2422     int i, iSize = menuItems.length;
2423     for (i = 0; i < iSize; i++)
2424     {
2425       if (menuItems[i].getName() != null &&
2426           menuItems[i].getName().equals("USER_DEFINED"))
2427       {
2428         colourMenu.remove(menuItems[i]);
2429         iSize--;
2430       }
2431     }
2432     if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)
2433     {
2434       java.util.Enumeration userColours = jalview.gui.UserDefinedColours.
2435           getUserColourSchemes().keys();
2436
2437       while (userColours.hasMoreElements())
2438       {
2439         final JRadioButtonMenuItem radioItem = new JRadioButtonMenuItem(
2440             userColours.
2441             nextElement().toString());
2442         radioItem.setName("USER_DEFINED");
2443         radioItem.addMouseListener(new MouseAdapter()
2444         {
2445           public void mousePressed(MouseEvent evt)
2446           {
2447             if (evt.isControlDown() || SwingUtilities.isRightMouseButton(evt))
2448             {
2449               radioItem.removeActionListener(radioItem.getActionListeners()[0]);
2450
2451               int option = JOptionPane.showInternalConfirmDialog(jalview.gui.
2452                   Desktop.desktop,
2453                   "Remove from default list?",
2454                   "Remove user defined colour",
2455                   JOptionPane.YES_NO_OPTION);
2456               if (option == JOptionPane.YES_OPTION)
2457               {
2458                 jalview.gui.UserDefinedColours.removeColourFromDefaults(
2459                     radioItem.getText());
2460                 colourMenu.remove(radioItem);
2461               }
2462               else
2463               {
2464                 radioItem.addActionListener(new ActionListener()
2465                 {
2466                   public void actionPerformed(ActionEvent evt)
2467                   {
2468                     userDefinedColour_actionPerformed(evt);
2469                   }
2470                 });
2471               }
2472             }
2473           }
2474         });
2475         radioItem.addActionListener(new ActionListener()
2476         {
2477           public void actionPerformed(ActionEvent evt)
2478           {
2479             userDefinedColour_actionPerformed(evt);
2480           }
2481         });
2482
2483         colourMenu.insert(radioItem, 15);
2484         colours.add(radioItem);
2485       }
2486     }
2487   }
2488
2489   /**
2490    * DOCUMENT ME!
2491    *
2492    * @param e DOCUMENT ME!
2493    */
2494   public void PIDColour_actionPerformed(ActionEvent e)
2495   {
2496     changeColour(new PIDColourScheme());
2497   }
2498
2499   /**
2500    * DOCUMENT ME!
2501    *
2502    * @param e DOCUMENT ME!
2503    */
2504   public void BLOSUM62Colour_actionPerformed(ActionEvent e)
2505   {
2506     changeColour(new Blosum62ColourScheme());
2507   }
2508
2509   /**
2510    * DOCUMENT ME!
2511    *
2512    * @param e DOCUMENT ME!
2513    */
2514   public void sortPairwiseMenuItem_actionPerformed(ActionEvent e)
2515   {
2516     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2517     AlignmentSorter.sortByPID(viewport.getAlignment(),
2518                               viewport.getAlignment().getSequenceAt(0));
2519     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
2520                                     viewport.alignment));
2521     alignPanel.repaint();
2522   }
2523
2524   /**
2525    * DOCUMENT ME!
2526    *
2527    * @param e DOCUMENT ME!
2528    */
2529   public void sortIDMenuItem_actionPerformed(ActionEvent e)
2530   {
2531     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2532     AlignmentSorter.sortByID(viewport.getAlignment());
2533     addHistoryItem(new OrderCommand("ID Sort", oldOrder, viewport.alignment));
2534     alignPanel.repaint();
2535   }
2536
2537   /**
2538    * DOCUMENT ME!
2539    *
2540    * @param e DOCUMENT ME!
2541    */
2542   public void sortGroupMenuItem_actionPerformed(ActionEvent e)
2543   {
2544     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2545     AlignmentSorter.sortByGroup(viewport.getAlignment());
2546     addHistoryItem(new OrderCommand("Group Sort", oldOrder, viewport.alignment));
2547
2548     alignPanel.repaint();
2549   }
2550
2551   /**
2552    * DOCUMENT ME!
2553    *
2554    * @param e DOCUMENT ME!
2555    */
2556   public void removeRedundancyMenuItem_actionPerformed(ActionEvent e)
2557   {
2558     new RedundancyPanel(alignPanel, this);
2559   }
2560
2561   /**
2562    * DOCUMENT ME!
2563    *
2564    * @param e DOCUMENT ME!
2565    */
2566   public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e)
2567   {
2568     if ( (viewport.getSelectionGroup() == null) ||
2569         (viewport.getSelectionGroup().getSize() < 2))
2570     {
2571       JOptionPane.showInternalMessageDialog(this,
2572                                             "You must select at least 2 sequences.",
2573                                             "Invalid Selection",
2574                                             JOptionPane.WARNING_MESSAGE);
2575     }
2576     else
2577     {
2578       JInternalFrame frame = new JInternalFrame();
2579       frame.setContentPane(new PairwiseAlignPanel(viewport));
2580       Desktop.addInternalFrame(frame, "Pairwise Alignment", 600, 500);
2581     }
2582   }
2583
2584   /**
2585    * DOCUMENT ME!
2586    *
2587    * @param e DOCUMENT ME!
2588    */
2589   public void PCAMenuItem_actionPerformed(ActionEvent e)
2590   {
2591     if ( ( (viewport.getSelectionGroup() != null) &&
2592           (viewport.getSelectionGroup().getSize() < 4) &&
2593           (viewport.getSelectionGroup().getSize() > 0)) ||
2594         (viewport.getAlignment().getHeight() < 4))
2595     {
2596       JOptionPane.showInternalMessageDialog(this,
2597                                             "Principal component analysis must take\n" +
2598                                             "at least 4 input sequences.",
2599                                             "Sequence selection insufficient",
2600                                             JOptionPane.WARNING_MESSAGE);
2601
2602       return;
2603     }
2604
2605     new PCAPanel(alignPanel);
2606   }
2607
2608   public void autoCalculate_actionPerformed(ActionEvent e)
2609   {
2610     viewport.autoCalculateConsensus = autoCalculate.isSelected();
2611     if (viewport.autoCalculateConsensus)
2612     {
2613       viewport.firePropertyChange("alignment",
2614                                   null,
2615                                   viewport.getAlignment().getSequences());
2616     }
2617   }
2618
2619   /**
2620    * DOCUMENT ME!
2621    *
2622    * @param e DOCUMENT ME!
2623    */
2624   public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)
2625   {
2626     NewTreePanel("AV", "PID", "Average distance tree using PID");
2627   }
2628
2629   /**
2630    * DOCUMENT ME!
2631    *
2632    * @param e DOCUMENT ME!
2633    */
2634   public void neighbourTreeMenuItem_actionPerformed(ActionEvent e)
2635   {
2636     NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
2637   }
2638
2639   /**
2640    * DOCUMENT ME!
2641    *
2642    * @param e DOCUMENT ME!
2643    */
2644   protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)
2645   {
2646     NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
2647   }
2648
2649   /**
2650    * DOCUMENT ME!
2651    *
2652    * @param e DOCUMENT ME!
2653    */
2654   protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e)
2655   {
2656     NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
2657   }
2658
2659   /**
2660    * DOCUMENT ME!
2661    *
2662    * @param type DOCUMENT ME!
2663    * @param pwType DOCUMENT ME!
2664    * @param title DOCUMENT ME!
2665    */
2666   void NewTreePanel(String type, String pwType, String title)
2667   {
2668     TreePanel tp;
2669
2670     if (viewport.getSelectionGroup() != null)
2671     {
2672       if (viewport.getSelectionGroup().getSize() < 3)
2673       {
2674         JOptionPane.showMessageDialog(Desktop.desktop,
2675                                       "You need to have more than two sequences selected to build a tree!",
2676                                       "Not enough sequences",
2677                                       JOptionPane.WARNING_MESSAGE);
2678         return;
2679       }
2680
2681       int s = 0;
2682       SequenceGroup sg = viewport.getSelectionGroup();
2683
2684       /* Decide if the selection is a column region */
2685       while (s < sg.getSize())
2686       {
2687         if ( ( (SequenceI) sg.getSequences(null).elementAt(s++)).getLength() <
2688             sg.getEndRes())
2689         {
2690           JOptionPane.showMessageDialog(Desktop.desktop,
2691                                         "The selected region to create a tree may\nonly contain residues or gaps.\n" +
2692                                         "Try using the Pad function in the edit menu,\n" +
2693                                         "or one of the multiple sequence alignment web services.",
2694                                         "Sequences in selection are not aligned",
2695                                         JOptionPane.WARNING_MESSAGE);
2696
2697           return;
2698         }
2699       }
2700
2701       title = title + " on region";
2702       tp = new TreePanel(alignPanel, type, pwType);
2703     }
2704     else
2705     {
2706       //are the sequences aligned?
2707       if (!viewport.alignment.isAligned())
2708       {
2709         JOptionPane.showMessageDialog(Desktop.desktop,
2710                                       "The sequences must be aligned before creating a tree.\n" +
2711                                       "Try using the Pad function in the edit menu,\n" +
2712                                       "or one of the multiple sequence alignment web services.",
2713                                       "Sequences not aligned",
2714                                       JOptionPane.WARNING_MESSAGE);
2715
2716         return;
2717       }
2718
2719       if (viewport.alignment.getHeight() < 2)
2720       {
2721         return;
2722       }
2723
2724       tp = new TreePanel(alignPanel, type, pwType);
2725     }
2726
2727     title += " from ";
2728
2729     if (viewport.viewName != null)
2730     {
2731       title += viewport.viewName + " of ";
2732     }
2733
2734     title += this.title;
2735
2736     Desktop.addInternalFrame(tp, title, 600, 500);
2737   }
2738
2739   /**
2740    * DOCUMENT ME!
2741    *
2742    * @param title DOCUMENT ME!
2743    * @param order DOCUMENT ME!
2744    */
2745   public void addSortByOrderMenuItem(String title, final AlignmentOrder order)
2746   {
2747     final JMenuItem item = new JMenuItem("by " + title);
2748     sort.add(item);
2749     item.addActionListener(new java.awt.event.ActionListener()
2750     {
2751       public void actionPerformed(ActionEvent e)
2752       {
2753         SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2754
2755         // TODO: JBPNote - have to map order entries to curent SequenceI pointers
2756         AlignmentSorter.sortBy(viewport.getAlignment(), order);
2757
2758         addHistoryItem(new OrderCommand(order.getName(), oldOrder,
2759                                         viewport.alignment));
2760
2761         alignPanel.repaint();
2762       }
2763     });
2764   }
2765
2766   /**
2767    * Maintain the Order by->Displayed Tree menu.
2768    * Creates a new menu item for a TreePanel with an appropriate
2769    * <code>jalview.analysis.AlignmentSorter</code> call. Listeners are added
2770    * to remove the menu item when the treePanel is closed, and adjust
2771    * the tree leaf to sequence mapping when the alignment is modified.
2772    * @param treePanel Displayed tree window.
2773    * @param title SortBy menu item title.
2774    */
2775   public void buildTreeMenu()
2776   {
2777     sortByTreeMenu.removeAll();
2778
2779     Vector comps = (Vector) PaintRefresher.components.get(viewport.
2780         getSequenceSetId());
2781     Vector treePanels = new Vector();
2782     int i, iSize = comps.size();
2783     for (i = 0; i < iSize; i++)
2784     {
2785       if (comps.elementAt(i) instanceof TreePanel)
2786       {
2787         treePanels.add(comps.elementAt(i));
2788       }
2789     }
2790
2791     iSize = treePanels.size();
2792
2793     if (iSize < 1)
2794     {
2795       sortByTreeMenu.setVisible(false);
2796       return;
2797     }
2798
2799     sortByTreeMenu.setVisible(true);
2800
2801     for (i = 0; i < treePanels.size(); i++)
2802     {
2803       TreePanel tp = (TreePanel) treePanels.elementAt(i);
2804       final JMenuItem item = new JMenuItem(tp.getTitle());
2805       final NJTree tree = ( (TreePanel) treePanels.elementAt(i)).getTree();
2806       item.addActionListener(new java.awt.event.ActionListener()
2807       {
2808         public void actionPerformed(ActionEvent e)
2809         {
2810           SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2811           AlignmentSorter.sortByTree(viewport.getAlignment(), tree);
2812
2813           addHistoryItem(new OrderCommand("Tree Sort",
2814                                           oldOrder,
2815                                           viewport.alignment));
2816
2817           alignPanel.repaint();
2818         }
2819       });
2820
2821       sortByTreeMenu.add(item);
2822     }
2823   }
2824
2825   /**
2826    * Work out whether the whole set of sequences
2827    * or just the selected set will be submitted for multiple alignment.
2828    *
2829    */
2830   private jalview.datamodel.AlignmentView gatherSequencesForAlignment()
2831   {
2832     // Now, check we have enough sequences
2833     AlignmentView msa = null;
2834
2835     if ( (viewport.getSelectionGroup() != null) &&
2836         (viewport.getSelectionGroup().getSize() > 1))
2837     {
2838       // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to some common interface!
2839       /*SequenceGroup seqs = viewport.getSelectionGroup();
2840              int sz;
2841              msa = new SequenceI[sz = seqs.getSize(false)];
2842
2843              for (int i = 0; i < sz; i++)
2844              {
2845         msa[i] = (SequenceI) seqs.getSequenceAt(i);
2846              } */
2847       msa = viewport.getAlignmentView(true);
2848     }
2849     else
2850     {
2851       /*Vector seqs = viewport.getAlignment().getSequences();
2852              if (seqs.size() > 1)
2853              {
2854         msa = new SequenceI[seqs.size()];
2855
2856         for (int i = 0; i < seqs.size(); i++)
2857         {
2858           msa[i] = (SequenceI) seqs.elementAt(i);
2859         }
2860              }*/
2861       msa = viewport.getAlignmentView(false);
2862     }
2863     return msa;
2864   }
2865
2866   /**
2867    * Decides what is submitted to a secondary structure prediction service,
2868    * the currently selected sequence, or the currently selected alignment
2869    * (where the first sequence in the set is the one that the prediction
2870    * will be for).
2871    */
2872   AlignmentView gatherSeqOrMsaForSecStrPrediction()
2873   {
2874     AlignmentView seqs = null;
2875
2876     if ( (viewport.getSelectionGroup() != null) &&
2877         (viewport.getSelectionGroup().getSize() > 0))
2878     {
2879       seqs = viewport.getAlignmentView(true);
2880     }
2881     else
2882     {
2883       seqs = viewport.getAlignmentView(false);
2884     }
2885     // limit sequences - JBPNote in future - could spawn multiple prediction jobs
2886     // TODO: viewport.alignment.isAligned is a global state - the local selection may well be aligned - we preserve 2.0.8 behaviour for moment.
2887     if (!viewport.alignment.isAligned())
2888     {
2889       seqs.setSequences(new SeqCigar[]
2890                         {seqs.getSequences()[0]});
2891     }
2892     return seqs;
2893   }
2894
2895   /**
2896    * DOCUMENT ME!
2897    *
2898    * @param e DOCUMENT ME!
2899    */
2900   protected void LoadtreeMenuItem_actionPerformed(ActionEvent e)
2901   {
2902     // Pick the tree file
2903     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2904         getProperty(
2905             "LAST_DIRECTORY"));
2906     chooser.setFileView(new JalviewFileView());
2907     chooser.setDialogTitle("Select a newick-like tree file");
2908     chooser.setToolTipText("Load a tree file");
2909
2910     int value = chooser.showOpenDialog(null);
2911
2912     if (value == JalviewFileChooser.APPROVE_OPTION)
2913     {
2914       String choice = chooser.getSelectedFile().getPath();
2915       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
2916
2917       try
2918       {
2919         jalview.io.NewickFile fin = new jalview.io.NewickFile(choice,
2920             "File");
2921         viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
2922       }
2923       catch (Exception ex)
2924       {
2925         JOptionPane.showMessageDialog(Desktop.desktop,
2926                                       "Problem reading tree file",
2927                                       ex.getMessage(),
2928                                       JOptionPane.WARNING_MESSAGE);
2929         ex.printStackTrace();
2930       }
2931     }
2932   }
2933
2934   public TreePanel ShowNewickTree(NewickFile nf, String title)
2935   {
2936     return ShowNewickTree(nf, title, 600, 500, 4, 5);
2937   }
2938
2939   public TreePanel ShowNewickTree(NewickFile nf, String title,
2940                                   AlignmentView input)
2941   {
2942     return ShowNewickTree(nf, title, input, 600, 500, 4, 5);
2943   }
2944
2945   public TreePanel ShowNewickTree(NewickFile nf, String title, int w, int h,
2946                                   int x, int y)
2947   {
2948     return ShowNewickTree(nf, title, null, w, h, x, y);
2949   }
2950
2951   /**
2952    * Add a treeviewer for the tree extracted from a newick file object to the current alignment view
2953    *
2954    * @param nf the tree
2955    * @param title tree viewer title
2956    * @param input Associated alignment input data (or null)
2957    * @param w width
2958    * @param h height
2959    * @param x position
2960    * @param y position
2961    * @return TreePanel handle
2962    */
2963   public TreePanel ShowNewickTree(NewickFile nf, String title,
2964                                   AlignmentView input, int w, int h, int x,
2965                                   int y)
2966   {
2967     TreePanel tp = null;
2968
2969     try
2970     {
2971       nf.parse();
2972
2973       if (nf.getTree() != null)
2974       {
2975         tp = new TreePanel(alignPanel,
2976                            "FromFile",
2977                            title,
2978                            nf, input);
2979
2980         tp.setSize(w, h);
2981
2982         if (x > 0 && y > 0)
2983         {
2984           tp.setLocation(x, y);
2985         }
2986
2987         Desktop.addInternalFrame(tp, title, w, h);
2988       }
2989     }
2990     catch (Exception ex)
2991     {
2992       ex.printStackTrace();
2993     }
2994
2995     return tp;
2996   }
2997
2998   /**
2999    * Generates menu items and listener event actions for web service clients
3000    *
3001    */
3002   public void BuildWebServiceMenu()
3003   {
3004     if ( (Discoverer.services != null)
3005         && (Discoverer.services.size() > 0))
3006     {
3007       Vector msaws = (Vector) Discoverer.services.get("MsaWS");
3008       Vector secstrpr = (Vector) Discoverer.services.get("SecStrPred");
3009       Vector wsmenu = new Vector();
3010       final AlignFrame af = this;
3011       if (msaws != null)
3012       {
3013         // Add any Multiple Sequence Alignment Services
3014         final JMenu msawsmenu = new JMenu("Alignment");
3015         for (int i = 0, j = msaws.size(); i < j; i++)
3016         {
3017           final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) msaws.
3018               get(i);
3019           final JMenuItem method = new JMenuItem(sh.getName());
3020           method.addActionListener(new ActionListener()
3021           {
3022             public void actionPerformed(ActionEvent e)
3023             {
3024               AlignmentView msa = gatherSequencesForAlignment();
3025               new jalview.ws.MsaWSClient(sh, title, msa,
3026                                          false, true,
3027                                          viewport.getAlignment().getDataset(),
3028                                          af);
3029
3030             }
3031
3032           });
3033           msawsmenu.add(method);
3034           // Deal with services that we know accept partial alignments.
3035           if (sh.getName().indexOf("lustal") > -1)
3036           {
3037             // We know that ClustalWS can accept partial alignments for refinement.
3038             final JMenuItem methodR = new JMenuItem(sh.getName() + " Realign");
3039             methodR.addActionListener(new ActionListener()
3040             {
3041               public void actionPerformed(ActionEvent e)
3042               {
3043                 AlignmentView msa = gatherSequencesForAlignment();
3044                 new jalview.ws.MsaWSClient(sh, title, msa,
3045                                            true, true,
3046                                            viewport.getAlignment().getDataset(),
3047                                            af);
3048
3049               }
3050
3051             });
3052             msawsmenu.add(methodR);
3053
3054           }
3055         }
3056         wsmenu.add(msawsmenu);
3057       }
3058       if (secstrpr != null)
3059       {
3060         // Add any secondary structure prediction services
3061         final JMenu secstrmenu = new JMenu("Secondary Structure Prediction");
3062         for (int i = 0, j = secstrpr.size(); i < j; i++)
3063         {
3064           final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle)
3065               secstrpr.get(i);
3066           final JMenuItem method = new JMenuItem(sh.getName());
3067           method.addActionListener(new ActionListener()
3068           {
3069             public void actionPerformed(ActionEvent e)
3070             {
3071               AlignmentView msa = gatherSeqOrMsaForSecStrPrediction();
3072               if (msa.getSequences().length == 1)
3073               {
3074                 // Single Sequence prediction
3075                 new jalview.ws.JPredClient(sh, title, false, msa, af, true);
3076               }
3077               else
3078               {
3079                 if (msa.getSequences().length > 1)
3080                 {
3081                   // Sequence profile based prediction
3082                   new jalview.ws.JPredClient(sh,
3083                                              title, true, msa, af, true);
3084                 }
3085               }
3086             }
3087           });
3088           secstrmenu.add(method);
3089         }
3090         wsmenu.add(secstrmenu);
3091       }
3092       this.webService.removeAll();
3093       for (int i = 0, j = wsmenu.size(); i < j; i++)
3094       {
3095         webService.add( (JMenu) wsmenu.get(i));
3096       }
3097     }
3098     else
3099     {
3100       this.webService.removeAll();
3101       this.webService.add(this.webServiceNoServices);
3102     }
3103     // TODO: add in rediscovery function
3104     // TODO: reduce code redundancy.
3105     // TODO: group services by location as well as function.
3106   }
3107
3108   /* public void vamsasStore_actionPerformed(ActionEvent e)
3109    {
3110      JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
3111          getProperty("LAST_DIRECTORY"));
3112
3113      chooser.setFileView(new JalviewFileView());
3114      chooser.setDialogTitle("Export to Vamsas file");
3115      chooser.setToolTipText("Export");
3116
3117      int value = chooser.showSaveDialog(this);
3118
3119      if (value == JalviewFileChooser.APPROVE_OPTION)
3120      {
3121    jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport);
3122        //vs.store(chooser.getSelectedFile().getAbsolutePath()   );
3123        vs.storeJalview( chooser.getSelectedFile().getAbsolutePath(), this);
3124      }
3125    }*/
3126
3127
3128
3129
3130   public void showTranslation_actionPerformed(ActionEvent e)
3131   {
3132     SequenceI[] selection = viewport.getSelectionAsNewSequence();
3133     String[] seqstring = viewport.getViewAsString(true);
3134
3135     int s, sSize = selection.length;
3136     SequenceI[] newSeq = new SequenceI[sSize];
3137
3138     int res, resSize;
3139     StringBuffer protein;
3140     String seq;
3141     for (s = 0; s < sSize; s++)
3142     {
3143       protein = new StringBuffer();
3144       seq = AlignSeq.extractGaps("-. ", seqstring[s]);
3145       resSize = seq.length();
3146       resSize -= resSize % 3;
3147
3148       for (res = 0; res < resSize; res += 3)
3149       {
3150         String codon = seq.substring(res, res + 3);
3151         codon = codon.replace('U', 'T');
3152         String aa = ResidueProperties.codonTranslate(codon);
3153         if (aa == null)
3154         {
3155           protein.append(viewport.getGapCharacter());
3156         }
3157         else if (aa.equals("STOP"))
3158         {
3159           protein.append("X");
3160         }
3161         else
3162         {
3163           protein.append(aa);
3164         }
3165       }
3166       newSeq[s] = new Sequence(selection[s].getName(),
3167                                protein.toString());
3168     }
3169
3170     AlignmentI al = new Alignment(newSeq);
3171     al.setDataset(null);
3172
3173     ////////////////////////////////
3174     // Copy annotations across
3175     jalview.datamodel.AlignmentAnnotation[] annotations
3176         = viewport.alignment.getAlignmentAnnotation();
3177     int a, aSize;
3178     if (annotations != null)
3179     {
3180       for (int i = 0; i < annotations.length; i++)
3181       {
3182         if (annotations[i] == viewport.quality ||
3183             annotations[i] == viewport.conservation ||
3184             annotations[i] == viewport.consensus)
3185         {
3186           System.out.println("COPT HERE");
3187           continue;
3188         }
3189
3190         aSize = viewport.alignment.getWidth() / 3;
3191         jalview.datamodel.Annotation[] anots =
3192             new jalview.datamodel.Annotation[aSize];
3193
3194         for (a = 0; a < viewport.alignment.getWidth(); a++)
3195         {
3196           if (annotations[i].annotations[a] == null
3197               || annotations[i].annotations[a] == null)
3198           {
3199             continue;
3200           }
3201
3202           anots[a / 3] = new Annotation(
3203               annotations[i].annotations[a].displayCharacter,
3204               annotations[i].annotations[a].description,
3205               annotations[i].annotations[a].secondaryStructure,
3206               annotations[i].annotations[a].value,
3207               annotations[i].annotations[a].colour);
3208         }
3209
3210         jalview.datamodel.AlignmentAnnotation aa
3211             = new jalview.datamodel.AlignmentAnnotation(annotations[i].label,
3212             annotations[i].description, anots);
3213         al.addAnnotation(aa);
3214       }
3215     }
3216
3217     AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
3218     Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
3219                              DEFAULT_WIDTH,
3220                              DEFAULT_HEIGHT);
3221
3222   }
3223
3224   /**
3225    * DOCUMENT ME!
3226    *
3227    * @param String DOCUMENT ME!
3228    */
3229   public boolean parseFeaturesFile(String file, String type)
3230   {
3231     boolean featuresFile = false;
3232     try
3233     {
3234       featuresFile = new FeaturesFile(file,
3235           type).parse(viewport.alignment.getDataset(),
3236                       alignPanel.seqPanel.seqCanvas.
3237                       getFeatureRenderer().featureColours,
3238                       false);
3239     }
3240     catch (Exception ex)
3241     {
3242       ex.printStackTrace();
3243     }
3244
3245     if (featuresFile)
3246     {
3247       viewport.showSequenceFeatures = true;
3248       showSeqFeatures.setSelected(true);
3249       alignPanel.repaint();
3250     }
3251
3252     return featuresFile;
3253   }
3254
3255   public void dragEnter(DropTargetDragEvent evt)
3256   {}
3257
3258   public void dragExit(DropTargetEvent evt)
3259   {}
3260
3261   public void dragOver(DropTargetDragEvent evt)
3262   {}
3263
3264   public void dropActionChanged(DropTargetDragEvent evt)
3265   {}
3266
3267   public void drop(DropTargetDropEvent evt)
3268   {
3269     Transferable t = evt.getTransferable();
3270     java.util.List files = null;
3271
3272     try
3273     {
3274       DataFlavor uriListFlavor = new DataFlavor(
3275           "text/uri-list;class=java.lang.String");
3276       if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3277       {
3278         //Works on Windows and MacOSX
3279         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3280         files = (java.util.List) t.getTransferData(DataFlavor.
3281             javaFileListFlavor);
3282       }
3283       else if (t.isDataFlavorSupported(uriListFlavor))
3284       {
3285         // This is used by Unix drag system
3286         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3287         String data = (String) t.getTransferData(uriListFlavor);
3288         files = new java.util.ArrayList(1);
3289         for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3290             data,
3291             "\r\n");
3292              st.hasMoreTokens(); )
3293         {
3294           String s = st.nextToken();
3295           if (s.startsWith("#"))
3296           {
3297             // the line is a comment (as per the RFC 2483)
3298             continue;
3299           }
3300
3301           java.net.URI uri = new java.net.URI(s);
3302           java.io.File file = new java.io.File(uri);
3303           files.add(file);
3304         }
3305       }
3306     }
3307     catch (Exception e)
3308     {
3309       e.printStackTrace();
3310     }
3311     if (files != null)
3312     {
3313       try
3314       {
3315
3316         for (int i = 0; i < files.size(); i++)
3317         {
3318           loadJalviewDataFile(files.get(i).toString());
3319         }
3320       }
3321       catch (Exception ex)
3322       {
3323         ex.printStackTrace();
3324       }
3325     }
3326   }
3327
3328   // This method will attempt to load a "dropped" file first by testing
3329   // whether its and Annotation file, then features file. If both are
3330   // false then the user may have dropped an alignment file onto this
3331   // AlignFrame
3332   public void loadJalviewDataFile(String file)
3333   {
3334     try
3335     {
3336       String protocol = "File";
3337
3338       if (file.indexOf("http:") > -1 || file.indexOf("file:") > -1)
3339       {
3340         protocol = "URL";
3341       }
3342
3343       boolean isAnnotation = new AnnotationFile().readAnnotationFile(viewport.
3344           alignment, file, protocol);
3345
3346       if (!isAnnotation)
3347       {
3348         boolean isGroupsFile = parseFeaturesFile(file, protocol);
3349         if (!isGroupsFile)
3350         {
3351           String format = new IdentifyFile().Identify(file, protocol);
3352
3353           if (format.equalsIgnoreCase("JnetFile"))
3354           {
3355             jalview.io.JPredFile predictions = new jalview.io.JPredFile(
3356                 file, protocol);
3357             new JnetAnnotationMaker().add_annotation(predictions,
3358                 viewport.getAlignment(),
3359                 0, false);
3360             alignPanel.adjustAnnotationHeight();
3361             alignPanel.repaint();
3362           }
3363           else
3364           {
3365             new FileLoader().LoadFile(viewport, file, protocol, format);
3366           }
3367         }
3368       }
3369       else
3370       {
3371         // (isAnnotation)
3372         alignPanel.adjustAnnotationHeight();
3373       }
3374
3375     }
3376     catch (Exception ex)
3377     {
3378       ex.printStackTrace();
3379     }
3380   }
3381
3382   public void tabSelectionChanged(int index)
3383   {
3384     if (index > -1)
3385     {
3386       alignPanel = (AlignmentPanel) alignPanels.elementAt(index);
3387       viewport = alignPanel.av;
3388       setMenusFromViewport(viewport);
3389     }
3390   }
3391
3392   public void tabbedPane_mousePressed(MouseEvent e)
3393   {
3394     if (SwingUtilities.isRightMouseButton(e))
3395     {
3396       String reply = JOptionPane.showInternalInputDialog(this,
3397           "Enter View Name",
3398           "Edit View Name",
3399           JOptionPane.QUESTION_MESSAGE);
3400
3401       if (reply != null)
3402       {
3403         viewport.viewName = reply;
3404         tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
3405       }
3406     }
3407   }
3408
3409   public AlignViewport getCurrentView()
3410   {
3411     return viewport;
3412   }
3413 }
3414
3415 class PrintThread
3416     extends Thread
3417 {
3418   AlignmentPanel ap;
3419   public PrintThread(AlignmentPanel ap)
3420   {
3421     this.ap = ap;
3422   }
3423
3424   static PageFormat pf;
3425   public void run()
3426   {
3427     PrinterJob printJob = PrinterJob.getPrinterJob();
3428
3429     if (pf != null)
3430     {
3431       printJob.setPrintable(ap, pf);
3432     }
3433     else
3434     {
3435       printJob.setPrintable(ap);
3436     }
3437
3438     if (printJob.printDialog())
3439     {
3440       try
3441       {
3442         printJob.print();
3443       }
3444       catch (Exception PrintException)
3445       {
3446         PrintException.printStackTrace();
3447       }
3448     }
3449   }
3450 }