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