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