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