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