check cursor is visible for hidden cols
[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     new Finder();
1712   }
1713
1714   public void newView_actionPerformed(ActionEvent e)
1715   {
1716     AlignmentPanel newap =
1717         new Jalview2XML().copyAlignPanel(alignPanel, true);
1718
1719     if (viewport.viewName == null)
1720       viewport.viewName = "View 1";
1721
1722     newap.av.historyList = viewport.historyList;
1723     newap.av.redoList = viewport.redoList;
1724     newap.av.viewName = "View " +
1725         (Desktop.getViewCount(viewport.getSequenceSetId()) + 1);
1726
1727     addAlignmentPanel(newap, false);
1728
1729     if(alignPanels.size()==2)
1730     {
1731       viewport.gatherViewsHere = true;
1732     }
1733     tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
1734   }
1735
1736
1737   /**
1738    * DOCUMENT ME!
1739    *
1740    * @param e DOCUMENT ME!
1741    */
1742   public void font_actionPerformed(ActionEvent e)
1743   {
1744     new FontChooser(alignPanel);
1745   }
1746
1747
1748   /**
1749    * DOCUMENT ME!
1750    *
1751    * @param e DOCUMENT ME!
1752    */
1753   protected void seqLimit_actionPerformed(ActionEvent e)
1754   {
1755     viewport.setShowJVSuffix(seqLimits.isSelected());
1756
1757     alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel.calculateIdWidth());
1758     alignPanel.repaint();
1759   }
1760
1761   public void idRightAlign_actionPerformed(ActionEvent e)
1762   {
1763     viewport.idsAlignRight = idRightAlign.isSelected();
1764     alignPanel.repaint();
1765   }
1766
1767
1768
1769   /**
1770    * DOCUMENT ME!
1771    *
1772    * @param e DOCUMENT ME!
1773    */
1774   protected void colourTextMenuItem_actionPerformed(ActionEvent e)
1775   {
1776     viewport.setColourText(colourTextMenuItem.isSelected());
1777     alignPanel.repaint();
1778   }
1779
1780   /**
1781    * DOCUMENT ME!
1782    *
1783    * @param e DOCUMENT ME!
1784    */
1785   public void wrapMenuItem_actionPerformed(ActionEvent e)
1786   {
1787     scaleAbove.setVisible(wrapMenuItem.isSelected());
1788     scaleLeft.setVisible(wrapMenuItem.isSelected());
1789     scaleRight.setVisible(wrapMenuItem.isSelected());
1790     viewport.setWrapAlignment(wrapMenuItem.isSelected());
1791     alignPanel.setWrapAlignment(wrapMenuItem.isSelected());
1792   }
1793
1794   public void showAllSeqs_actionPerformed(ActionEvent e)
1795   {
1796     viewport.showAllHiddenSeqs();
1797   }
1798
1799   public void showAllColumns_actionPerformed(ActionEvent e)
1800   {
1801     viewport.showAllHiddenColumns();
1802     repaint();
1803   }
1804
1805   public void hideSelSequences_actionPerformed(ActionEvent e)
1806   {
1807     viewport.hideAllSelectedSeqs();
1808     alignPanel.repaint();
1809   }
1810
1811   public void hideSelColumns_actionPerformed(ActionEvent e)
1812   {
1813     viewport.hideSelectedColumns();
1814     alignPanel.repaint();
1815   }
1816
1817   public void hiddenMarkers_actionPerformed(ActionEvent e)
1818   {
1819     viewport.setShowHiddenMarkers(hiddenMarkers.isSelected());
1820     repaint();
1821   }
1822
1823   /**
1824    * DOCUMENT ME!
1825    *
1826    * @param e DOCUMENT ME!
1827    */
1828   protected void scaleAbove_actionPerformed(ActionEvent e)
1829   {
1830     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
1831     alignPanel.repaint();
1832   }
1833
1834   /**
1835    * DOCUMENT ME!
1836    *
1837    * @param e DOCUMENT ME!
1838    */
1839   protected void scaleLeft_actionPerformed(ActionEvent e)
1840   {
1841     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
1842     alignPanel.repaint();
1843   }
1844
1845   /**
1846    * DOCUMENT ME!
1847    *
1848    * @param e DOCUMENT ME!
1849    */
1850   protected void scaleRight_actionPerformed(ActionEvent e)
1851   {
1852     viewport.setScaleRightWrapped(scaleRight.isSelected());
1853     alignPanel.repaint();
1854   }
1855
1856   /**
1857    * DOCUMENT ME!
1858    *
1859    * @param e DOCUMENT ME!
1860    */
1861   public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
1862   {
1863     viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
1864     alignPanel.repaint();
1865   }
1866
1867   /**
1868    * DOCUMENT ME!
1869    *
1870    * @param e DOCUMENT ME!
1871    */
1872   public void viewTextMenuItem_actionPerformed(ActionEvent e)
1873   {
1874     viewport.setShowText(viewTextMenuItem.isSelected());
1875     alignPanel.repaint();
1876   }
1877
1878   /**
1879    * DOCUMENT ME!
1880    *
1881    * @param e DOCUMENT ME!
1882    */
1883   protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
1884   {
1885     viewport.setRenderGaps(renderGapsMenuItem.isSelected());
1886     alignPanel.repaint();
1887   }
1888
1889
1890   public FeatureSettings featureSettings;
1891   public void featureSettings_actionPerformed(ActionEvent e)
1892   {
1893     if(featureSettings !=null )
1894     {
1895       featureSettings.close();
1896       featureSettings = null;
1897     }
1898     featureSettings = new FeatureSettings(this);
1899   }
1900
1901   /**
1902    * DOCUMENT ME!
1903    *
1904    * @param evt DOCUMENT ME!
1905    */
1906   public void showSeqFeatures_actionPerformed(ActionEvent evt)
1907   {
1908     viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
1909     alignPanel.repaint();
1910     if (alignPanel.getOverviewPanel() != null)
1911     {
1912       alignPanel.getOverviewPanel().updateOverviewImage();
1913     }
1914   }
1915
1916   /**
1917    * DOCUMENT ME!
1918    *
1919    * @param e DOCUMENT ME!
1920    */
1921   public void annotationPanelMenuItem_actionPerformed(ActionEvent e)
1922   {
1923     viewport.setShowAnnotation(annotationPanelMenuItem.isSelected());
1924     alignPanel.setAnnotationVisible(annotationPanelMenuItem.isSelected());
1925   }
1926
1927   /**
1928    * DOCUMENT ME!
1929    *
1930    * @param e DOCUMENT ME!
1931    */
1932   public void overviewMenuItem_actionPerformed(ActionEvent e)
1933   {
1934     if (alignPanel.overviewPanel != null)
1935     {
1936       return;
1937     }
1938
1939     JInternalFrame frame = new JInternalFrame();
1940     OverviewPanel overview = new OverviewPanel(alignPanel);
1941     frame.setContentPane(overview);
1942     Desktop.addInternalFrame(frame, "Overview " + this.getTitle(),
1943                              frame.getWidth(), frame.getHeight());
1944     frame.pack();
1945     frame.setLayer(JLayeredPane.PALETTE_LAYER);
1946     frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
1947     {
1948       public void internalFrameClosed(
1949           javax.swing.event.InternalFrameEvent evt)
1950       {
1951         alignPanel.setOverviewPanel(null);
1952       }
1953       ;
1954     });
1955
1956     alignPanel.setOverviewPanel(overview);
1957   }
1958
1959   public void textColour_actionPerformed(ActionEvent e)
1960   {
1961     int original1 = viewport.textColour.getRGB();
1962     int original2 = viewport.textColour2.getRGB();
1963     int thresh = viewport.thresholdTextColour;
1964     final JSlider slider = new JSlider(0, 750, viewport.thresholdTextColour);
1965     final JButton col1 = new JButton("DARK");
1966     col1.setBackground(viewport.textColour);
1967     col1.setForeground(viewport.textColour);
1968     final JButton col2 = new JButton("LIGHT");
1969     col2.setBackground(viewport.textColour2);
1970     col2.setForeground(viewport.textColour2);
1971     final JPanel bigpanel = new JPanel(new BorderLayout());
1972     JPanel panel = new JPanel();
1973     bigpanel.add(panel, BorderLayout.CENTER);
1974     bigpanel.add(new JLabel(
1975       "<html><i>Select a dark and light text colour, then set the threshold to"
1976      +"<br>switch between colours, based on background colour</i></html>"),
1977                  BorderLayout.NORTH);
1978     panel.add(col1);
1979     panel.add(slider);
1980     panel.add(col2);
1981
1982     col1.addActionListener(new ActionListener()
1983         {
1984           public void actionPerformed(ActionEvent e)
1985           {
1986             Color col = JColorChooser.showDialog(bigpanel,
1987                                                  "Select Colour for Text",
1988                                                  viewport.textColour);
1989             if (col != null)
1990             {
1991               viewport.textColour = col;
1992               col1.setBackground(col);
1993               col1.setForeground(col);
1994               if(viewport.colourAppliesToAllGroups)
1995                 setGroupTextColour();
1996             }
1997             alignPanel.repaint();
1998           }
1999         });
2000
2001     col2.addActionListener(new ActionListener()
2002     {
2003       public void actionPerformed(ActionEvent e)
2004       {
2005         Color col = JColorChooser.showDialog(bigpanel,
2006                                              "Select Colour for Text",
2007                                              viewport.textColour);
2008         if (col != null)
2009         {
2010           viewport.textColour2 = col;
2011           col2.setBackground(col);
2012           col2.setForeground(col);
2013           if(viewport.colourAppliesToAllGroups)
2014                 setGroupTextColour();
2015         }
2016         alignPanel.repaint();
2017       }
2018     });
2019
2020
2021     slider.addChangeListener(new ChangeListener()
2022     {
2023       public void stateChanged(ChangeEvent evt)
2024       {
2025         viewport.thresholdTextColour = slider.getValue();
2026         if(viewport.colourAppliesToAllGroups)
2027                 setGroupTextColour();
2028         alignPanel.repaint();
2029       }
2030     });
2031
2032     int reply = JOptionPane.showInternalOptionDialog(this,
2033                                                  bigpanel,
2034                                                  "Adjust Foreground Text Colour Threshold",
2035                                                  JOptionPane.OK_CANCEL_OPTION,
2036                                                  JOptionPane.QUESTION_MESSAGE,
2037                                                  null,
2038                                                  null, null);
2039
2040     if(reply==JOptionPane.CANCEL_OPTION)
2041     {
2042       viewport.textColour = new Color(original1);
2043       viewport.textColour2 = new Color(original2);
2044       viewport.thresholdTextColour = thresh;
2045     }
2046   }
2047
2048   void setGroupTextColour()
2049   {
2050     if(viewport.alignment.getGroups()==null)
2051       return;
2052
2053     Vector groups = viewport.alignment.getGroups();
2054
2055     for(int i=0; i<groups.size(); i++)
2056     {
2057       SequenceGroup sg = (SequenceGroup)groups.elementAt(i);
2058       sg.textColour = viewport.textColour;
2059       sg.textColour2 = viewport.textColour2;
2060       sg.thresholdTextColour = viewport.thresholdTextColour;
2061     }
2062
2063
2064   }
2065
2066
2067   /**
2068    * DOCUMENT ME!
2069    *
2070    * @param e DOCUMENT ME!
2071    */
2072   protected void noColourmenuItem_actionPerformed(ActionEvent e)
2073   {
2074     changeColour(null);
2075   }
2076
2077   /**
2078    * DOCUMENT ME!
2079    *
2080    * @param e DOCUMENT ME!
2081    */
2082   public void clustalColour_actionPerformed(ActionEvent e)
2083   {
2084     changeColour(new ClustalxColourScheme(
2085         viewport.alignment.getSequences(), viewport.alignment.getWidth()));
2086   }
2087
2088   /**
2089    * DOCUMENT ME!
2090    *
2091    * @param e DOCUMENT ME!
2092    */
2093   public void zappoColour_actionPerformed(ActionEvent e)
2094   {
2095     changeColour(new ZappoColourScheme());
2096   }
2097
2098   /**
2099    * DOCUMENT ME!
2100    *
2101    * @param e DOCUMENT ME!
2102    */
2103   public void taylorColour_actionPerformed(ActionEvent e)
2104   {
2105     changeColour(new TaylorColourScheme());
2106   }
2107
2108   /**
2109    * DOCUMENT ME!
2110    *
2111    * @param e DOCUMENT ME!
2112    */
2113   public void hydrophobicityColour_actionPerformed(ActionEvent e)
2114   {
2115     changeColour(new HydrophobicColourScheme());
2116   }
2117
2118   /**
2119    * DOCUMENT ME!
2120    *
2121    * @param e DOCUMENT ME!
2122    */
2123   public void helixColour_actionPerformed(ActionEvent e)
2124   {
2125     changeColour(new HelixColourScheme());
2126   }
2127
2128   /**
2129    * DOCUMENT ME!
2130    *
2131    * @param e DOCUMENT ME!
2132    */
2133   public void strandColour_actionPerformed(ActionEvent e)
2134   {
2135     changeColour(new StrandColourScheme());
2136   }
2137
2138   /**
2139    * DOCUMENT ME!
2140    *
2141    * @param e DOCUMENT ME!
2142    */
2143   public void turnColour_actionPerformed(ActionEvent e)
2144   {
2145     changeColour(new TurnColourScheme());
2146   }
2147
2148   /**
2149    * DOCUMENT ME!
2150    *
2151    * @param e DOCUMENT ME!
2152    */
2153   public void buriedColour_actionPerformed(ActionEvent e)
2154   {
2155     changeColour(new BuriedColourScheme());
2156   }
2157
2158   /**
2159    * DOCUMENT ME!
2160    *
2161    * @param e DOCUMENT ME!
2162    */
2163   public void nucleotideColour_actionPerformed(ActionEvent e)
2164   {
2165     changeColour(new NucleotideColourScheme());
2166   }
2167
2168   public void annotationColour_actionPerformed(ActionEvent e)
2169   {
2170     new AnnotationColourChooser(viewport, alignPanel);
2171   }
2172
2173
2174   /**
2175    * DOCUMENT ME!
2176    *
2177    * @param e DOCUMENT ME!
2178    */
2179   protected void applyToAllGroups_actionPerformed(ActionEvent e)
2180   {
2181     viewport.setColourAppliesToAllGroups(applyToAllGroups.isSelected());
2182   }
2183
2184   /**
2185    * DOCUMENT ME!
2186    *
2187    * @param cs DOCUMENT ME!
2188    */
2189   public void changeColour(ColourSchemeI cs)
2190   {
2191     int threshold = 0;
2192
2193     if(cs!=null)
2194     {
2195       if (viewport.getAbovePIDThreshold())
2196       {
2197         threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
2198                                                    "Background");
2199
2200         cs.setThreshold(threshold,
2201                         viewport.getIgnoreGapsConsensus());
2202
2203         viewport.setGlobalColourScheme(cs);
2204       }
2205       else
2206       {
2207         cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
2208       }
2209
2210       if (viewport.getConservationSelected())
2211       {
2212
2213         Alignment al = (Alignment) viewport.alignment;
2214         Conservation c = new Conservation("All",
2215                                           ResidueProperties.propHash, 3,
2216                                           al.getSequences(), 0,
2217                                           al.getWidth() - 1);
2218
2219         c.calculate();
2220         c.verdict(false, viewport.ConsPercGaps);
2221
2222         cs.setConservation(c);
2223
2224         cs.setConservationInc(SliderPanel.setConservationSlider(alignPanel, cs,
2225             "Background"));
2226       }
2227       else
2228       {
2229         cs.setConservation(null);
2230       }
2231
2232       cs.setConsensus(viewport.hconsensus);
2233     }
2234
2235     viewport.setGlobalColourScheme(cs);
2236
2237     if (viewport.getColourAppliesToAllGroups())
2238     {
2239       Vector groups = viewport.alignment.getGroups();
2240
2241       for (int i = 0; i < groups.size(); i++)
2242       {
2243         SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
2244
2245         if (cs == null)
2246         {
2247           sg.cs = null;
2248           continue;
2249         }
2250
2251         if (cs instanceof ClustalxColourScheme)
2252         {
2253           sg.cs = new ClustalxColourScheme(
2254               sg.getSequences(true), sg.getWidth());
2255         }
2256         else if (cs instanceof UserColourScheme)
2257         {
2258           sg.cs = new UserColourScheme( ( (UserColourScheme) cs).getColours());
2259         }
2260         else
2261         {
2262           try
2263           {
2264             sg.cs = (ColourSchemeI) cs.getClass().newInstance();
2265           }
2266           catch (Exception ex)
2267           {
2268           }
2269         }
2270
2271         if (viewport.getAbovePIDThreshold()
2272             || cs instanceof PIDColourScheme
2273             || cs instanceof Blosum62ColourScheme)
2274         {
2275          sg.cs.setThreshold(threshold,
2276                 viewport.getIgnoreGapsConsensus());
2277
2278          sg.cs.setConsensus(AAFrequency.calculate(
2279              sg.getSequences(true), sg.getStartRes(),
2280              sg.getEndRes()+1));
2281        }
2282         else
2283           sg.cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
2284
2285
2286         if (viewport.getConservationSelected())
2287         {
2288           Conservation c = new Conservation("Group",
2289                                             ResidueProperties.propHash, 3,
2290                                             sg.getSequences(true),
2291                                             sg.getStartRes(),
2292                                             sg.getEndRes()+1);
2293           c.calculate();
2294           c.verdict(false, viewport.ConsPercGaps);
2295           sg.cs.setConservation(c);
2296         }
2297         else
2298           sg.cs.setConservation(null);
2299       }
2300     }
2301
2302     if (alignPanel.getOverviewPanel() != null)
2303     {
2304       alignPanel.getOverviewPanel().updateOverviewImage();
2305     }
2306
2307     alignPanel.repaint();
2308   }
2309
2310   /**
2311    * DOCUMENT ME!
2312    *
2313    * @param e DOCUMENT ME!
2314    */
2315   protected void modifyPID_actionPerformed(ActionEvent e)
2316   {
2317     if (viewport.getAbovePIDThreshold() && viewport.globalColourScheme!=null)
2318     {
2319       SliderPanel.setPIDSliderSource(alignPanel,
2320                                      viewport.getGlobalColourScheme(),
2321                                      "Background");
2322       SliderPanel.showPIDSlider();
2323     }
2324   }
2325
2326   /**
2327    * DOCUMENT ME!
2328    *
2329    * @param e DOCUMENT ME!
2330    */
2331   protected void modifyConservation_actionPerformed(ActionEvent e)
2332   {
2333     if (viewport.getConservationSelected() && viewport.globalColourScheme!=null)
2334     {
2335       SliderPanel.setConservationSlider(alignPanel,
2336                                         viewport.globalColourScheme,
2337                                         "Background");
2338       SliderPanel.showConservationSlider();
2339     }
2340   }
2341
2342   /**
2343    * DOCUMENT ME!
2344    *
2345    * @param e DOCUMENT ME!
2346    */
2347   protected void conservationMenuItem_actionPerformed(ActionEvent e)
2348   {
2349     viewport.setConservationSelected(conservationMenuItem.isSelected());
2350
2351     viewport.setAbovePIDThreshold(false);
2352     abovePIDThreshold.setSelected(false);
2353
2354     changeColour(viewport.getGlobalColourScheme());
2355
2356     modifyConservation_actionPerformed(null);
2357   }
2358
2359   /**
2360    * DOCUMENT ME!
2361    *
2362    * @param e DOCUMENT ME!
2363    */
2364   public void abovePIDThreshold_actionPerformed(ActionEvent e)
2365   {
2366     viewport.setAbovePIDThreshold(abovePIDThreshold.isSelected());
2367
2368     conservationMenuItem.setSelected(false);
2369     viewport.setConservationSelected(false);
2370
2371     changeColour(viewport.getGlobalColourScheme());
2372
2373     modifyPID_actionPerformed(null);
2374   }
2375
2376   /**
2377    * DOCUMENT ME!
2378    *
2379    * @param e DOCUMENT ME!
2380    */
2381   public void userDefinedColour_actionPerformed(ActionEvent e)
2382   {
2383     if (e.getActionCommand().equals("User Defined..."))
2384     {
2385       new UserDefinedColours(alignPanel, null);
2386     }
2387     else
2388     {
2389       UserColourScheme udc = (UserColourScheme) UserDefinedColours.
2390           getUserColourSchemes().get(e.getActionCommand());
2391
2392       changeColour(udc);
2393     }
2394   }
2395
2396   public void updateUserColourMenu()
2397   {
2398
2399     Component[] menuItems = colourMenu.getMenuComponents();
2400     int i, iSize = menuItems.length;
2401     for (i = 0; i < iSize; i++)
2402     {
2403       if (menuItems[i].getName() != null &&
2404           menuItems[i].getName().equals("USER_DEFINED"))
2405       {
2406         colourMenu.remove(menuItems[i]);
2407         iSize--;
2408       }
2409     }
2410     if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)
2411     {
2412       java.util.Enumeration userColours = jalview.gui.UserDefinedColours.
2413           getUserColourSchemes().keys();
2414
2415       while (userColours.hasMoreElements())
2416       {
2417         final JRadioButtonMenuItem radioItem = new JRadioButtonMenuItem(userColours.
2418             nextElement().toString());
2419         radioItem.setName("USER_DEFINED");
2420         radioItem.addMouseListener(new MouseAdapter()
2421             {
2422               public void mousePressed(MouseEvent evt)
2423               {
2424                 if(evt.isControlDown() || SwingUtilities.isRightMouseButton(evt))
2425                 {
2426                   radioItem.removeActionListener(radioItem.getActionListeners()[0]);
2427
2428                   int option = JOptionPane.showInternalConfirmDialog(jalview.gui.Desktop.desktop,
2429                       "Remove from default list?",
2430                       "Remove user defined colour",
2431                       JOptionPane.YES_NO_OPTION);
2432                   if(option == JOptionPane.YES_OPTION)
2433                   {
2434                     jalview.gui.UserDefinedColours.removeColourFromDefaults(radioItem.getText());
2435                     colourMenu.remove(radioItem);
2436                   }
2437                   else
2438                     radioItem.addActionListener(new ActionListener()
2439                     {
2440                       public void actionPerformed(ActionEvent evt)
2441                       {
2442                         userDefinedColour_actionPerformed(evt);
2443                       }
2444                     });
2445                 }
2446               }
2447             });
2448         radioItem.addActionListener(new ActionListener()
2449         {
2450           public void actionPerformed(ActionEvent evt)
2451           {
2452             userDefinedColour_actionPerformed(evt);
2453           }
2454         });
2455
2456         colourMenu.insert(radioItem, 15);
2457         colours.add(radioItem);
2458       }
2459     }
2460   }
2461
2462   /**
2463    * DOCUMENT ME!
2464    *
2465    * @param e DOCUMENT ME!
2466    */
2467   public void PIDColour_actionPerformed(ActionEvent e)
2468   {
2469     changeColour(new PIDColourScheme());
2470   }
2471
2472   /**
2473    * DOCUMENT ME!
2474    *
2475    * @param e DOCUMENT ME!
2476    */
2477   public void BLOSUM62Colour_actionPerformed(ActionEvent e)
2478   {
2479     changeColour(new Blosum62ColourScheme());
2480   }
2481
2482   /**
2483    * DOCUMENT ME!
2484    *
2485    * @param e DOCUMENT ME!
2486    */
2487   public void sortPairwiseMenuItem_actionPerformed(ActionEvent e)
2488   {
2489     SequenceI [] oldOrder = viewport.getAlignment().getSequencesArray();
2490     AlignmentSorter.sortByPID(viewport.getAlignment(),
2491                               viewport.getAlignment().getSequenceAt(0));
2492     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder, viewport.alignment));
2493     alignPanel.repaint();
2494   }
2495
2496   /**
2497    * DOCUMENT ME!
2498    *
2499    * @param e DOCUMENT ME!
2500    */
2501   public void sortIDMenuItem_actionPerformed(ActionEvent e)
2502   {
2503     SequenceI [] oldOrder = viewport.getAlignment().getSequencesArray();
2504     AlignmentSorter.sortByID(viewport.getAlignment());
2505     addHistoryItem(new OrderCommand("ID Sort", oldOrder, viewport.alignment));
2506     alignPanel.repaint();
2507   }
2508
2509   /**
2510    * DOCUMENT ME!
2511    *
2512    * @param e DOCUMENT ME!
2513    */
2514   public void sortGroupMenuItem_actionPerformed(ActionEvent e)
2515   {
2516     SequenceI [] oldOrder = viewport.getAlignment().getSequencesArray();
2517     AlignmentSorter.sortByGroup(viewport.getAlignment());
2518     addHistoryItem(new OrderCommand("Group Sort", oldOrder, viewport.alignment));
2519
2520     alignPanel.repaint();
2521   }
2522
2523   /**
2524    * DOCUMENT ME!
2525    *
2526    * @param e DOCUMENT ME!
2527    */
2528   public void removeRedundancyMenuItem_actionPerformed(ActionEvent e)
2529   {
2530     new RedundancyPanel(alignPanel, this);
2531   }
2532
2533
2534   /**
2535    * DOCUMENT ME!
2536    *
2537    * @param e DOCUMENT ME!
2538    */
2539   public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e)
2540   {
2541     if ( (viewport.getSelectionGroup() == null) ||
2542         (viewport.getSelectionGroup().getSize(false) < 2))
2543     {
2544       JOptionPane.showInternalMessageDialog(this,
2545                                             "You must select at least 2 sequences.",
2546                                             "Invalid Selection",
2547                                             JOptionPane.WARNING_MESSAGE);
2548     }
2549     else
2550     {
2551       JInternalFrame frame = new JInternalFrame();
2552       frame.setContentPane(new PairwiseAlignPanel(viewport));
2553       Desktop.addInternalFrame(frame, "Pairwise Alignment", 600, 500);
2554     }
2555   }
2556
2557   /**
2558    * DOCUMENT ME!
2559    *
2560    * @param e DOCUMENT ME!
2561    */
2562   public void PCAMenuItem_actionPerformed(ActionEvent e)
2563   {
2564     if ( ( (viewport.getSelectionGroup() != null) &&
2565           (viewport.getSelectionGroup().getSize(false) < 4) &&
2566           (viewport.getSelectionGroup().getSize(false) > 0)) ||
2567         (viewport.getAlignment().getHeight() < 4))
2568     {
2569       JOptionPane.showInternalMessageDialog(this,
2570                                             "Principal component analysis must take\n" +
2571                                             "at least 4 input sequences.",
2572                                             "Sequence selection insufficient",
2573                                             JOptionPane.WARNING_MESSAGE);
2574
2575       return;
2576     }
2577
2578      new PCAPanel(viewport);
2579   }
2580
2581
2582   public void autoCalculate_actionPerformed(ActionEvent e)
2583   {
2584     viewport.autoCalculateConsensus = autoCalculate.isSelected();
2585     if(viewport.autoCalculateConsensus)
2586     {
2587       viewport.firePropertyChange("alignment",
2588                                   null,
2589                                   viewport.getAlignment().getSequences());
2590     }
2591   }
2592
2593
2594   /**
2595    * DOCUMENT ME!
2596    *
2597    * @param e DOCUMENT ME!
2598    */
2599   public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)
2600   {
2601     NewTreePanel("AV", "PID", "Average distance tree using PID");
2602   }
2603
2604   /**
2605    * DOCUMENT ME!
2606    *
2607    * @param e DOCUMENT ME!
2608    */
2609   public void neighbourTreeMenuItem_actionPerformed(ActionEvent e)
2610   {
2611     NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
2612   }
2613
2614   /**
2615    * DOCUMENT ME!
2616    *
2617    * @param e DOCUMENT ME!
2618    */
2619   protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)
2620   {
2621     NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
2622   }
2623
2624   /**
2625    * DOCUMENT ME!
2626    *
2627    * @param e DOCUMENT ME!
2628    */
2629   protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e)
2630   {
2631     NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
2632   }
2633
2634   /**
2635    * DOCUMENT ME!
2636    *
2637    * @param type DOCUMENT ME!
2638    * @param pwType DOCUMENT ME!
2639    * @param title DOCUMENT ME!
2640    */
2641   void NewTreePanel(String type, String pwType, String title)
2642   {
2643     TreePanel tp;
2644
2645     if (viewport.getSelectionGroup() != null) {
2646       if (viewport.getSelectionGroup().getSize(false) < 3) {
2647         JOptionPane.showMessageDialog(Desktop.desktop,
2648                                       "You need to have more than two sequences selected to build a tree!",
2649                                       "Not enough sequences",
2650                                       JOptionPane.WARNING_MESSAGE);
2651         return;
2652       }
2653
2654       int s = 0;
2655       SequenceGroup sg = viewport.getSelectionGroup();
2656
2657       /* Decide if the selection is a column region */
2658       while (s < sg.getSize(false))
2659       {
2660         if ( ( (SequenceI) sg.getSequences(false).elementAt(s++)).getLength() <
2661             sg.getEndRes())
2662         {
2663           JOptionPane.showMessageDialog(Desktop.desktop,
2664                                         "The selected region to create a tree may\nonly contain residues or gaps.\n" +
2665                                         "Try using the Pad function in the edit menu,\n" +
2666                                         "or one of the multiple sequence alignment web services.",
2667                                         "Sequences in selection are not aligned",
2668                                         JOptionPane.WARNING_MESSAGE);
2669
2670           return;
2671         }
2672       }
2673
2674       title = title + " on region";
2675       tp = new TreePanel(alignPanel, type, pwType);
2676     }
2677     else
2678     {
2679       //are the sequences aligned?
2680       if (!viewport.alignment.isAligned())
2681       {
2682         JOptionPane.showMessageDialog(Desktop.desktop,
2683                                       "The sequences must be aligned before creating a tree.\n" +
2684                                       "Try using the Pad function in the edit menu,\n" +
2685                                       "or one of the multiple sequence alignment web services.",
2686                                       "Sequences not aligned",
2687                                       JOptionPane.WARNING_MESSAGE);
2688
2689         return;
2690       }
2691
2692       if(viewport.alignment.getHeight()<2)
2693         return;
2694
2695       tp = new TreePanel(alignPanel, type, pwType);
2696     }
2697
2698     addTreeMenuItem(tp, title);
2699
2700     Desktop.addInternalFrame(tp, title + " from " + this.title, 600, 500);
2701   }
2702
2703   /**
2704    * DOCUMENT ME!
2705    *
2706    * @param title DOCUMENT ME!
2707    * @param order DOCUMENT ME!
2708    */
2709   public void addSortByOrderMenuItem(String title, final AlignmentOrder order)
2710   {
2711     final JMenuItem item = new JMenuItem("by " + title);
2712     sort.add(item);
2713     item.addActionListener(new java.awt.event.ActionListener()
2714     {
2715       public void actionPerformed(ActionEvent e)
2716       {
2717         SequenceI [] oldOrder = viewport.getAlignment().getSequencesArray();
2718
2719         // TODO: JBPNote - have to map order entries to curent SequenceI pointers
2720         AlignmentSorter.sortBy(viewport.getAlignment(), order);
2721
2722         addHistoryItem(new OrderCommand(order.getName(), oldOrder, viewport.alignment));
2723
2724         alignPanel.repaint();
2725       }
2726     });
2727   }
2728
2729   /**
2730    * Maintain the Order by->Displayed Tree menu.
2731    * Creates a new menu item for a TreePanel with an appropriate
2732    * <code>jalview.analysis.AlignmentSorter</code> call. Listeners are added
2733    * to remove the menu item when the treePanel is closed, and adjust
2734    * the tree leaf to sequence mapping when the alignment is modified.
2735    * @param treePanel Displayed tree window.
2736    * @param title SortBy menu item title.
2737    */
2738   void addTreeMenuItem(final TreePanel treePanel, String title)
2739   {
2740     final JMenuItem item = new JMenuItem(title);
2741
2742     treeCount++;
2743
2744     if (treeCount == 1)
2745     {
2746       sort.add(sortByTreeMenu);
2747     }
2748
2749     sortByTreeMenu.add(item);
2750     item.addActionListener(new java.awt.event.ActionListener()
2751     {
2752       public void actionPerformed(ActionEvent e)
2753       {
2754         SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2755         AlignmentSorter.sortByTree(viewport.getAlignment(),
2756                                    treePanel.getTree());
2757
2758         addHistoryItem(new OrderCommand("Tree Sort",
2759                                         oldOrder,
2760                                         viewport.alignment));
2761
2762
2763         alignPanel.repaint();
2764       }
2765     });
2766
2767     treePanel.addInternalFrameListener(new javax.swing.event.
2768                                        InternalFrameAdapter()
2769     {
2770       public void internalFrameClosed(
2771           javax.swing.event.InternalFrameEvent evt)
2772       {
2773         treeCount--;
2774         sortByTreeMenu.remove(item);
2775
2776         if (treeCount == 0)
2777         {
2778           sort.remove(sortByTreeMenu);
2779         }
2780       }
2781       ;
2782     });
2783   }
2784
2785   /**
2786    * Work out whether the whole set of sequences
2787    * or just the selected set will be submitted for multiple alignment.
2788    *
2789    */
2790   private jalview.datamodel.AlignmentView gatherSequencesForAlignment()
2791   {
2792     // Now, check we have enough sequences
2793     AlignmentView msa = null;
2794
2795     if ( (viewport.getSelectionGroup() != null) &&
2796         (viewport.getSelectionGroup().getSize(false) > 1))
2797     {
2798       // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to some common interface!
2799       /*SequenceGroup seqs = viewport.getSelectionGroup();
2800       int sz;
2801       msa = new SequenceI[sz = seqs.getSize(false)];
2802
2803       for (int i = 0; i < sz; i++)
2804       {
2805         msa[i] = (SequenceI) seqs.getSequenceAt(i);
2806       } */
2807       msa = viewport.getAlignmentView(true);
2808     }
2809     else
2810     {
2811       /*Vector seqs = viewport.getAlignment().getSequences();
2812
2813       if (seqs.size() > 1)
2814       {
2815         msa = new SequenceI[seqs.size()];
2816
2817         for (int i = 0; i < seqs.size(); i++)
2818         {
2819           msa[i] = (SequenceI) seqs.elementAt(i);
2820         }
2821       }*/
2822       msa = viewport.getAlignmentView(false);
2823     }
2824     return msa;
2825   }
2826
2827   /**
2828    * Decides what is submitted to a secondary structure prediction service,
2829    * the currently selected sequence, or the currently selected alignment
2830    * (where the first sequence in the set is the one that the prediction
2831    * will be for).
2832    */
2833   AlignmentView gatherSeqOrMsaForSecStrPrediction()
2834   {
2835    AlignmentView seqs = null;
2836
2837     if ( (viewport.getSelectionGroup() != null) &&
2838         (viewport.getSelectionGroup().getSize(false) > 0))
2839     {
2840       seqs = viewport.getAlignmentView(true);
2841     }
2842     else
2843     {
2844       seqs = viewport.getAlignmentView(false);
2845     }
2846     // limit sequences - JBPNote in future - could spawn multiple prediction jobs
2847     // TODO: viewport.alignment.isAligned is a global state - the local selection may well be aligned - we preserve 2.0.8 behaviour for moment.
2848     if (!viewport.alignment.isAligned())
2849     {
2850       seqs.setSequences(new SeqCigar[] { seqs.getSequences()[0] } );
2851     }
2852     return seqs;
2853   }
2854   /**
2855    * DOCUMENT ME!
2856    *
2857    * @param e DOCUMENT ME!
2858    */
2859   protected void LoadtreeMenuItem_actionPerformed(ActionEvent e)
2860   {
2861     // Pick the tree file
2862     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2863         getProperty(
2864             "LAST_DIRECTORY"));
2865     chooser.setFileView(new JalviewFileView());
2866     chooser.setDialogTitle("Select a newick-like tree file");
2867     chooser.setToolTipText("Load a tree file");
2868
2869     int value = chooser.showOpenDialog(null);
2870
2871     if (value == JalviewFileChooser.APPROVE_OPTION)
2872     {
2873       String choice = chooser.getSelectedFile().getPath();
2874       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
2875
2876       try
2877       {
2878         jalview.io.NewickFile fin = new jalview.io.NewickFile(choice,
2879             "File");
2880         viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
2881       }
2882       catch (Exception ex)
2883       {
2884         JOptionPane.showMessageDialog(Desktop.desktop,
2885                                       "Problem reading tree file",
2886                                       ex.getMessage(),
2887                                       JOptionPane.WARNING_MESSAGE);
2888         ex.printStackTrace();
2889       }
2890     }
2891   }
2892
2893
2894   public TreePanel ShowNewickTree(NewickFile nf, String title)
2895   {
2896     return ShowNewickTree(nf,title,600,500,4,5);
2897   }
2898   public TreePanel ShowNewickTree(NewickFile nf, String title, AlignmentView input)
2899   {
2900     return ShowNewickTree(nf,title, input, 600,500,4,5);
2901   }
2902   public TreePanel ShowNewickTree(NewickFile nf, String title, int w,int h,int x, int y) {
2903     return ShowNewickTree(nf, title, null, w, h, x, y);
2904   }
2905   /**
2906    * Add a treeviewer for the tree extracted from a newick file object to the current alignment view
2907    *
2908    * @param nf the tree
2909    * @param title tree viewer title
2910    * @param input Associated alignment input data (or null)
2911    * @param w width
2912    * @param h height
2913    * @param x position
2914    * @param y position
2915    * @return TreePanel handle
2916    */
2917   public TreePanel ShowNewickTree(NewickFile nf, String title, AlignmentView input, int w,int h,int x, int y) {
2918     TreePanel tp = null;
2919
2920     try
2921     {
2922       nf.parse();
2923
2924       if (nf.getTree() != null)
2925       {
2926         tp = new TreePanel(alignPanel,
2927                            "FromFile",
2928                            title,
2929                            nf, input);
2930
2931         tp.setSize(w,h);
2932
2933         if(x>0 && y>0)
2934           tp.setLocation(x,y);
2935
2936
2937         Desktop.addInternalFrame(tp, title, w, h);
2938         addTreeMenuItem(tp, title);
2939       }
2940     }
2941     catch (Exception ex)
2942     {
2943       ex.printStackTrace();
2944     }
2945
2946     return tp;
2947   }
2948
2949   class PrintThread
2950       extends Thread
2951   {
2952     public void run()
2953     {
2954       PrinterJob printJob = PrinterJob.getPrinterJob();
2955       PageFormat pf = printJob.pageDialog(printJob.defaultPage());
2956       printJob.setPrintable(alignPanel, pf);
2957
2958       if (printJob.printDialog())
2959       {
2960         try
2961         {
2962           printJob.print();
2963         }
2964         catch (Exception PrintException)
2965         {
2966           PrintException.printStackTrace();
2967         }
2968       }
2969     }
2970   }
2971
2972   /**
2973    * Generates menu items and listener event actions for web service clients
2974    *
2975    */
2976   public void BuildWebServiceMenu()
2977   {
2978     if ( (Discoverer.services != null)
2979         && (Discoverer.services.size() > 0))
2980     {
2981       Vector msaws = (Vector) Discoverer.services.get("MsaWS");
2982       Vector secstrpr = (Vector) Discoverer.services.get("SecStrPred");
2983       Vector wsmenu = new Vector();
2984       final AlignFrame af = this;
2985       if (msaws != null)
2986       {
2987         // Add any Multiple Sequence Alignment Services
2988         final JMenu msawsmenu = new JMenu("Alignment");
2989         for (int i = 0, j = msaws.size(); i < j; i++)
2990         {
2991           final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) msaws.
2992               get(i);
2993           final JMenuItem method = new JMenuItem(sh.getName());
2994           method.addActionListener(new ActionListener()
2995           {
2996             public void actionPerformed(ActionEvent e)
2997             {
2998               AlignmentView msa = gatherSequencesForAlignment();
2999               new jalview.ws.MsaWSClient(sh, title, msa,
3000                   false, true, viewport.getAlignment().getDataset(), af);
3001
3002             }
3003
3004           });
3005           msawsmenu.add(method);
3006           // Deal with services that we know accept partial alignments.
3007           if (sh.getName().indexOf("lustal") > -1)
3008           {
3009             // We know that ClustalWS can accept partial alignments for refinement.
3010             final JMenuItem methodR = new JMenuItem(sh.getName()+" Realign");
3011             methodR.addActionListener(new ActionListener()
3012             {
3013               public void actionPerformed(ActionEvent e)
3014               {
3015                 AlignmentView msa = gatherSequencesForAlignment();
3016                 new jalview.ws.MsaWSClient(sh, title, msa,
3017                     true, true, viewport.getAlignment().getDataset(), af);
3018
3019               }
3020
3021             });
3022             msawsmenu.add(methodR);
3023
3024           }
3025         }
3026         wsmenu.add(msawsmenu);
3027       }
3028       if (secstrpr != null)
3029       {
3030         // Add any secondary structure prediction services
3031         final JMenu secstrmenu = new JMenu("Secondary Structure Prediction");
3032         for (int i = 0, j = secstrpr.size(); i < j; i++)
3033         {
3034           final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle)
3035               secstrpr.get(i);
3036           final JMenuItem method = new JMenuItem(sh.getName());
3037           method.addActionListener(new ActionListener()
3038           {
3039             public void actionPerformed(ActionEvent e)
3040             {
3041               AlignmentView msa = gatherSeqOrMsaForSecStrPrediction();
3042               if (msa.getSequences().length == 1)
3043               {
3044                 // Single Sequence prediction
3045                 new jalview.ws.JPredClient(sh, title, false, msa, af, true);
3046               }
3047               else
3048               {
3049                 if (msa.getSequences().length > 1)
3050                 {
3051                   // Sequence profile based prediction
3052                   new jalview.ws.JPredClient(sh,
3053                       title, true, msa, af, true);
3054                 }
3055               }
3056             }
3057           });
3058           secstrmenu.add(method);
3059         }
3060         wsmenu.add(secstrmenu);
3061       }
3062       this.webService.removeAll();
3063       for (int i = 0, j = wsmenu.size(); i < j; i++)
3064       {
3065         webService.add( (JMenu) wsmenu.get(i));
3066       }
3067     }
3068     else
3069     {
3070       this.webService.removeAll();
3071       this.webService.add(this.webServiceNoServices);
3072     }
3073     // TODO: add in rediscovery function
3074     // TODO: reduce code redundancy.
3075     // TODO: group services by location as well as function.
3076   }
3077
3078  /* public void vamsasStore_actionPerformed(ActionEvent e)
3079   {
3080     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
3081         getProperty("LAST_DIRECTORY"));
3082
3083     chooser.setFileView(new JalviewFileView());
3084     chooser.setDialogTitle("Export to Vamsas file");
3085     chooser.setToolTipText("Export");
3086
3087     int value = chooser.showSaveDialog(this);
3088
3089     if (value == JalviewFileChooser.APPROVE_OPTION)
3090     {
3091       jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport);
3092       //vs.store(chooser.getSelectedFile().getAbsolutePath()   );
3093       vs.storeJalview( chooser.getSelectedFile().getAbsolutePath(), this);
3094     }
3095   }*/
3096
3097
3098
3099
3100 public void showTranslation_actionPerformed(ActionEvent e)
3101 {
3102   SequenceI [] selection = viewport.getSelectionAsNewSequence();
3103   String [] seqstring = viewport.getViewAsString(true);
3104
3105   int s, sSize = selection.length;
3106   SequenceI [] newSeq = new SequenceI[sSize];
3107
3108   int res, resSize;
3109   StringBuffer protein;
3110   String seq;
3111   for(s=0; s<sSize; s++)
3112   {
3113     protein = new StringBuffer();
3114     seq = AlignSeq.extractGaps("-. ", seqstring[s]);
3115     resSize = seq.length();
3116     resSize -= resSize%3;
3117
3118     for(res = 0; res < resSize; res+=3)
3119     {
3120       String codon = seq.substring(res, res+3);
3121       codon = codon.replace('U', 'T');
3122       String aa = ResidueProperties.codonTranslate(codon);
3123       if(aa==null)
3124         protein.append(viewport.getGapCharacter());
3125       else if(aa.equals("STOP"))
3126         protein.append("X");
3127       else
3128         protein.append( aa );
3129     }
3130     newSeq[s] = new Sequence(selection[s].getName(),
3131                              protein.toString());
3132   }
3133
3134
3135   AlignmentI al = new Alignment(newSeq);
3136   al.setDataset(null);
3137
3138
3139   ////////////////////////////////
3140   // Copy annotations across
3141   jalview.datamodel.AlignmentAnnotation[] annotations
3142       = viewport.alignment.getAlignmentAnnotation();
3143   int a, aSize;
3144   if(annotations!=null)
3145   {
3146     for (int i = 0; i < annotations.length; i++)
3147     {
3148       if (annotations[i].label.equals("Quality") ||
3149           annotations[i].label.equals("Conservation") ||
3150           annotations[i].label.equals("Consensus"))
3151       {
3152         continue;
3153       }
3154
3155       aSize = viewport.alignment.getWidth() / 3;
3156       jalview.datamodel.Annotation[] anots =
3157           new jalview.datamodel.Annotation[aSize];
3158
3159       for (a = 0; a < viewport.alignment.getWidth(); a++)
3160       {
3161         if (annotations[i].annotations[a] == null
3162             || annotations[i].annotations[a] == null)
3163           continue;
3164
3165         anots[a / 3] = new Annotation(
3166             annotations[i].annotations[a].displayCharacter,
3167             annotations[i].annotations[a].description,
3168             annotations[i].annotations[a].secondaryStructure,
3169             annotations[i].annotations[a].value,
3170             annotations[i].annotations[a].colour);
3171       }
3172
3173       jalview.datamodel.AlignmentAnnotation aa
3174           = new jalview.datamodel.AlignmentAnnotation(annotations[i].label,
3175           annotations[i].description, anots);
3176       al.addAnnotation(aa);
3177     }
3178   }
3179
3180     AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
3181     Desktop.addInternalFrame(af, "Translation of "+this.getTitle(),
3182                              DEFAULT_WIDTH,
3183                              DEFAULT_HEIGHT);
3184
3185
3186
3187
3188 }
3189
3190 /**
3191  * DOCUMENT ME!
3192  *
3193  * @param String DOCUMENT ME!
3194  */
3195 public boolean parseFeaturesFile(String file, String type)
3196 {
3197     boolean featuresFile = false;
3198     try{
3199       featuresFile = new FeaturesFile(file, type).parse(viewport.alignment.getDataset(),
3200                                          alignPanel.seqPanel.seqCanvas.
3201                                          getFeatureRenderer().featureColours,
3202                                          false);
3203     }
3204     catch(Exception ex)
3205     {
3206       ex.printStackTrace();
3207     }
3208
3209     if(featuresFile)
3210     {
3211       viewport.showSequenceFeatures = true;
3212       showSeqFeatures.setSelected(true);
3213       alignPanel.repaint();
3214     }
3215
3216     return featuresFile;
3217 }
3218
3219 public void dragEnter(DropTargetDragEvent evt)
3220 {}
3221
3222 public void dragExit(DropTargetEvent evt)
3223 {}
3224
3225 public void dragOver(DropTargetDragEvent evt)
3226 {}
3227
3228 public void dropActionChanged(DropTargetDragEvent evt)
3229 {}
3230
3231 public void drop(DropTargetDropEvent evt)
3232 {
3233     Transferable t = evt.getTransferable();
3234     java.util.List files = null;
3235
3236     try
3237     {
3238       DataFlavor uriListFlavor = new DataFlavor("text/uri-list;class=java.lang.String");
3239       if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3240       {
3241         //Works on Windows and MacOSX
3242         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3243         files = (java.util.List) t.getTransferData(DataFlavor.javaFileListFlavor);
3244       }
3245       else if (t.isDataFlavorSupported(uriListFlavor))
3246       {
3247         // This is used by Unix drag system
3248         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3249         String data = (String) t.getTransferData(uriListFlavor);
3250         files = new java.util.ArrayList(1);
3251         for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3252             data,
3253             "\r\n");
3254              st.hasMoreTokens(); )
3255         {
3256           String s = st.nextToken();
3257           if (s.startsWith("#"))
3258           {
3259             // the line is a comment (as per the RFC 2483)
3260             continue;
3261           }
3262
3263           java.net.URI uri = new java.net.URI(s);
3264           java.io.File file = new java.io.File(uri);
3265           files.add(file);
3266         }
3267       }
3268     }
3269     catch (Exception e)
3270     {
3271       e.printStackTrace();
3272     }
3273     if (files != null)
3274     {
3275       try
3276       {
3277
3278         for (int i = 0; i < files.size(); i++)
3279         {
3280           loadJalviewDataFile(files.get(i).toString());
3281         }
3282       }
3283       catch (Exception ex)
3284       {
3285         ex.printStackTrace();
3286       }
3287     }
3288 }
3289
3290   // This method will attempt to load a "dropped" file first by testing
3291   // whether its and Annotation file, then features file. If both are
3292   // false then the user may have dropped an alignment file onto this
3293   // AlignFrame
3294    public void loadJalviewDataFile(String file)
3295   {
3296     try{
3297       String protocol = "File";
3298
3299       if (file.indexOf("http:") > -1 || file.indexOf("file:") > -1)
3300       {
3301         protocol = "URL";
3302       }
3303
3304       boolean isAnnotation = new AnnotationFile().readAnnotationFile(viewport.
3305           alignment, file);
3306
3307       if (!isAnnotation)
3308       {
3309         boolean isGroupsFile = parseFeaturesFile(file,protocol);
3310         if (!isGroupsFile)
3311         {
3312           String format = new IdentifyFile().Identify(file, protocol);
3313
3314           if(format.equalsIgnoreCase("JnetFile"))
3315           {
3316             jalview.io.JPredFile predictions = new jalview.io.JPredFile(
3317                 file, protocol);
3318             new JnetAnnotationMaker().add_annotation(predictions,
3319                 viewport.getAlignment(),
3320                 0, false);
3321             alignPanel.adjustAnnotationHeight();
3322             alignPanel.repaint();
3323           }
3324           else
3325             new FileLoader().LoadFile(viewport, file, protocol, format);
3326         }
3327       }
3328       else
3329       {
3330         // (isAnnotation)
3331         alignPanel.adjustAnnotationHeight();
3332       }
3333
3334     }catch(Exception ex)
3335     {
3336       ex.printStackTrace();
3337     }
3338   }
3339
3340   public void tabSelectionChanged(int index)
3341   {
3342     if (index > -1)
3343     {
3344       alignPanel = (AlignmentPanel) alignPanels.elementAt(index);
3345       viewport = alignPanel.av;
3346       setMenusFromViewport(viewport);
3347     }
3348   }
3349
3350   public void tabbedPane_mousePressed(MouseEvent e)
3351   {
3352     if(SwingUtilities.isRightMouseButton(e))
3353     {
3354       String reply = JOptionPane.showInternalInputDialog(this,
3355           "Enter View Name",
3356           "Edit View Name",
3357           JOptionPane.QUESTION_MESSAGE);
3358
3359       if (reply != null)
3360       {
3361         viewport.viewName = reply;
3362         tabbedPane.setTitleAt( tabbedPane.getSelectedIndex() ,reply);
3363       }
3364     }
3365   }
3366
3367
3368   public AlignViewport getCurrentView()
3369   {
3370     return viewport;
3371   }
3372 }