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