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