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