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