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