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