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