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