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