GPL license added
[jalview.git] / src / jalview / gui / AlignFrame.java
1 /*
2 * Jalview - A Sequence Alignment Editor and Viewer
3 * Copyright (C) 2005 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 Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18 */
19
20 package jalview.gui;
21
22 import java.util.*;
23
24 import java.awt.*;
25 import java.awt.datatransfer.*;
26 import java.awt.event.*;
27 import java.awt.print.*;
28 import javax.swing.*;
29 import javax.swing.event.*;
30
31 import jalview.analysis.*;
32 import jalview.datamodel.*;
33 import jalview.io.*;
34 import jalview.jbgui.*;
35 import jalview.schemes.*;
36 import jalview.ws.*;
37 import java.beans.PropertyChangeEvent;
38
39 public class AlignFrame extends GAlignFrame
40 {
41   final AlignmentPanel alignPanel;
42   final AlignViewport viewport;
43   public static final int NEW_WINDOW_WIDTH = 700;
44   public static final int NEW_WINDOW_HEIGHT = 500;
45   public String currentFileFormat = "Jalview";
46
47   public AlignFrame(AlignmentI al)
48   {
49     viewport = new AlignViewport(al);
50
51     alignPanel = new AlignmentPanel(this, viewport);
52     alignPanel.annotationPanel.adjustPanelHeight();
53     alignPanel.annotationSpaceFillerHolder.setPreferredSize(alignPanel.annotationPanel.getPreferredSize());
54     alignPanel.annotationScroller.setPreferredSize(alignPanel.annotationPanel.getPreferredSize());
55     alignPanel.setAnnotationVisible( viewport.getShowAnnotation() );
56
57     getContentPane().add(alignPanel, java.awt.BorderLayout.CENTER);
58
59     addInternalFrameListener(new InternalFrameAdapter()
60    {
61      public void internalFrameActivated(InternalFrameEvent evt)
62      {
63           javax.swing.SwingUtilities.invokeLater(new Runnable()
64           {
65             public void run()
66             {      alignPanel.requestFocus();    }
67           });
68
69      }
70    });
71
72   }
73
74   public void saveAlignmentMenu_actionPerformed(ActionEvent e)
75   {
76     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty("LAST_DIRECTORY")
77         ,  new String[]{"fa, fasta, fastq", "aln",  "pfam", "msf", "pir","blc","jar"},
78           new String[]{"Fasta", "Clustal", "PFAM", "MSF", "PIR", "BLC", "Jalview"},
79           currentFileFormat);
80
81     chooser.setAcceptAllFileFilterUsed(false);
82     chooser.setFileView(new JalviewFileView());
83     chooser.setDialogTitle("Save Alignment to file");
84     chooser.setToolTipText("Save");
85     int value = chooser.showSaveDialog(this);
86     if(value == JalviewFileChooser.APPROVE_OPTION)
87     {
88       currentFileFormat  = chooser.getSelectedFormat();
89       jalview.bin.Cache.setProperty("DEFAULT_FILE_FORMAT", currentFileFormat);
90
91       if (currentFileFormat.equals("Jalview"))
92       {
93         String shortName = title;
94         if(shortName.indexOf(java.io.File.separatorChar)>-1)
95               shortName = shortName.substring(
96                     shortName.lastIndexOf(java.io.File.separatorChar)+1);
97
98         String choice = chooser.getSelectedFile().getPath();
99         Jalview2XML.SaveState(this, choice, shortName);
100         // USE Jalview2XML to save this file
101         return;
102       }
103
104       String choice =  chooser.getSelectedFile().getPath();
105       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
106       String output = FormatAdapter.formatSequences(currentFileFormat, viewport.getAlignment().getSequences());
107       try{
108         java.io.PrintWriter out = new java.io.PrintWriter( new java.io.FileWriter( choice )  );
109         out.println(output);
110         out.close();
111       }
112       catch(Exception ex){}
113     }
114
115   }
116
117   protected void outputText_actionPerformed(ActionEvent e)
118   {
119      CutAndPasteTransfer cap = new CutAndPasteTransfer();
120      Desktop.addInternalFrame(cap, "Alignment output - "+e.getActionCommand(), 600, 500);
121      cap.setText( FormatAdapter.formatSequences(e.getActionCommand(), viewport.getAlignment().getSequences()));
122   }
123
124   protected void htmlMenuItem_actionPerformed(ActionEvent e)
125   {
126     new HTMLOutput(viewport);
127   }
128
129   protected void createPNG_actionPerformed(ActionEvent e)
130   {
131     alignPanel.makePNG();
132   }
133
134   protected void epsFile_actionPerformed(ActionEvent e)
135   {
136     alignPanel.makeEPS();
137   }
138
139
140   public void printMenuItem_actionPerformed(ActionEvent e)
141   {
142     //Putting in a thread avoids Swing painting problems
143     PrintThread thread = new PrintThread();
144     thread.start();
145   }
146
147   class PrintThread extends Thread
148   {
149     public void run()
150     {
151       PrinterJob printJob = PrinterJob.getPrinterJob();
152       PageFormat pf = printJob.pageDialog(printJob.defaultPage());
153       printJob.setPrintable(alignPanel, pf);
154       if (printJob.printDialog())
155       {
156         try
157         {
158           printJob.print();
159         }
160         catch (Exception PrintException)
161         {
162           PrintException.printStackTrace();
163         }
164       }
165     }
166
167   }
168
169
170
171
172   public void closeMenuItem_actionPerformed(ActionEvent e)
173   {
174     try{
175       this.setClosed(true);
176     }catch(Exception ex){}
177   }
178
179   Stack historyList = new Stack();
180   Stack redoList = new Stack();
181   private int treeCount = 0;
182
183   void updateEditMenuBar()
184    {
185      if(historyList.size()>0)
186       {
187         undoMenuItem.setEnabled(true);
188         HistoryItem hi = (HistoryItem)historyList.peek();
189         undoMenuItem.setText("Undo "+hi.getDescription());
190       }
191      else
192      {
193        undoMenuItem.setEnabled(false);
194        undoMenuItem.setText("Undo");
195      }
196
197      if(redoList.size()>0)
198       {
199         redoMenuItem.setEnabled(true);
200         HistoryItem hi = (HistoryItem)redoList.peek();
201         redoMenuItem.setText("Redo "+hi.getDescription());
202       }
203      else
204      {
205        redoMenuItem.setEnabled(false);
206        redoMenuItem.setText("Redo");
207      }
208    }
209
210    public void addHistoryItem(HistoryItem hi)
211    {
212      historyList.push(hi);
213      updateEditMenuBar();
214    }
215
216    protected void undoMenuItem_actionPerformed(ActionEvent e)
217    {
218        HistoryItem hi = (HistoryItem)historyList.pop();
219        redoList.push(new HistoryItem(hi.getDescription(), viewport.alignment, HistoryItem.HIDE));
220        restoreHistoryItem(hi);
221    }
222
223
224    protected void redoMenuItem_actionPerformed(ActionEvent e)
225    {
226       HistoryItem hi = (HistoryItem)redoList.pop();
227       restoreHistoryItem(hi);
228       updateEditMenuBar();
229       viewport.updateConsensus();
230       alignPanel.repaint();
231       alignPanel.repaint();
232    }
233
234
235    // used by undo and redo
236    void restoreHistoryItem(HistoryItem hi)
237    {
238       if(hi.getType()== HistoryItem.SORT)
239       {
240            for(int i=0; i<hi.getSequences().size(); i++)
241              viewport.alignment.getSequences().setElementAt(hi.getSequences().elementAt(i), i);
242       }
243       else
244       {
245         for (int i = 0; i < hi.getSequences().size(); i++)
246         {
247           SequenceI restore = (SequenceI) hi.getSequences().elementAt(i);
248           if(restore.getLength()==0)
249           {
250             restore.setSequence(hi.getHidden().elementAt(i).toString());
251             viewport.alignment.getSequences().insertElementAt(
252                restore,
253                hi.getAlignIndex(i));
254           }
255           else
256             restore.setSequence(hi.getHidden().elementAt(i).toString());
257         }
258         if(hi.getType()==HistoryItem.PASTE)
259         {
260           for(int i=viewport.alignment.getHeight()-1;i>hi.getSequences().size()-1; i--)
261             viewport.alignment.deleteSequence(i);
262         }
263       }
264       updateEditMenuBar();
265
266       viewport.updateConsensus();
267       viewport.updateConservation();
268       alignPanel.repaint();
269       viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());
270   }
271
272   public void moveSelectedSequences(boolean up)
273   {
274     SequenceGroup sg = viewport.getSelectionGroup();
275     if (sg == null)
276       return;
277
278     if (up)
279     {
280       for (int i = 1; i < viewport.alignment.getHeight(); i++)
281       {
282         SequenceI seq = viewport.alignment.getSequenceAt(i);
283         if (!sg.sequences.contains(seq))
284           continue;
285
286         SequenceI temp = viewport.alignment.getSequenceAt(i - 1);
287         if (sg.sequences.contains(temp))
288           continue;
289
290         viewport.alignment.getSequences().setElementAt(temp, i);
291         viewport.alignment.getSequences().setElementAt(seq, i - 1);
292       }
293     }
294     else
295     {
296       for (int i = viewport.alignment.getHeight() - 2; i > -1; i--)
297       {
298         SequenceI seq = viewport.alignment.getSequenceAt(i);
299         if (!sg.sequences.contains(seq))
300           continue;
301
302         SequenceI temp = viewport.alignment.getSequenceAt(i + 1);
303         if (sg.sequences.contains(temp))
304           continue;
305
306         viewport.alignment.getSequences().setElementAt(temp, i);
307         viewport.alignment.getSequences().setElementAt(seq, i + 1);
308       }
309     }
310
311     alignPanel.repaint();
312   }
313
314
315
316   protected void copy_actionPerformed(ActionEvent e)
317   {
318      if(viewport.getSelectionGroup()==null)
319        return;
320
321      SequenceGroup sg = viewport.getSelectionGroup();
322
323      Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
324      StringBuffer buffer= new StringBuffer();
325
326      Hashtable orderedSeqs = new Hashtable();
327      for(int i=0; i<sg.getSize(); i++)
328      {
329         SequenceI seq = sg.getSequenceAt(i);
330         int index = viewport.alignment.findIndex(seq);
331         orderedSeqs.put(index+"", seq);
332      }
333
334      int index=0;
335      for(int i=0; i<sg.getSize(); i++)
336      {
337        SequenceI seq = null;
338        while( seq == null )
339        {
340          if(orderedSeqs.containsKey(index+""))
341          {
342            seq = (SequenceI) orderedSeqs.get(index + "");
343            index++;
344            break;
345          }
346          else
347            index++;
348        }
349
350          buffer.append( seq.getName()+"\t"+seq.findPosition( sg.getStartRes() ) +"\t"
351                         +seq.findPosition( sg.getEndRes() )+ "\t"
352                         +sg.getSequenceAt(i).getSequence(sg.getStartRes(), sg.getEndRes()+1)+"\n");
353      }
354      c.setContents( new StringSelection( buffer.toString()) , null ) ;
355
356   }
357
358
359   protected void pasteNew_actionPerformed(ActionEvent e)
360   {
361     paste(true);
362   }
363
364   protected void pasteThis_actionPerformed(ActionEvent e)
365   {
366     addHistoryItem(new HistoryItem("Paste Sequences", viewport.alignment, HistoryItem.PASTE));
367     paste(false);
368   }
369
370   void paste(boolean newAlignment)
371   {
372     try{
373       Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
374       Transferable contents = c.getContents(this);
375       if (contents == null)
376         return;
377
378       String str = (String) contents.getTransferData(DataFlavor.stringFlavor);
379       StringTokenizer st = new StringTokenizer(str);
380       ArrayList seqs = new ArrayList();
381       while (st.hasMoreElements())
382       {
383         String name = st.nextToken();
384         int start = Integer.parseInt(st.nextToken());
385         int end = Integer.parseInt(st.nextToken());
386         Sequence sequence = new Sequence(name,st.nextToken(), start, end);
387
388         if(!newAlignment)
389           viewport.alignment.addSequence(sequence);
390         else
391           seqs.add(sequence);
392       }
393
394       if(newAlignment)
395       {
396         SequenceI[] newSeqs = new SequenceI[seqs.size()];
397         seqs.toArray(newSeqs);
398         AlignFrame af = new AlignFrame(new Alignment(newSeqs));
399         String newtitle = new String("Copied sequences");
400         if( title.startsWith("Copied sequences"))
401          newtitle = title;
402        else
403          newtitle = newtitle.concat("- from "+title);
404
405         Desktop.addInternalFrame(af, newtitle, NEW_WINDOW_WIDTH, NEW_WINDOW_HEIGHT);
406       }
407       else
408       {
409         viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());
410         viewport.setEndSeq(viewport.alignment.getHeight());
411         viewport.alignment.getWidth();
412         viewport.updateConservation();
413         viewport.updateConsensus();
414         alignPanel.repaint();
415       }
416
417     }catch(Exception ex){}// could be anything being pasted in here
418
419   }
420
421
422   protected void cut_actionPerformed(ActionEvent e)
423   {
424     copy_actionPerformed(null);
425     delete_actionPerformed(null);
426   }
427
428   protected void delete_actionPerformed(ActionEvent e)
429   {
430     boolean seqsdeleted=false;
431
432     if (viewport.getSelectionGroup() == null)
433       return;
434
435     addHistoryItem(new HistoryItem("Delete Sequences", viewport.alignment, HistoryItem.HIDE));
436
437      SequenceGroup sg = viewport.getSelectionGroup();
438      for (int i=0;i < sg.sequences.size(); i++)
439      {
440        SequenceI seq = sg.getSequenceAt(i);
441        int index = viewport.getAlignment().findIndex(seq);
442        seq.deleteChars(sg.getStartRes(),sg.getEndRes()+1);
443
444        if(seq.getSequence().length()<1) {
445          seqsdeleted=true;
446          viewport.getAlignment().deleteSequence(seq);
447         } else {
448          viewport.getAlignment().getSequences().setElementAt(seq, index);
449        }
450      }
451
452      viewport.setSelectionGroup(null);
453      viewport.alignment.deleteGroup(sg);
454      if (seqsdeleted)
455        viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());
456      viewport.resetSeqLimits( alignPanel.seqPanel.seqCanvas.getHeight());
457      if(viewport.getAlignment().getHeight()<1)
458      try
459      {
460        this.setClosed(true);
461      }catch(Exception ex){}
462    viewport.updateConservation();
463    viewport.updateConsensus();
464    alignPanel.repaint();
465  }
466
467
468   protected void deleteGroups_actionPerformed(ActionEvent e)
469   {
470     viewport.alignment.deleteAllGroups();
471     viewport.setSelectionGroup(null);
472     alignPanel.repaint();
473   }
474
475
476
477   public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)
478   {
479     SequenceGroup sg = new SequenceGroup();
480     for (int i=0; i<viewport.getAlignment().getSequences().size(); i++)
481       sg.addSequence( viewport.getAlignment().getSequenceAt(i));
482     sg.setEndRes(viewport.alignment.getWidth());
483     viewport.setSelectionGroup(sg);
484     PaintRefresher.Refresh(null);
485   }
486
487   public void deselectAllSequenceMenuItem_actionPerformed(ActionEvent e)
488   {
489     viewport.setSelectionGroup(null);
490     viewport.getColumnSelection().clear();
491     viewport.setSelectionGroup(null);
492     PaintRefresher.Refresh(null);
493   }
494
495   public void invertSequenceMenuItem_actionPerformed(ActionEvent e)
496   {
497     SequenceGroup sg = viewport.getSelectionGroup();
498     for (int i=0; i<viewport.getAlignment().getSequences().size(); i++)
499       sg.addOrRemove (viewport.getAlignment().getSequenceAt(i));
500
501     PaintRefresher.Refresh(null);
502   }
503
504   public void remove2LeftMenuItem_actionPerformed(ActionEvent e)
505   {
506     ColumnSelection colSel = viewport.getColumnSelection();
507     if (colSel.size() > 0)
508     {
509       addHistoryItem(new HistoryItem("Remove Left",viewport.alignment,
510                                      HistoryItem.HIDE));
511       int min = colSel.getMin();
512       viewport.getAlignment().trimLeft(min);
513       colSel.compensateForEdit(0,min);
514
515       if(viewport.getSelectionGroup()!=null)
516         viewport.getSelectionGroup().adjustForRemoveLeft(min);
517
518       Vector groups = viewport.alignment.getGroups();
519       for(int i=0; i<groups.size(); i++)
520       {
521         SequenceGroup sg = (SequenceGroup) groups.get(i);
522         if(!sg.adjustForRemoveLeft(min))
523           viewport.alignment.deleteGroup(sg);
524       }
525
526       alignPanel.repaint();
527     }
528   }
529
530   public void remove2RightMenuItem_actionPerformed(ActionEvent e)
531   {
532     ColumnSelection colSel = viewport.getColumnSelection();
533     if (colSel.size() > 0)
534     {
535       addHistoryItem(new HistoryItem("Remove Right",viewport.alignment,
536                                      HistoryItem.HIDE));
537
538       int max = colSel.getMax();
539       viewport.getAlignment().trimRight(max);
540       if(viewport.getSelectionGroup()!=null)
541         viewport.getSelectionGroup().adjustForRemoveRight(max);
542
543       Vector groups = viewport.alignment.getGroups();
544       for(int i=0; i<groups.size(); i++)
545       {
546         SequenceGroup sg = (SequenceGroup) groups.get(i);
547         if(!sg.adjustForRemoveRight(max))
548           viewport.alignment.deleteGroup(sg);
549       }
550
551
552
553       alignPanel.repaint();
554     }
555
556   }
557
558   public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e)
559   {
560     addHistoryItem(new HistoryItem("Remove Gapped Columns",
561                                    viewport.alignment,
562                                    HistoryItem.HIDE));
563
564     viewport.getAlignment().removeGaps();
565     viewport.updateConservation();
566     viewport.updateConsensus();
567     alignPanel.repaint();
568   }
569
570   public void removeAllGapsMenuItem_actionPerformed(ActionEvent e)
571   {
572     addHistoryItem(new HistoryItem("Remove Gaps",
573                                    viewport.alignment,
574                                    HistoryItem.HIDE));
575     SequenceI current;
576     int jSize;
577     for (int i=0; i < viewport.getAlignment().getSequences().size();i++)
578     {
579       current = viewport.getAlignment().getSequenceAt(i);
580       jSize = current.getLength();
581       for (int j=0; j < jSize; j++)
582         if(jalview.util.Comparison.isGap(current.getCharAt(j)))
583         {
584           current.deleteCharAt(j);
585           j--;
586           jSize--;
587         }
588     }
589     viewport.updateConservation();
590     viewport.updateConsensus();
591     alignPanel.repaint();
592   }
593
594
595   public void padGapsMenuitem_actionPerformed(ActionEvent e)
596     {
597       addHistoryItem(new HistoryItem("Pad Gaps",
598                                      viewport.alignment,
599                                      HistoryItem.HIDE));
600       SequenceI current;
601       int Width = viewport.getAlignment().getWidth()-1;
602       for (int i=0; i < viewport.getAlignment().getSequences().size();i++)
603       {
604         current = viewport.getAlignment().getSequenceAt(i);
605
606         if (current.getLength()<Width)
607           current.insertCharAt(Width, viewport.getGapCharacter());
608       }
609       viewport.updateConservation();
610       viewport.updateConsensus();
611       alignPanel.repaint();
612   }
613
614
615   public void findMenuItem_actionPerformed(ActionEvent e)
616   {
617     JInternalFrame frame = new JInternalFrame();
618     Finder finder = new Finder(viewport, alignPanel, frame);
619     frame.setContentPane(finder);
620     Desktop.addInternalFrame(frame, "Find", 340,110);
621     frame.setLayer(JLayeredPane.PALETTE_LAYER);
622
623   }
624
625
626   public void font_actionPerformed(ActionEvent e)
627   {
628     FontChooser fc = new FontChooser( alignPanel );
629   }
630
631   protected void fullSeqId_actionPerformed(ActionEvent e)
632   {
633     viewport.setShowFullId( fullSeqId.isSelected() );
634
635     alignPanel.idPanel.idCanvas.setPreferredSize( alignPanel.calculateIdWidth() );
636     alignPanel.repaint();
637   }
638
639   protected void colourTextMenuItem_actionPerformed(ActionEvent e)
640   {
641       viewport.setColourText( colourTextMenuItem.isSelected() );
642       alignPanel.repaint();
643   }
644
645   protected void wrapMenuItem_actionPerformed(ActionEvent e)
646   {
647     viewport.setWrapAlignment( wrapMenuItem.isSelected() );
648     alignPanel.setWrapAlignment( wrapMenuItem.isSelected() );
649     scaleAbove.setVisible( wrapMenuItem.isSelected() );
650     scaleLeft.setVisible( wrapMenuItem.isSelected() );
651     scaleRight.setVisible( wrapMenuItem.isSelected() );
652     alignPanel.repaint();
653   }
654
655   protected void scaleAbove_actionPerformed(ActionEvent e)
656   {
657     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
658     alignPanel.repaint();
659   }
660
661   protected void scaleLeft_actionPerformed(ActionEvent e)
662   {
663     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
664     alignPanel.repaint();
665   }
666
667   protected void scaleRight_actionPerformed(ActionEvent e)
668   {
669     viewport.setScaleRightWrapped(scaleRight.isSelected());
670     alignPanel.repaint();
671   }
672
673
674
675   public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
676   {
677     viewport.setShowBoxes( viewBoxesMenuItem.isSelected() );
678     alignPanel.repaint();
679   }
680
681   public void viewTextMenuItem_actionPerformed(ActionEvent e)
682   {
683     viewport.setShowText( viewTextMenuItem.isSelected() );
684     alignPanel.repaint();
685   }
686
687
688   protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
689   {
690     viewport.setRenderGaps(renderGapsMenuItem.isSelected());
691     alignPanel.repaint();
692   }
693
694   public void sequenceFeatures_actionPerformed(ActionEvent evt)
695   {
696     viewport.showSequenceFeatures(sequenceFeatures.isSelected());
697     if(viewport.showSequenceFeatures && !((Alignment)viewport.alignment).featuresAdded)
698     {
699          SequenceFeatureFetcher sft = new SequenceFeatureFetcher(viewport.alignment, alignPanel);
700          ((Alignment)viewport.alignment).featuresAdded = true;
701     }
702     alignPanel.repaint();
703   }
704
705   public void annotationPanelMenuItem_actionPerformed(ActionEvent e)
706   {
707     if(annotationPanelMenuItem.isSelected() && viewport.getWrapAlignment())
708     {
709       annotationPanelMenuItem.setSelected(false);
710       return;
711     }
712     viewport.setShowAnnotation( annotationPanelMenuItem.isSelected() );
713     alignPanel.setAnnotationVisible( annotationPanelMenuItem.isSelected() );
714   }
715
716   public void overviewMenuItem_actionPerformed(ActionEvent e)
717   {
718     if (alignPanel.overviewPanel != null)
719       return;
720
721     JInternalFrame frame = new JInternalFrame();
722     OverviewPanel overview = new OverviewPanel(alignPanel);
723      frame.setContentPane(overview);
724     Desktop.addInternalFrame(frame, "Overview " + this.getTitle(),
725                              frame.getWidth(), frame.getHeight());
726     frame.pack();
727     frame.setLayer(JLayeredPane.PALETTE_LAYER);
728     frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
729     { public void internalFrameClosed(javax.swing.event.InternalFrameEvent evt)
730       {
731             alignPanel.setOverviewPanel(null);
732       };
733     });
734
735     alignPanel.setOverviewPanel( overview );
736
737
738   }
739
740   protected void noColourmenuItem_actionPerformed(ActionEvent e)
741   {
742     changeColour( null );
743   }
744
745
746   public void clustalColour_actionPerformed(ActionEvent e)
747   {
748     changeColour(new ClustalxColourScheme(viewport.alignment.getSequences(), viewport.alignment.getWidth()));
749   }
750
751   public void zappoColour_actionPerformed(ActionEvent e)
752   {
753     changeColour(new ZappoColourScheme());
754   }
755
756   public void taylorColour_actionPerformed(ActionEvent e)
757   {
758     changeColour(new TaylorColourScheme());
759   }
760
761
762   public void hydrophobicityColour_actionPerformed(ActionEvent e)
763   {
764     changeColour( new HydrophobicColourScheme() );
765   }
766
767   public void helixColour_actionPerformed(ActionEvent e)
768   {
769     changeColour(new HelixColourScheme() );
770   }
771
772
773   public void strandColour_actionPerformed(ActionEvent e)
774   {
775     changeColour(new StrandColourScheme());
776   }
777
778
779   public void turnColour_actionPerformed(ActionEvent e)
780   {
781     changeColour(new TurnColourScheme());
782   }
783
784
785   public void buriedColour_actionPerformed(ActionEvent e)
786   {
787     changeColour(new BuriedColourScheme() );
788   }
789
790   public void nucleotideColour_actionPerformed(ActionEvent e)
791   {
792     changeColour(new NucleotideColourScheme());
793   }
794
795
796   protected void applyToAllGroups_actionPerformed(ActionEvent e)
797   {
798     viewport.setColourAppliesToAllGroups(applyToAllGroups.isSelected());
799   }
800
801
802
803   void changeColour(ColourSchemeI cs)
804   {
805     int threshold = 0;
806
807     if ( viewport.getAbovePIDThreshold() )
808     {
809       threshold = SliderPanel.setPIDSliderSource(alignPanel, cs, "Background");
810
811       if (cs instanceof ResidueColourScheme)
812         ( (ResidueColourScheme) cs).setThreshold(threshold);
813       else if (cs instanceof ScoreColourScheme)
814         ( (ScoreColourScheme) cs).setThreshold(threshold);
815
816       viewport.setGlobalColourScheme(cs);
817     }
818     else if (cs instanceof ResidueColourScheme)
819       ( (ResidueColourScheme) cs).setThreshold(0);
820     else if (cs instanceof ScoreColourScheme)
821       ( (ScoreColourScheme) cs).setThreshold(0);
822
823
824
825     if (viewport.getConservationSelected())
826     {
827       ConservationColourScheme ccs = null;
828
829       Alignment al = (Alignment) viewport.alignment;
830       Conservation c = new Conservation("All",
831                                         ResidueProperties.propHash, 3,
832                                         al.getSequences(), 0,
833                                         al.getWidth() - 1);
834
835       c.calculate();
836       c.verdict(false, viewport.ConsPercGaps);
837
838       ccs = new ConservationColourScheme(c, cs);
839
840       // MUST NOTIFY THE COLOURSCHEME OF CONSENSUS!
841       ccs.setConsensus( viewport.vconsensus );
842       viewport.setGlobalColourScheme(ccs);
843
844       ccs.inc = SliderPanel.setConservationSlider(alignPanel, ccs, "Background");
845
846     }
847     else
848     {
849         // MUST NOTIFY THE COLOURSCHEME OF CONSENSUS!
850         if (cs != null)
851           cs.setConsensus(viewport.vconsensus);
852         viewport.setGlobalColourScheme(cs);
853     }
854
855
856     if(viewport.getColourAppliesToAllGroups())
857     {
858       Vector groups = viewport.alignment.getGroups();
859       for(int i=0; i<groups.size(); i++)
860       {
861         SequenceGroup sg = (SequenceGroup)groups.elementAt(i);
862
863         if(cs==null)
864           sg.cs = null;
865         else if (cs instanceof ClustalxColourScheme)
866           sg.cs = new ClustalxColourScheme(sg.sequences, sg.getWidth());
867         else if (cs instanceof UserColourScheme)
868           sg.cs = new UserColourScheme( ((UserColourScheme)cs).getColours());
869         else
870           try{
871             sg.cs = (ColourSchemeI) cs.getClass().newInstance();
872           }catch(Exception ex){}
873
874         if(viewport.getAbovePIDThreshold())
875         {
876           if (sg.cs instanceof ResidueColourScheme)
877             ( (ResidueColourScheme) sg.cs).setThreshold(threshold);
878           else if (sg.cs instanceof ScoreColourScheme)
879             ( (ScoreColourScheme) sg.cs).setThreshold(threshold);
880
881            sg.cs.setConsensus( AAFrequency.calculate(sg.sequences, 0, sg.getWidth()) );
882         }
883
884         if( viewport.getConservationSelected() )
885         {
886           Conservation c = new Conservation("Group",
887                                             ResidueProperties.propHash, 3,
888                                             sg.sequences, 0, viewport.alignment.getWidth()-1);
889           c.calculate();
890           c.verdict(false, viewport.ConsPercGaps);
891           ConservationColourScheme ccs = new ConservationColourScheme(c, sg.cs);
892
893           // MUST NOTIFY THE COLOURSCHEME OF CONSENSUS!
894           ccs.setConsensus( AAFrequency.calculate(sg.sequences, 0, sg.getWidth()));
895           sg.cs = ccs;
896         }
897         else if(cs!=null)
898         {
899           // MUST NOTIFY THE COLOURSCHEME OF CONSENSUS!
900           sg.cs.setConsensus(AAFrequency.calculate(sg.sequences, 0, sg.getWidth()));
901         }
902
903       }
904     }
905
906     if(alignPanel.getOverviewPanel()!=null)
907       alignPanel.getOverviewPanel().updateOverviewImage();
908     alignPanel.repaint();
909   }
910
911   protected void modifyPID_actionPerformed(ActionEvent e)
912   {
913       if(viewport.getAbovePIDThreshold())
914       {
915         SliderPanel.setPIDSliderSource(alignPanel, viewport.getGlobalColourScheme(),
916                                    "Background");
917         SliderPanel.showPIDSlider();
918       }
919   }
920
921   protected void modifyConservation_actionPerformed(ActionEvent e)
922   {
923     if(viewport.getConservationSelected())
924     {
925       SliderPanel.setConservationSlider(alignPanel, viewport.globalColourScheme,
926                                         "Background");
927       SliderPanel.showConservationSlider();
928     }
929   }
930
931
932   protected  void conservationMenuItem_actionPerformed(ActionEvent e)
933   {
934     viewport.setConservationSelected(conservationMenuItem.isSelected());
935
936     viewport.setAbovePIDThreshold(false);
937     abovePIDThreshold.setSelected(false);
938
939    ColourSchemeI cs = viewport.getGlobalColourScheme();
940    if(cs instanceof ConservationColourScheme )
941      changeColour( ((ConservationColourScheme)cs).cs );
942     else
943       changeColour( cs );
944
945     modifyConservation_actionPerformed(null);
946   }
947
948   public void abovePIDThreshold_actionPerformed(ActionEvent e)
949   {
950     viewport.setAbovePIDThreshold(abovePIDThreshold.isSelected());
951
952     conservationMenuItem.setSelected(false);
953     viewport.setConservationSelected(false);
954
955     ColourSchemeI cs = viewport.getGlobalColourScheme();
956
957     if(cs instanceof ConservationColourScheme )
958         changeColour( ((ConservationColourScheme)cs).cs );
959     else
960         changeColour( cs );
961
962     modifyPID_actionPerformed(null);
963   }
964
965
966
967   public void userDefinedColour_actionPerformed(ActionEvent e)
968   {
969     new UserDefinedColours( alignPanel, null);
970   }
971
972   public void PIDColour_actionPerformed(ActionEvent e)
973   {
974     changeColour( new PIDColourScheme() );
975   }
976
977
978   public void BLOSUM62Colour_actionPerformed(ActionEvent e)
979   {
980     changeColour(new Blosum62ColourScheme() );
981   }
982
983
984
985   public void sortPairwiseMenuItem_actionPerformed(ActionEvent e)
986   {
987     addHistoryItem(new HistoryItem("Pairwise Sort", viewport.alignment, HistoryItem.SORT));
988     AlignmentSorter.sortByPID(viewport.getAlignment(), viewport.getAlignment().getSequenceAt(0));
989     alignPanel.repaint();
990   }
991
992   public void sortIDMenuItem_actionPerformed(ActionEvent e)
993   {
994     addHistoryItem(new HistoryItem("ID Sort", viewport.alignment, HistoryItem.SORT));
995     AlignmentSorter.sortByID( viewport.getAlignment() );
996     alignPanel.repaint();
997   }
998
999   public void sortGroupMenuItem_actionPerformed(ActionEvent e)
1000   {
1001     addHistoryItem(new HistoryItem("Group Sort", viewport.alignment, HistoryItem.SORT));
1002   //  AlignmentSorter.sortByGroup(viewport.getAlignment());
1003     AlignmentSorter.sortGroups(viewport.getAlignment());
1004     alignPanel.repaint();
1005   }
1006
1007   public void removeRedundancyMenuItem_actionPerformed(ActionEvent e)
1008   {
1009     RedundancyPanel sp = new RedundancyPanel(alignPanel,this);
1010     JInternalFrame frame = new JInternalFrame();
1011     frame.setContentPane(sp);
1012     Desktop.addInternalFrame(frame, "Redundancy threshold selection", 400, 100, false);
1013
1014   }
1015
1016   public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e)
1017   {
1018     if((viewport.getSelectionGroup()==null) ||
1019        viewport.getSelectionGroup().getSize()<2)
1020       JOptionPane.showInternalMessageDialog(this, "You must select at least 2 sequences.", "Invalid Selection", JOptionPane.WARNING_MESSAGE);
1021     else
1022     {
1023       JInternalFrame frame = new JInternalFrame();
1024       frame.setContentPane(new PairwiseAlignPanel(viewport));
1025       Desktop.addInternalFrame(frame, "Pairwise Alignment", 600, 500);
1026     }
1027   }
1028
1029   public void PCAMenuItem_actionPerformed(ActionEvent e)
1030   {
1031
1032     if( (viewport.getSelectionGroup()!=null && viewport.getSelectionGroup().getSize()<4 && viewport.getSelectionGroup().getSize()>0)
1033        || viewport.getAlignment().getHeight()<4)
1034     {
1035       JOptionPane.showInternalMessageDialog(this, "Principal component analysis must take\n"
1036                                     +"at least 4 input sequences.",
1037                                     "Sequence selection insufficient",
1038                                     JOptionPane.WARNING_MESSAGE);
1039       return;
1040     }
1041
1042     try{
1043       PCAPanel pcaPanel = new PCAPanel(viewport, null);
1044       JInternalFrame frame = new JInternalFrame();
1045       frame.setContentPane(pcaPanel);
1046       Desktop.addInternalFrame(frame, "Principal component analysis", 400, 400);
1047    }catch(java.lang.OutOfMemoryError ex)
1048    {
1049      JOptionPane.showInternalMessageDialog(this, "Too many sequences selected\nfor Principal Component Analysis!!",
1050                                    "Out of memory", JOptionPane.WARNING_MESSAGE);
1051    }
1052
1053
1054   }
1055
1056   public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)
1057   {
1058     NewTreePanel("AV", "PID", "Average distance tree using PID");
1059   }
1060
1061   public void neighbourTreeMenuItem_actionPerformed(ActionEvent e)
1062   {
1063     NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
1064   }
1065
1066
1067   protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)
1068   {
1069     NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
1070   }
1071
1072   protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e)
1073   {
1074     NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
1075   }
1076
1077   void NewTreePanel(String type, String pwType, String title)
1078   {
1079     String ltitle;
1080     final TreePanel tp;
1081     if (viewport.getSelectionGroup() != null &&
1082         viewport.getSelectionGroup().getSize() > 3)
1083     {
1084       int s=0;
1085       SequenceGroup sg = viewport.getSelectionGroup();
1086
1087       /* Decide if the selection is a column region */
1088       while (s<sg.sequences.size()) {
1089         if (((SequenceI) sg.sequences.elementAt(s++)).getLength()<sg.getEndRes()) {
1090           JOptionPane.showMessageDialog(Desktop.desktop,
1091                                         "The selected region to create a tree may\nonly contain residues or gaps.\n"
1092                                        +"Try using the Pad function in the edit menu,\n"
1093                                       +"or one of the multiple sequence alignment web services.",
1094                                         "Sequences in selection are not aligned", JOptionPane.WARNING_MESSAGE);
1095           return;
1096         }
1097
1098       }
1099       title=title+" on region";
1100       tp = new TreePanel(viewport, viewport.getSelectionGroup().sequences, type,
1101                          pwType,
1102                          sg.getStartRes(), sg.getEndRes());
1103     }
1104     else
1105     {
1106
1107      //are the sequences aligned?
1108      if(!viewport.alignment.isAligned())
1109      {
1110        JOptionPane.showMessageDialog(Desktop.desktop, "The sequences must be aligned before creating a tree.\n"
1111                                      +"Try using the Pad function in the edit menu,\n"
1112                                      +"or one of the multiple sequence alignment web services.",
1113                                      "Sequences not aligned", JOptionPane.WARNING_MESSAGE);
1114        return;
1115      }
1116      tp = new TreePanel(viewport, viewport.getAlignment().getSequences(),
1117                         type, pwType, 0, viewport.alignment.getWidth());
1118    }
1119
1120    addTreeMenuItem(tp, title);
1121    viewport.setCurrentTree(tp.getTree());
1122
1123    Desktop.addInternalFrame(tp, title+" from "+this.title, 600, 500);
1124   }
1125
1126   public void addSortByOrderMenuItem(String title, final AlignmentOrder order) {
1127     final JMenuItem item = new JMenuItem("by "+title);
1128     sort.add(item);
1129     item.addActionListener(new java.awt.event.ActionListener()
1130     {
1131       public void actionPerformed(ActionEvent e)
1132       {
1133         addHistoryItem(new HistoryItem("Sort", viewport.alignment,
1134                                        HistoryItem.SORT));
1135         // TODO: JBPNote - have to map order entries to curent SequenceI pointers
1136         AlignmentSorter.sortBy(viewport.getAlignment(), order);
1137         alignPanel.repaint();
1138       }
1139     });
1140   }
1141
1142   void addTreeMenuItem(final TreePanel treePanel, String title)
1143   {
1144     final JMenuItem item = new JMenuItem(title);
1145
1146     treeCount++;
1147
1148     if (treeCount==1)
1149       sort.add(sortByTreeMenu);
1150
1151     sortByTreeMenu.add(item);
1152     item.addActionListener(new java.awt.event.ActionListener()
1153     {
1154       public void actionPerformed(ActionEvent e)
1155       {
1156         addHistoryItem(new HistoryItem("Tree Sort", viewport.alignment,
1157                                        HistoryItem.SORT));
1158         AlignmentSorter.sortByTree(viewport.getAlignment(), treePanel.getTree());
1159         alignPanel.repaint();
1160       }
1161     });
1162
1163     treePanel.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
1164     {
1165       public void internalFrameClosed(javax.swing.event.InternalFrameEvent evt)
1166       {
1167         treeCount--;
1168         sortByTreeMenu.remove(item);
1169         if (treeCount==0)
1170           sort.remove(sortByTreeMenu);
1171       };
1172     });
1173     viewport.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
1174       public void propertyChange(PropertyChangeEvent evt)
1175       {
1176         if (evt.getPropertyName().equals("alignment")) {
1177           treePanel.getTree().UpdatePlaceHolders( (Vector) evt.getNewValue());
1178           treePanel.repaint();
1179         }
1180       }
1181
1182     }
1183     );
1184   }
1185
1186
1187   public void clustalAlignMenuItem_actionPerformed(ActionEvent e)
1188   {
1189       // TODO:resolve which menu item was actually selected
1190       // Now, check we have enough sequences
1191         SequenceI[] msa=null;
1192         if (viewport.getSelectionGroup() != null && viewport.getSelectionGroup().getSize()>1)
1193         {
1194           // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to some common interface!
1195           SequenceGroup seqs = viewport.getSelectionGroup();
1196           int sz;
1197           msa = new SequenceI[sz=seqs.getSize()];
1198           for (int i = 0; i < sz; i++)
1199           {
1200             msa[i] = (SequenceI) seqs.getSequenceAt(i);
1201           }
1202
1203           }
1204         else
1205         {
1206           Vector seqs = viewport.getAlignment().getSequences();
1207
1208           if (seqs.size() > 1) {
1209             msa = new SequenceI[seqs.size()];
1210             for (int i = 0; i < seqs.size(); i++)
1211             {
1212               msa[i] = (SequenceI) seqs.elementAt(i);
1213             }
1214
1215           }
1216
1217         }
1218         if (msa!=null) {
1219           jalview.ws.MsaWSClient ct = new jalview.ws.MsaWSClient("ClustalWS", title, msa, false, true);
1220         }
1221   }
1222   public void ClustalRealign_actionPerformed(ActionEvent e)
1223   {
1224       // TODO:resolve which menu item was actually selected
1225       // Now, check we have enough sequences
1226         SequenceI[] msa=null;
1227         if (viewport.getSelectionGroup() != null && viewport.getSelectionGroup().getSize()>1)
1228         {
1229           // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to some common interface!
1230           SequenceGroup seqs = viewport.getSelectionGroup();
1231           int sz;
1232           msa = new SequenceI[sz=seqs.getSize()];
1233           for (int i = 0; i < sz; i++)
1234           {
1235             msa[i] = (SequenceI) seqs.getSequenceAt(i);
1236           }
1237
1238           }
1239         else
1240         {
1241           Vector seqs = viewport.getAlignment().getSequences();
1242
1243           if (seqs.size() > 1) {
1244             msa = new SequenceI[seqs.size()];
1245             for (int i = 0; i < seqs.size(); i++)
1246             {
1247               msa[i] = (SequenceI) seqs.elementAt(i);
1248             }
1249
1250           }
1251
1252         }
1253         if (msa!=null) {
1254           jalview.ws.MsaWSClient ct = new jalview.ws.MsaWSClient("ClustalWS", title, msa, true, true);
1255         }
1256   }
1257
1258
1259   protected void jpred_actionPerformed(ActionEvent e)
1260 {
1261     SequenceI seq=null;
1262     SequenceI[] msa=null;
1263
1264     if (viewport.getSelectionGroup() != null && viewport.getSelectionGroup().getSize()>0)
1265     {
1266       // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to some common interface!
1267       SequenceGroup seqs = viewport.getSelectionGroup();
1268       if (seqs.getSize() == 1 || !viewport.alignment.isAligned())
1269       {
1270         seq = (SequenceI)seqs.getSequenceAt(0);
1271       }
1272       else
1273       {
1274         int sz;
1275         msa = new SequenceI[sz=seqs.getSize()];
1276         for (int i = 0; i < sz; i++)
1277         {
1278           msa[i] = (SequenceI) seqs.getSequenceAt(i);
1279         }
1280       }
1281     }
1282     else
1283     {
1284       Vector seqs = viewport.getAlignment().getSequences();
1285
1286       if (seqs.size() == 1 || !viewport.alignment.isAligned())
1287       {
1288         seq = (SequenceI) seqs.elementAt(0);
1289       }
1290       else
1291       {
1292         msa = new SequenceI[seqs.size()];
1293         for (int i = 0; i < seqs.size(); i++)
1294         {
1295           msa[i] = (SequenceI) seqs.elementAt(i);
1296         }
1297       }
1298     }
1299     if (msa!=null) {
1300       JPredClient ct = new JPredClient(title, msa);
1301     } else
1302     if (seq!=null) {
1303       JPredClient ct = new JPredClient(title, seq);
1304     } else {
1305       System.err.print("JALVIEW ERROR! - Unexpected JPred selection state!\n");
1306     }
1307   }
1308   protected void msaAlignMenuItem_actionPerformed(ActionEvent e)
1309   {
1310     // TODO:resolve which menu item was actually selected
1311     // Now, check we have enough sequences
1312     SequenceI[] msa=null;
1313     if (viewport.getSelectionGroup() != null && viewport.getSelectionGroup().getSize()>1)
1314       {
1315         // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to some common interface!
1316         SequenceGroup seqs = viewport.getSelectionGroup();
1317         int sz;
1318         msa = new SequenceI[sz=seqs.getSize()];
1319         for (int i = 0; i < sz; i++)
1320         {
1321           msa[i] = (SequenceI) seqs.getSequenceAt(i);
1322         }
1323
1324
1325       }
1326       else
1327       {
1328         Vector seqs = viewport.getAlignment().getSequences();
1329
1330         if (seqs.size() > 1) {
1331           msa = new SequenceI[seqs.size()];
1332           for (int i = 0; i < seqs.size(); i++)
1333           {
1334             msa[i] = (SequenceI) seqs.elementAt(i);
1335           }
1336
1337         }
1338
1339       }
1340       if (msa!=null) {
1341         MsaWSClient ct = new jalview.ws.MsaWSClient("MuscleWS",title, msa, false, true);
1342       }
1343   }
1344     protected void LoadtreeMenuItem_actionPerformed(ActionEvent e) {
1345     // Pick the tree file
1346     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
1347         getProperty("LAST_DIRECTORY"));
1348     chooser.setFileView(new JalviewFileView());
1349     chooser.setDialogTitle("Select a newick-like tree file");
1350     chooser.setToolTipText("Load a tree file");
1351     int value = chooser.showOpenDialog(null);
1352     if (value == JalviewFileChooser.APPROVE_OPTION)
1353     {
1354       String choice = chooser.getSelectedFile().getPath();
1355       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
1356       try
1357       {
1358         jalview.io.NewickFile fin = new jalview.io.NewickFile(choice, "File");
1359         ShowNewickTree(fin, choice);
1360       }
1361       catch (Exception ex)
1362       {
1363         JOptionPane.showMessageDialog(Desktop.desktop,
1364                                       "Problem reading tree file",
1365                                       ex.getMessage(),
1366                                       JOptionPane.WARNING_MESSAGE);
1367         ex.printStackTrace();
1368       }
1369     }
1370   }
1371
1372   public void ShowNewickTree(NewickFile nf, String title)
1373   {
1374     try{
1375       nf.parse();
1376       if (nf.getTree() != null)
1377       {
1378         TreePanel tp = new TreePanel(viewport,
1379                                      viewport.getAlignment().getSequences(),
1380                                      nf, "FromFile", title);
1381         Desktop.addInternalFrame(tp, title, 600, 500);
1382         addTreeMenuItem(tp, title);
1383         viewport.setCurrentTree(tp.getTree());
1384       }
1385      }catch(Exception ex){ex.printStackTrace();}
1386   }
1387
1388 }