2.5.1 release branding
[jalview.git] / src / jalview / gui / AlignFrame.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5.1)
3  * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  * 
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.gui;
19
20 import java.beans.*;
21 import java.io.*;
22 import java.util.*;
23
24 import java.awt.*;
25 import java.awt.datatransfer.*;
26 import java.awt.dnd.*;
27 import java.awt.event.*;
28 import java.awt.print.*;
29 import javax.swing.*;
30 import javax.swing.event.MenuEvent;
31
32 import jalview.analysis.*;
33 import jalview.commands.*;
34 import jalview.datamodel.*;
35 import jalview.io.*;
36 import jalview.jbgui.*;
37 import jalview.schemes.*;
38 import jalview.ws.*;
39
40 /**
41  * DOCUMENT ME!
42  * 
43  * @author $author$
44  * @version $Revision$
45  */
46 public class AlignFrame extends GAlignFrame implements DropTargetListener,
47         IProgressIndicator
48 {
49
50   /** DOCUMENT ME!! */
51   public static final int DEFAULT_WIDTH = 700;
52
53   /** DOCUMENT ME!! */
54   public static final int DEFAULT_HEIGHT = 500;
55
56   public AlignmentPanel alignPanel;
57
58   AlignViewport viewport;
59
60   Vector alignPanels = new Vector();
61
62   /**
63    * Last format used to load or save alignments in this window
64    */
65   String currentFileFormat = null;
66
67   /**
68    * Current filename for this alignment
69    */
70   String fileName = null;
71
72   /**
73    * Creates a new AlignFrame object with specific width and height.
74    * 
75    * @param al
76    * @param width
77    * @param height
78    */
79   public AlignFrame(AlignmentI al, int width, int height)
80   {
81     this(al, null, width, height);
82   }
83
84   /**
85    * Creates a new AlignFrame object with specific width, height and
86    * sequenceSetId
87    * 
88    * @param al
89    * @param width
90    * @param height
91    * @param sequenceSetId
92    */
93   public AlignFrame(AlignmentI al, int width, int height,
94           String sequenceSetId)
95   {
96     this(al, null, width, height, sequenceSetId);
97   }
98
99   /**
100    * Creates a new AlignFrame object with specific width, height and
101    * sequenceSetId
102    * 
103    * @param al
104    * @param width
105    * @param height
106    * @param sequenceSetId
107    * @param viewId
108    */
109   public AlignFrame(AlignmentI al, int width, int height,
110           String sequenceSetId, String viewId)
111   {
112     this(al, null, width, height, sequenceSetId, viewId);
113   }
114
115   /**
116    * new alignment window with hidden columns
117    * 
118    * @param al
119    *          AlignmentI
120    * @param hiddenColumns
121    *          ColumnSelection or null
122    * @param width
123    *          Width of alignment frame
124    * @param height
125    *          height of frame.
126    */
127   public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
128           int width, int height)
129   {
130     this(al, hiddenColumns, width, height, null);
131   }
132
133   /**
134    * Create alignment frame for al with hiddenColumns, a specific width and
135    * height, and specific sequenceId
136    * 
137    * @param al
138    * @param hiddenColumns
139    * @param width
140    * @param height
141    * @param sequenceSetId
142    *          (may be null)
143    */
144   public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
145           int width, int height, String sequenceSetId)
146   {
147     this(al, hiddenColumns, width, height, sequenceSetId, null);
148   }
149
150   /**
151    * Create alignment frame for al with hiddenColumns, a specific width and
152    * height, and specific sequenceId
153    * 
154    * @param al
155    * @param hiddenColumns
156    * @param width
157    * @param height
158    * @param sequenceSetId
159    *          (may be null)
160    * @param viewId
161    *          (may be null)
162    */
163   public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
164           int width, int height, String sequenceSetId, String viewId)
165   {
166     setSize(width, height);
167     viewport = new AlignViewport(al, hiddenColumns, sequenceSetId, viewId);
168
169     alignPanel = new AlignmentPanel(this, viewport);
170
171     if (al.getDataset() == null)
172     {
173       al.setDataset(null);
174     }
175
176     addAlignmentPanel(alignPanel, true);
177     init();
178   }
179
180   /**
181    * Make a new AlignFrame from exisiting alignmentPanels
182    * 
183    * @param ap
184    *          AlignmentPanel
185    * @param av
186    *          AlignViewport
187    */
188   public AlignFrame(AlignmentPanel ap)
189   {
190     viewport = ap.av;
191     alignPanel = ap;
192     addAlignmentPanel(ap, false);
193     init();
194   }
195
196   /**
197    * initalise the alignframe from the underlying viewport data and the
198    * configurations
199    */
200   void init()
201   {
202     if (viewport.conservation == null)
203     {
204       BLOSUM62Colour.setEnabled(false);
205       conservationMenuItem.setEnabled(false);
206       modifyConservation.setEnabled(false);
207       // PIDColour.setEnabled(false);
208       // abovePIDThreshold.setEnabled(false);
209       // modifyPID.setEnabled(false);
210     }
211
212     String sortby = jalview.bin.Cache.getDefault("SORT_ALIGNMENT",
213             "No sort");
214
215     if (sortby.equals("Id"))
216     {
217       sortIDMenuItem_actionPerformed(null);
218     }
219     else if (sortby.equals("Pairwise Identity"))
220     {
221       sortPairwiseMenuItem_actionPerformed(null);
222     }
223
224     if (Desktop.desktop != null)
225     {
226       this.setDropTarget(new java.awt.dnd.DropTarget(this, this));
227       addServiceListeners();
228       setGUINucleotide(viewport.alignment.isNucleotide());
229     }
230
231     setMenusFromViewport(viewport);
232     buildSortByAnnotationScoresMenu();
233     if (viewport.wrapAlignment)
234     {
235       wrapMenuItem_actionPerformed(null);
236     }
237
238     if (jalview.bin.Cache.getDefault("SHOW_OVERVIEW", false))
239     {
240       this.overviewMenuItem_actionPerformed(null);
241     }
242
243     addKeyListener();
244
245   }
246
247   /**
248    * Change the filename and format for the alignment, and enable the 'reload'
249    * button functionality.
250    * 
251    * @param file
252    *          valid filename
253    * @param format
254    *          format of file
255    */
256   public void setFileName(String file, String format)
257   {
258     fileName = file;
259     currentFileFormat = format;
260     reload.setEnabled(true);
261   }
262
263   void addKeyListener()
264   {
265     addKeyListener(new KeyAdapter()
266     {
267       public void keyPressed(KeyEvent evt)
268       {
269         if (viewport.cursorMode
270                 && ((evt.getKeyCode() >= KeyEvent.VK_0 && evt.getKeyCode() <= KeyEvent.VK_9) || (evt
271                         .getKeyCode() >= KeyEvent.VK_NUMPAD0 && evt
272                         .getKeyCode() <= KeyEvent.VK_NUMPAD9))
273                 && Character.isDigit(evt.getKeyChar()))
274           alignPanel.seqPanel.numberPressed(evt.getKeyChar());
275
276         switch (evt.getKeyCode())
277         {
278
279         case 27: // escape key
280           deselectAllSequenceMenuItem_actionPerformed(null);
281
282           break;
283
284         case KeyEvent.VK_DOWN:
285           if (evt.isAltDown() || !viewport.cursorMode)
286             moveSelectedSequences(false);
287           if (viewport.cursorMode)
288             alignPanel.seqPanel.moveCursor(0, 1);
289           break;
290
291         case KeyEvent.VK_UP:
292           if (evt.isAltDown() || !viewport.cursorMode)
293             moveSelectedSequences(true);
294           if (viewport.cursorMode)
295             alignPanel.seqPanel.moveCursor(0, -1);
296
297           break;
298
299         case KeyEvent.VK_LEFT:
300           if (evt.isAltDown() || !viewport.cursorMode)
301             slideSequences(false, alignPanel.seqPanel.getKeyboardNo1());
302           else
303             alignPanel.seqPanel.moveCursor(-1, 0);
304
305           break;
306
307         case KeyEvent.VK_RIGHT:
308           if (evt.isAltDown() || !viewport.cursorMode)
309             slideSequences(true, alignPanel.seqPanel.getKeyboardNo1());
310           else
311             alignPanel.seqPanel.moveCursor(1, 0);
312           break;
313
314         case KeyEvent.VK_SPACE:
315           if (viewport.cursorMode)
316           {
317             alignPanel.seqPanel.insertGapAtCursor(evt.isControlDown()
318                     || evt.isShiftDown() || evt.isAltDown());
319           }
320           break;
321
322         case KeyEvent.VK_DELETE:
323         case KeyEvent.VK_BACK_SPACE:
324           if (!viewport.cursorMode)
325           {
326             cut_actionPerformed(null);
327           }
328           else
329           {
330             alignPanel.seqPanel.deleteGapAtCursor(evt.isControlDown()
331                     || evt.isShiftDown() || evt.isAltDown());
332           }
333
334           break;
335
336         case KeyEvent.VK_S:
337           if (viewport.cursorMode)
338           {
339             alignPanel.seqPanel.setCursorRow();
340           }
341           break;
342         case KeyEvent.VK_C:
343           if (viewport.cursorMode && !evt.isControlDown())
344           {
345             alignPanel.seqPanel.setCursorColumn();
346           }
347           break;
348         case KeyEvent.VK_P:
349           if (viewport.cursorMode)
350           {
351             alignPanel.seqPanel.setCursorPosition();
352           }
353           break;
354
355         case KeyEvent.VK_ENTER:
356         case KeyEvent.VK_COMMA:
357           if (viewport.cursorMode)
358           {
359             alignPanel.seqPanel.setCursorRowAndColumn();
360           }
361           break;
362
363         case KeyEvent.VK_Q:
364           if (viewport.cursorMode)
365           {
366             alignPanel.seqPanel.setSelectionAreaAtCursor(true);
367           }
368           break;
369         case KeyEvent.VK_M:
370           if (viewport.cursorMode)
371           {
372             alignPanel.seqPanel.setSelectionAreaAtCursor(false);
373           }
374           break;
375
376         case KeyEvent.VK_F2:
377           viewport.cursorMode = !viewport.cursorMode;
378           statusBar.setText("Keyboard editing mode is "
379                   + (viewport.cursorMode ? "on" : "off"));
380           if (viewport.cursorMode)
381           {
382             alignPanel.seqPanel.seqCanvas.cursorX = viewport.startRes;
383             alignPanel.seqPanel.seqCanvas.cursorY = viewport.startSeq;
384           }
385           alignPanel.seqPanel.seqCanvas.repaint();
386           break;
387
388         case KeyEvent.VK_F1:
389           try
390           {
391             ClassLoader cl = jalview.gui.Desktop.class.getClassLoader();
392             java.net.URL url = javax.help.HelpSet.findHelpSet(cl,
393                     "help/help");
394             javax.help.HelpSet hs = new javax.help.HelpSet(cl, url);
395
396             javax.help.HelpBroker hb = hs.createHelpBroker();
397             hb.setCurrentID("home");
398             hb.setDisplayed(true);
399           } catch (Exception ex)
400           {
401             ex.printStackTrace();
402           }
403           break;
404         case KeyEvent.VK_H:
405         {
406           boolean toggleSeqs = !evt.isControlDown();
407           boolean toggleCols = !evt.isShiftDown();
408           toggleHiddenRegions(toggleSeqs, toggleCols);
409           break;
410         }
411         case KeyEvent.VK_PAGE_UP:
412           if (viewport.wrapAlignment)
413           {
414             alignPanel.scrollUp(true);
415           }
416           else
417           {
418             alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
419                     - viewport.endSeq + viewport.startSeq);
420           }
421           break;
422         case KeyEvent.VK_PAGE_DOWN:
423           if (viewport.wrapAlignment)
424           {
425             alignPanel.scrollUp(false);
426           }
427           else
428           {
429             alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
430                     + viewport.endSeq - viewport.startSeq);
431           }
432           break;
433         }
434       }
435
436       public void keyReleased(KeyEvent evt)
437       {
438         switch (evt.getKeyCode())
439         {
440         case KeyEvent.VK_LEFT:
441           if (evt.isAltDown() || !viewport.cursorMode)
442             viewport.firePropertyChange("alignment", null, viewport
443                     .getAlignment().getSequences());
444           break;
445
446         case KeyEvent.VK_RIGHT:
447           if (evt.isAltDown() || !viewport.cursorMode)
448             viewport.firePropertyChange("alignment", null, viewport
449                     .getAlignment().getSequences());
450           break;
451         }
452       }
453     });
454   }
455
456   public void addAlignmentPanel(final AlignmentPanel ap, boolean newPanel)
457   {
458     ap.alignFrame = this;
459
460     alignPanels.addElement(ap);
461
462     PaintRefresher.Register(ap, ap.av.getSequenceSetId());
463
464     int aSize = alignPanels.size();
465
466     tabbedPane.setVisible(aSize > 1 || ap.av.viewName != null);
467
468     if (aSize == 1 && ap.av.viewName == null)
469     {
470       this.getContentPane().add(ap, BorderLayout.CENTER);
471     }
472     else
473     {
474       if (aSize == 2)
475       {
476         setInitialTabVisible();
477       }
478
479       expandViews.setEnabled(true);
480       gatherViews.setEnabled(true);
481       tabbedPane.addTab(ap.av.viewName, ap);
482
483       ap.setVisible(false);
484     }
485
486     if (newPanel)
487     {
488       if (ap.av.padGaps)
489       {
490         ap.av.alignment.padGaps();
491       }
492       ap.av.updateConservation(ap);
493       ap.av.updateConsensus(ap);
494     }
495   }
496
497   public void setInitialTabVisible()
498   {
499     expandViews.setEnabled(true);
500     gatherViews.setEnabled(true);
501     tabbedPane.setVisible(true);
502     AlignmentPanel first = (AlignmentPanel) alignPanels.firstElement();
503     tabbedPane.addTab(first.av.viewName, first);
504     this.getContentPane().add(tabbedPane, BorderLayout.CENTER);
505   }
506
507   public AlignViewport getViewport()
508   {
509     return viewport;
510   }
511
512   /* Set up intrinsic listeners for dynamically generated GUI bits. */
513   private void addServiceListeners()
514   {
515     final java.beans.PropertyChangeListener thisListener;
516     // Do this once to get current state
517     BuildWebServiceMenu();
518     Desktop.discoverer
519             .addPropertyChangeListener(thisListener = new java.beans.PropertyChangeListener()
520             {
521               public void propertyChange(PropertyChangeEvent evt)
522               {
523                 // System.out.println("Discoverer property change.");
524                 if (evt.getPropertyName().equals("services"))
525                 {
526                   // System.out.println("Rebuilding web service menu");
527                   BuildWebServiceMenu();
528                 }
529               }
530             });
531
532     addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
533     {
534       public void internalFrameClosed(
535               javax.swing.event.InternalFrameEvent evt)
536       {
537         // System.out.println("deregistering discoverer listener");
538         Desktop.discoverer.removePropertyChangeListener(thisListener);
539         closeMenuItem_actionPerformed(true);
540       };
541     });
542   }
543
544   public void setGUINucleotide(boolean nucleotide)
545   {
546     showTranslation.setVisible(nucleotide);
547     conservationMenuItem.setEnabled(!nucleotide);
548     modifyConservation.setEnabled(!nucleotide);
549     showGroupConservation.setEnabled(!nucleotide);
550     // Remember AlignFrame always starts as protein
551     if (!nucleotide)
552     {
553       calculateMenu.remove(calculateMenu.getItemCount() - 2);
554     }
555   }
556
557   /**
558    * set up menus for the currently viewport. This may be called after any
559    * operation that affects the data in the current view (selection changed,
560    * etc) to update the menus to reflect the new state.
561    */
562   public void setMenusForViewport()
563   {
564     setMenusFromViewport(viewport);
565   }
566
567   /**
568    * Need to call this method when tabs are selected for multiple views, or when
569    * loading from Jalview2XML.java
570    * 
571    * @param av
572    *          AlignViewport
573    */
574   void setMenusFromViewport(AlignViewport av)
575   {
576     padGapsMenuitem.setSelected(av.padGaps);
577     colourTextMenuItem.setSelected(av.showColourText);
578     abovePIDThreshold.setSelected(av.getAbovePIDThreshold());
579     conservationMenuItem.setSelected(av.getConservationSelected());
580     seqLimits.setSelected(av.getShowJVSuffix());
581     idRightAlign.setSelected(av.rightAlignIds);
582     centreColumnLabelsMenuItem.setState(av.centreColumnLabels);
583     renderGapsMenuItem.setSelected(av.renderGaps);
584     wrapMenuItem.setSelected(av.wrapAlignment);
585     scaleAbove.setVisible(av.wrapAlignment);
586     scaleLeft.setVisible(av.wrapAlignment);
587     scaleRight.setVisible(av.wrapAlignment);
588     annotationPanelMenuItem.setState(av.showAnnotation);
589     viewBoxesMenuItem.setSelected(av.showBoxes);
590     viewTextMenuItem.setSelected(av.showText);
591     showNonconservedMenuItem.setSelected(av.showUnconserved);
592     showGroupConsensus.setSelected(av.showGroupConsensus);
593     showGroupConservation.setSelected(av.showGroupConservation);
594     showConsensusHistogram.setSelected(av.showConsensusHistogram);
595     showSequenceLogo.setSelected(av.showSequenceLogo);
596     setColourSelected(ColourSchemeProperty.getColourName(av
597             .getGlobalColourScheme()));
598
599     showSeqFeatures.setSelected(av.showSequenceFeatures);
600     hiddenMarkers.setState(av.showHiddenMarkers);
601     applyToAllGroups.setState(av.colourAppliesToAllGroups);
602     showNpFeatsMenuitem.setSelected(av.isShowNpFeats());
603     showDbRefsMenuitem.setSelected(av.isShowDbRefs());
604
605     setShowProductsEnabled();
606
607     updateEditMenuBar();
608   }
609
610   Hashtable progressBars, progressBarHandlers;
611
612   /*
613    * (non-Javadoc)
614    * 
615    * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
616    */
617   public void setProgressBar(String message, long id)
618   {
619     if (progressBars == null)
620     {
621       progressBars = new Hashtable();
622       progressBarHandlers = new Hashtable();
623     }
624
625     JPanel progressPanel;
626     Long lId = new Long(id);
627     GridLayout layout = (GridLayout) statusPanel.getLayout();
628     if (progressBars.get(lId) != null)
629     {
630       progressPanel = (JPanel) progressBars.get(new Long(id));
631       statusPanel.remove(progressPanel);
632       progressBars.remove(lId);
633       progressPanel = null;
634       if (message != null)
635       {
636         statusBar.setText(message);
637       }
638       if (progressBarHandlers.contains(lId))
639       {
640         progressBarHandlers.remove(lId);
641       }
642       layout.setRows(layout.getRows() - 1);
643     }
644     else
645     {
646       progressPanel = new JPanel(new BorderLayout(10, 5));
647
648       JProgressBar progressBar = new JProgressBar();
649       progressBar.setIndeterminate(true);
650
651       progressPanel.add(new JLabel(message), BorderLayout.WEST);
652       progressPanel.add(progressBar, BorderLayout.CENTER);
653
654       layout.setRows(layout.getRows() + 1);
655       statusPanel.add(progressPanel);
656
657       progressBars.put(lId, progressPanel);
658     }
659     // update GUI
660     setMenusForViewport();
661     validate();
662   }
663
664   public void registerHandler(final long id,
665           final IProgressIndicatorHandler handler)
666   {
667     if (progressBarHandlers == null || !progressBars.contains(new Long(id)))
668     {
669       throw new Error(
670               "call setProgressBar before registering the progress bar's handler.");
671     }
672     progressBarHandlers.put(new Long(id), handler);
673     final JPanel progressPanel = (JPanel) progressBars.get(new Long(id));
674     if (handler.canCancel())
675     {
676       JButton cancel = new JButton("Cancel");
677       final IProgressIndicator us = this;
678       cancel.addActionListener(new ActionListener()
679       {
680
681         public void actionPerformed(ActionEvent e)
682         {
683           handler.cancelActivity(id);
684           us.setProgressBar("Cancelled "
685                   + ((JLabel) progressPanel.getComponent(0)).getText(), id);
686         }
687       });
688       progressPanel.add(cancel, BorderLayout.EAST);
689     }
690   }
691
692   /**
693    * 
694    * @return true if any progress bars are still active
695    */
696   public boolean operationInProgress()
697   {
698     if (progressBars != null && progressBars.size() > 0)
699     {
700       return true;
701     }
702     return false;
703   }
704
705   /*
706    * Added so Castor Mapping file can obtain Jalview Version
707    */
708   public String getVersion()
709   {
710     return jalview.bin.Cache.getProperty("VERSION");
711   }
712
713   public FeatureRenderer getFeatureRenderer()
714   {
715     return alignPanel.seqPanel.seqCanvas.getFeatureRenderer();
716   }
717
718   public void fetchSequence_actionPerformed(ActionEvent e)
719   {
720     new SequenceFetcher(this);
721   }
722
723   public void addFromFile_actionPerformed(ActionEvent e)
724   {
725     Desktop.instance.inputLocalFileMenuItem_actionPerformed(viewport);
726   }
727
728   public void reload_actionPerformed(ActionEvent e)
729   {
730     if (fileName != null)
731     {
732       // TODO: work out how to recover feature settings for correct view(s) when
733       // file is reloaded.
734       if (currentFileFormat.equals("Jalview"))
735       {
736         JInternalFrame[] frames = Desktop.desktop.getAllFrames();
737         for (int i = 0; i < frames.length; i++)
738         {
739           if (frames[i] instanceof AlignFrame && frames[i] != this
740                   && ((AlignFrame) frames[i]).fileName.equals(fileName))
741           {
742             try
743             {
744               frames[i].setSelected(true);
745               Desktop.instance.closeAssociatedWindows();
746             } catch (java.beans.PropertyVetoException ex)
747             {
748             }
749           }
750
751         }
752         Desktop.instance.closeAssociatedWindows();
753
754         FileLoader loader = new FileLoader();
755         String protocol = fileName.startsWith("http:") ? "URL" : "File";
756         loader.LoadFile(viewport, fileName, protocol, currentFileFormat);
757       }
758       else
759       {
760         Rectangle bounds = this.getBounds();
761
762         FileLoader loader = new FileLoader();
763         String protocol = fileName.startsWith("http:") ? "URL" : "File";
764         AlignFrame newframe = loader.LoadFileWaitTillLoaded(fileName,
765                 protocol, currentFileFormat);
766
767         newframe.setBounds(bounds);
768         if (featureSettings != null && featureSettings.isShowing())
769         {
770           final Rectangle fspos = featureSettings.frame.getBounds();
771           // TODO: need a 'show feature settings' function that takes bounds -
772           // need to refactor Desktop.addFrame
773           newframe.featureSettings_actionPerformed(null);
774           final FeatureSettings nfs = newframe.featureSettings;
775           SwingUtilities.invokeLater(new Runnable()
776           {
777             public void run()
778             {
779               nfs.frame.setBounds(fspos);
780             }
781           });
782           this.featureSettings.close();
783           this.featureSettings = null;
784         }
785         this.closeMenuItem_actionPerformed(true);
786       }
787     }
788   }
789
790   public void addFromText_actionPerformed(ActionEvent e)
791   {
792     Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport);
793   }
794
795   public void addFromURL_actionPerformed(ActionEvent e)
796   {
797     Desktop.instance.inputURLMenuItem_actionPerformed(viewport);
798   }
799
800   public void save_actionPerformed(ActionEvent e)
801   {
802     if (fileName == null
803             || (currentFileFormat == null || !jalview.io.FormatAdapter
804                     .isValidIOFormat(currentFileFormat, true))
805             || fileName.startsWith("http"))
806     {
807       saveAs_actionPerformed(null);
808     }
809     else
810     {
811       saveAlignment(fileName, currentFileFormat);
812     }
813   }
814
815   /**
816    * DOCUMENT ME!
817    * 
818    * @param e
819    *          DOCUMENT ME!
820    */
821   public void saveAs_actionPerformed(ActionEvent e)
822   {
823     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
824             .getProperty("LAST_DIRECTORY"),
825             jalview.io.AppletFormatAdapter.WRITABLE_EXTENSIONS,
826             jalview.io.AppletFormatAdapter.WRITABLE_FNAMES,
827             currentFileFormat, false);
828
829     chooser.setFileView(new JalviewFileView());
830     chooser.setDialogTitle("Save Alignment to file");
831     chooser.setToolTipText("Save");
832
833     int value = chooser.showSaveDialog(this);
834
835     if (value == JalviewFileChooser.APPROVE_OPTION)
836     {
837       currentFileFormat = chooser.getSelectedFormat();
838       if (currentFileFormat == null)
839       {
840         JOptionPane.showInternalMessageDialog(Desktop.desktop,
841                 "You must select a file format before saving!",
842                 "File format not specified", JOptionPane.WARNING_MESSAGE);
843         value = chooser.showSaveDialog(this);
844         return;
845       }
846
847       fileName = chooser.getSelectedFile().getPath();
848
849       jalview.bin.Cache.setProperty("DEFAULT_FILE_FORMAT",
850               currentFileFormat);
851
852       jalview.bin.Cache.setProperty("LAST_DIRECTORY", fileName);
853       if (currentFileFormat.indexOf(" ") > -1)
854       {
855         currentFileFormat = currentFileFormat.substring(0,
856                 currentFileFormat.indexOf(" "));
857       }
858       saveAlignment(fileName, currentFileFormat);
859     }
860   }
861
862   public boolean saveAlignment(String file, String format)
863   {
864     boolean success = true;
865
866     if (format.equalsIgnoreCase("Jalview"))
867     {
868       String shortName = title;
869
870       if (shortName.indexOf(java.io.File.separatorChar) > -1)
871       {
872         shortName = shortName.substring(shortName
873                 .lastIndexOf(java.io.File.separatorChar) + 1);
874       }
875
876       success = new Jalview2XML().SaveAlignment(this, file, shortName);
877
878       statusBar.setText("Successfully saved to file: " + fileName + " in "
879               + format + " format.");
880
881     }
882     else
883     {
884       if (!jalview.io.AppletFormatAdapter.isValidFormat(format, true))
885       {
886         warningMessage("Cannot save file " + fileName + " using format "
887                 + format, "Alignment output format not supported");
888         saveAs_actionPerformed(null);
889         // JBPNote need to have a raise_gui flag here
890         return false;
891       }
892
893       String[] omitHidden = null;
894
895       if (viewport.hasHiddenColumns)
896       {
897         int reply = JOptionPane
898                 .showInternalConfirmDialog(
899                         Desktop.desktop,
900                         "The Alignment contains hidden columns."
901                                 + "\nDo you want to save only the visible alignment?",
902                         "Save / Omit Hidden Columns",
903                         JOptionPane.YES_NO_OPTION,
904                         JOptionPane.QUESTION_MESSAGE);
905
906         if (reply == JOptionPane.YES_OPTION)
907         {
908           omitHidden = viewport.getViewAsString(false);
909         }
910       }
911       FormatAdapter f = new FormatAdapter();
912       String output = f.formatSequences(format,
913               (Alignment) viewport.alignment, // class cast exceptions will
914               // occur in the distant future
915               omitHidden, f.getCacheSuffixDefault(format), viewport.colSel);
916
917       if (output == null)
918       {
919         success = false;
920       }
921       else
922       {
923         try
924         {
925           java.io.PrintWriter out = new java.io.PrintWriter(
926                   new java.io.FileWriter(file));
927
928           out.print(output);
929           out.close();
930           this.setTitle(file);
931           statusBar.setText("Successfully saved to file: " + fileName
932                   + " in " + format + " format.");
933         } catch (Exception ex)
934         {
935           success = false;
936           ex.printStackTrace();
937         }
938       }
939     }
940
941     if (!success)
942     {
943       JOptionPane.showInternalMessageDialog(this, "Couldn't save file: "
944               + fileName, "Error Saving File", JOptionPane.WARNING_MESSAGE);
945     }
946
947     return success;
948   }
949
950   private void warningMessage(String warning, String title)
951   {
952     if (new jalview.util.Platform().isHeadless())
953     {
954       System.err.println("Warning: " + title + "\nWarning: " + warning);
955
956     }
957     else
958     {
959       JOptionPane.showInternalMessageDialog(this, warning, title,
960               JOptionPane.WARNING_MESSAGE);
961     }
962     return;
963   }
964
965   /**
966    * DOCUMENT ME!
967    * 
968    * @param e
969    *          DOCUMENT ME!
970    */
971   protected void outputText_actionPerformed(ActionEvent e)
972   {
973     String[] omitHidden = null;
974
975     if (viewport.hasHiddenColumns)
976     {
977       int reply = JOptionPane
978               .showInternalConfirmDialog(
979                       Desktop.desktop,
980                       "The Alignment contains hidden columns."
981                               + "\nDo you want to output only the visible alignment?",
982                       "Save / Omit Hidden Columns",
983                       JOptionPane.YES_NO_OPTION,
984                       JOptionPane.QUESTION_MESSAGE);
985
986       if (reply == JOptionPane.YES_OPTION)
987       {
988         omitHidden = viewport.getViewAsString(false);
989       }
990     }
991
992     CutAndPasteTransfer cap = new CutAndPasteTransfer();
993     cap.setForInput(null);
994     Desktop.addInternalFrame(cap, "Alignment output - "
995             + e.getActionCommand(), 600, 500);
996
997     cap.setText(new FormatAdapter().formatSequences(e.getActionCommand(),
998             viewport.alignment, omitHidden, viewport.colSel));
999   }
1000
1001   /**
1002    * DOCUMENT ME!
1003    * 
1004    * @param e
1005    *          DOCUMENT ME!
1006    */
1007   protected void htmlMenuItem_actionPerformed(ActionEvent e)
1008   {
1009     new HTMLOutput(alignPanel, alignPanel.seqPanel.seqCanvas
1010             .getSequenceRenderer(), alignPanel.seqPanel.seqCanvas
1011             .getFeatureRenderer());
1012   }
1013
1014   public void createImageMap(File file, String image)
1015   {
1016     alignPanel.makePNGImageMap(file, image);
1017   }
1018
1019   /**
1020    * DOCUMENT ME!
1021    * 
1022    * @param e
1023    *          DOCUMENT ME!
1024    */
1025   public void createPNG(File f)
1026   {
1027     alignPanel.makePNG(f);
1028   }
1029
1030   /**
1031    * DOCUMENT ME!
1032    * 
1033    * @param e
1034    *          DOCUMENT ME!
1035    */
1036   public void createEPS(File f)
1037   {
1038     alignPanel.makeEPS(f);
1039   }
1040
1041   public void pageSetup_actionPerformed(ActionEvent e)
1042   {
1043     PrinterJob printJob = PrinterJob.getPrinterJob();
1044     PrintThread.pf = printJob.pageDialog(printJob.defaultPage());
1045   }
1046
1047   /**
1048    * DOCUMENT ME!
1049    * 
1050    * @param e
1051    *          DOCUMENT ME!
1052    */
1053   public void printMenuItem_actionPerformed(ActionEvent e)
1054   {
1055     // Putting in a thread avoids Swing painting problems
1056     PrintThread thread = new PrintThread(alignPanel);
1057     thread.start();
1058   }
1059
1060   public void exportFeatures_actionPerformed(ActionEvent e)
1061   {
1062     new AnnotationExporter().exportFeatures(alignPanel);
1063   }
1064
1065   public void exportAnnotations_actionPerformed(ActionEvent e)
1066   {
1067     new AnnotationExporter().exportAnnotations(alignPanel,
1068             viewport.showAnnotation ? viewport.alignment
1069                     .getAlignmentAnnotation() : null, viewport.alignment
1070                     .getGroups(),
1071             ((Alignment) viewport.alignment).alignmentProperties);
1072   }
1073
1074   public void associatedData_actionPerformed(ActionEvent e)
1075   {
1076     // Pick the tree file
1077     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
1078             .getProperty("LAST_DIRECTORY"));
1079     chooser.setFileView(new JalviewFileView());
1080     chooser.setDialogTitle("Load Jalview Annotations or Features File");
1081     chooser.setToolTipText("Load Jalview Annotations / Features file");
1082
1083     int value = chooser.showOpenDialog(null);
1084
1085     if (value == JalviewFileChooser.APPROVE_OPTION)
1086     {
1087       String choice = chooser.getSelectedFile().getPath();
1088       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
1089       loadJalviewDataFile(choice);
1090     }
1091
1092   }
1093
1094   /**
1095    * Close the current view or all views in the alignment frame. If the frame
1096    * only contains one view then the alignment will be removed from memory.
1097    * 
1098    * @param closeAllTabs
1099    */
1100   public void closeMenuItem_actionPerformed(boolean closeAllTabs)
1101   {
1102     if (alignPanels != null && alignPanels.size() < 2)
1103     {
1104       closeAllTabs = true;
1105     }
1106
1107     try
1108     {
1109       if (alignPanels != null)
1110       {
1111         if (closeAllTabs)
1112         {
1113           if (this.isClosed())
1114           {
1115             // really close all the windows - otherwise wait till
1116             // setClosed(true) is called
1117             for (int i = 0; i < alignPanels.size(); i++)
1118             {
1119               AlignmentPanel ap = (AlignmentPanel) alignPanels.elementAt(i);
1120               ap.closePanel();
1121             }
1122           }
1123         }
1124         else
1125         {
1126           closeView(alignPanel);
1127         }
1128       }
1129
1130       if (closeAllTabs)
1131       {
1132         this.setClosed(true);
1133       }
1134     } catch (Exception ex)
1135     {
1136       ex.printStackTrace();
1137     }
1138   }
1139
1140   /**
1141    * close alignPanel2 and shuffle tabs appropriately.
1142    * 
1143    * @param alignPanel2
1144    */
1145   public void closeView(AlignmentPanel alignPanel2)
1146   {
1147     int index = tabbedPane.getSelectedIndex();
1148     int closedindex = tabbedPane.indexOfComponent(alignPanel2);
1149     alignPanels.removeElement(alignPanel2);
1150     // Unnecessary
1151     // if (viewport == alignPanel2.av)
1152     // {
1153     // viewport = null;
1154     // }
1155     alignPanel2.closePanel();
1156     alignPanel2 = null;
1157
1158     tabbedPane.removeTabAt(closedindex);
1159     tabbedPane.validate();
1160
1161     if (index > closedindex || index == tabbedPane.getTabCount())
1162     {
1163       // modify currently selected tab index if necessary.
1164       index--;
1165     }
1166
1167     this.tabSelectionChanged(index);
1168   }
1169
1170   /**
1171    * DOCUMENT ME!
1172    */
1173   void updateEditMenuBar()
1174   {
1175
1176     if (viewport.historyList.size() > 0)
1177     {
1178       undoMenuItem.setEnabled(true);
1179       CommandI command = (CommandI) viewport.historyList.peek();
1180       undoMenuItem.setText("Undo " + command.getDescription());
1181     }
1182     else
1183     {
1184       undoMenuItem.setEnabled(false);
1185       undoMenuItem.setText("Undo");
1186     }
1187
1188     if (viewport.redoList.size() > 0)
1189     {
1190       redoMenuItem.setEnabled(true);
1191
1192       CommandI command = (CommandI) viewport.redoList.peek();
1193       redoMenuItem.setText("Redo " + command.getDescription());
1194     }
1195     else
1196     {
1197       redoMenuItem.setEnabled(false);
1198       redoMenuItem.setText("Redo");
1199     }
1200   }
1201
1202   public void addHistoryItem(CommandI command)
1203   {
1204     if (command.getSize() > 0)
1205     {
1206       viewport.historyList.push(command);
1207       viewport.redoList.clear();
1208       updateEditMenuBar();
1209       viewport.hasHiddenColumns = (viewport.colSel != null
1210               && viewport.colSel.getHiddenColumns() != null && viewport.colSel
1211               .getHiddenColumns().size() > 0);
1212     }
1213   }
1214
1215   /**
1216    * 
1217    * @return alignment objects for all views
1218    */
1219   AlignmentI[] getViewAlignments()
1220   {
1221     if (alignPanels != null)
1222     {
1223       Enumeration e = alignPanels.elements();
1224       AlignmentI[] als = new AlignmentI[alignPanels.size()];
1225       for (int i = 0; e.hasMoreElements(); i++)
1226       {
1227         als[i] = ((AlignmentPanel) e.nextElement()).av.getAlignment();
1228       }
1229       return als;
1230     }
1231     if (viewport != null)
1232     {
1233       return new AlignmentI[]
1234       { viewport.alignment };
1235     }
1236     return null;
1237   }
1238
1239   /**
1240    * DOCUMENT ME!
1241    * 
1242    * @param e
1243    *          DOCUMENT ME!
1244    */
1245   protected void undoMenuItem_actionPerformed(ActionEvent e)
1246   {
1247     if (viewport.historyList.empty())
1248       return;
1249     CommandI command = (CommandI) viewport.historyList.pop();
1250     viewport.redoList.push(command);
1251     command.undoCommand(getViewAlignments());
1252
1253     AlignViewport originalSource = getOriginatingSource(command);
1254     updateEditMenuBar();
1255
1256     if (originalSource != null)
1257     {
1258       originalSource.hasHiddenColumns = (viewport.colSel != null
1259               && viewport.colSel.getHiddenColumns() != null && viewport.colSel
1260               .getHiddenColumns().size() > 0);
1261       originalSource.firePropertyChange("alignment", null,
1262               originalSource.alignment.getSequences());
1263     }
1264   }
1265
1266   /**
1267    * DOCUMENT ME!
1268    * 
1269    * @param e
1270    *          DOCUMENT ME!
1271    */
1272   protected void redoMenuItem_actionPerformed(ActionEvent e)
1273   {
1274     if (viewport.redoList.size() < 1)
1275     {
1276       return;
1277     }
1278
1279     CommandI command = (CommandI) viewport.redoList.pop();
1280     viewport.historyList.push(command);
1281     command.doCommand(getViewAlignments());
1282
1283     AlignViewport originalSource = getOriginatingSource(command);
1284     updateEditMenuBar();
1285
1286     if (originalSource != null)
1287     {
1288       originalSource.hasHiddenColumns = (viewport.colSel != null
1289               && viewport.colSel.getHiddenColumns() != null && viewport.colSel
1290               .getHiddenColumns().size() > 0);
1291       originalSource.firePropertyChange("alignment", null,
1292               originalSource.alignment.getSequences());
1293     }
1294   }
1295
1296   AlignViewport getOriginatingSource(CommandI command)
1297   {
1298     AlignViewport originalSource = null;
1299     // For sequence removal and addition, we need to fire
1300     // the property change event FROM the viewport where the
1301     // original alignment was altered
1302     AlignmentI al = null;
1303     if (command instanceof EditCommand)
1304     {
1305       EditCommand editCommand = (EditCommand) command;
1306       al = editCommand.getAlignment();
1307       Vector comps = (Vector) PaintRefresher.components.get(viewport
1308               .getSequenceSetId());
1309
1310       for (int i = 0; i < comps.size(); i++)
1311       {
1312         if (comps.elementAt(i) instanceof AlignmentPanel)
1313         {
1314           if (al == ((AlignmentPanel) comps.elementAt(i)).av.alignment)
1315           {
1316             originalSource = ((AlignmentPanel) comps.elementAt(i)).av;
1317             break;
1318           }
1319         }
1320       }
1321     }
1322
1323     if (originalSource == null)
1324     {
1325       // The original view is closed, we must validate
1326       // the current view against the closed view first
1327       if (al != null)
1328       {
1329         PaintRefresher.validateSequences(al, viewport.alignment);
1330       }
1331
1332       originalSource = viewport;
1333     }
1334
1335     return originalSource;
1336   }
1337
1338   /**
1339    * DOCUMENT ME!
1340    * 
1341    * @param up
1342    *          DOCUMENT ME!
1343    */
1344   public void moveSelectedSequences(boolean up)
1345   {
1346     SequenceGroup sg = viewport.getSelectionGroup();
1347
1348     if (sg == null)
1349     {
1350       return;
1351     }
1352
1353     if (up)
1354     {
1355       for (int i = 1; i < viewport.alignment.getHeight(); i++)
1356       {
1357         SequenceI seq = viewport.alignment.getSequenceAt(i);
1358
1359         if (!sg.getSequences(null).contains(seq))
1360         {
1361           continue;
1362         }
1363
1364         SequenceI temp = viewport.alignment.getSequenceAt(i - 1);
1365
1366         if (sg.getSequences(null).contains(temp))
1367         {
1368           continue;
1369         }
1370
1371         viewport.alignment.getSequences().setElementAt(temp, i);
1372         viewport.alignment.getSequences().setElementAt(seq, i - 1);
1373       }
1374     }
1375     else
1376     {
1377       for (int i = viewport.alignment.getHeight() - 2; i > -1; i--)
1378       {
1379         SequenceI seq = viewport.alignment.getSequenceAt(i);
1380
1381         if (!sg.getSequences(null).contains(seq))
1382         {
1383           continue;
1384         }
1385
1386         SequenceI temp = viewport.alignment.getSequenceAt(i + 1);
1387
1388         if (sg.getSequences(null).contains(temp))
1389         {
1390           continue;
1391         }
1392
1393         viewport.alignment.getSequences().setElementAt(temp, i);
1394         viewport.alignment.getSequences().setElementAt(seq, i + 1);
1395       }
1396     }
1397
1398     alignPanel.paintAlignment(true);
1399   }
1400
1401   synchronized void slideSequences(boolean right, int size)
1402   {
1403     Vector sg = new Vector();
1404     if (viewport.cursorMode)
1405     {
1406       sg.addElement(viewport.alignment
1407               .getSequenceAt(alignPanel.seqPanel.seqCanvas.cursorY));
1408     }
1409     else if (viewport.getSelectionGroup() != null
1410             && viewport.getSelectionGroup().getSize() != viewport.alignment
1411                     .getHeight())
1412     {
1413       sg = viewport.getSelectionGroup().getSequences(
1414               viewport.hiddenRepSequences);
1415     }
1416
1417     if (sg.size() < 1)
1418     {
1419       return;
1420     }
1421
1422     Vector invertGroup = new Vector();
1423
1424     for (int i = 0; i < viewport.alignment.getHeight(); i++)
1425     {
1426       if (!sg.contains(viewport.alignment.getSequenceAt(i)))
1427         invertGroup.add(viewport.alignment.getSequenceAt(i));
1428     }
1429
1430     SequenceI[] seqs1 = new SequenceI[sg.size()];
1431     for (int i = 0; i < sg.size(); i++)
1432       seqs1[i] = (SequenceI) sg.elementAt(i);
1433
1434     SequenceI[] seqs2 = new SequenceI[invertGroup.size()];
1435     for (int i = 0; i < invertGroup.size(); i++)
1436       seqs2[i] = (SequenceI) invertGroup.elementAt(i);
1437
1438     SlideSequencesCommand ssc;
1439     if (right)
1440       ssc = new SlideSequencesCommand("Slide Sequences", seqs2, seqs1,
1441               size, viewport.getGapCharacter());
1442     else
1443       ssc = new SlideSequencesCommand("Slide Sequences", seqs1, seqs2,
1444               size, viewport.getGapCharacter());
1445
1446     int groupAdjustment = 0;
1447     if (ssc.getGapsInsertedBegin() && right)
1448     {
1449       if (viewport.cursorMode)
1450         alignPanel.seqPanel.moveCursor(size, 0);
1451       else
1452         groupAdjustment = size;
1453     }
1454     else if (!ssc.getGapsInsertedBegin() && !right)
1455     {
1456       if (viewport.cursorMode)
1457         alignPanel.seqPanel.moveCursor(-size, 0);
1458       else
1459         groupAdjustment = -size;
1460     }
1461
1462     if (groupAdjustment != 0)
1463     {
1464       viewport.getSelectionGroup().setStartRes(
1465               viewport.getSelectionGroup().getStartRes() + groupAdjustment);
1466       viewport.getSelectionGroup().setEndRes(
1467               viewport.getSelectionGroup().getEndRes() + groupAdjustment);
1468     }
1469
1470     boolean appendHistoryItem = false;
1471     if (viewport.historyList != null && viewport.historyList.size() > 0
1472             && viewport.historyList.peek() instanceof SlideSequencesCommand)
1473     {
1474       appendHistoryItem = ssc
1475               .appendSlideCommand((SlideSequencesCommand) viewport.historyList
1476                       .peek());
1477     }
1478
1479     if (!appendHistoryItem)
1480       addHistoryItem(ssc);
1481
1482     repaint();
1483   }
1484
1485   /**
1486    * DOCUMENT ME!
1487    * 
1488    * @param e
1489    *          DOCUMENT ME!
1490    */
1491   protected void copy_actionPerformed(ActionEvent e)
1492   {
1493     System.gc();
1494     if (viewport.getSelectionGroup() == null)
1495     {
1496       return;
1497     }
1498     // TODO: preserve the ordering of displayed alignment annotation in any
1499     // internal paste (particularly sequence associated annotation)
1500     SequenceI[] seqs = viewport.getSelectionAsNewSequence();
1501     String[] omitHidden = null;
1502
1503     if (viewport.hasHiddenColumns)
1504     {
1505       omitHidden = viewport.getViewAsString(true);
1506     }
1507
1508     String output = new FormatAdapter().formatSequences("Fasta", seqs,
1509             omitHidden);
1510
1511     StringSelection ss = new StringSelection(output);
1512
1513     try
1514     {
1515       jalview.gui.Desktop.internalCopy = true;
1516       // Its really worth setting the clipboard contents
1517       // to empty before setting the large StringSelection!!
1518       Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
1519               new StringSelection(""), null);
1520
1521       Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss,
1522               Desktop.instance);
1523     } catch (OutOfMemoryError er)
1524     {
1525       new OOMWarning("copying region", er);
1526       return;
1527     }
1528
1529     Vector hiddenColumns = null;
1530     if (viewport.hasHiddenColumns)
1531     {
1532       hiddenColumns = new Vector();
1533       int hiddenOffset = viewport.getSelectionGroup().getStartRes(),hiddenCutoff=viewport.getSelectionGroup().getEndRes();
1534       for (int i = 0; i < viewport.getColumnSelection().getHiddenColumns()
1535               .size(); i++)
1536       {
1537         int[] region = (int[]) viewport.getColumnSelection()
1538                 .getHiddenColumns().elementAt(i);
1539         if (region[0]>=hiddenOffset && region[1]<=hiddenCutoff)
1540         {
1541           hiddenColumns.addElement(new int[]
1542         { region[0] - hiddenOffset, region[1] - hiddenOffset });
1543         }
1544       }
1545     }
1546
1547     Desktop.jalviewClipboard = new Object[]
1548     { seqs, viewport.alignment.getDataset(), hiddenColumns };
1549     statusBar.setText("Copied " + seqs.length + " sequences to clipboard.");
1550   }
1551
1552   /**
1553    * DOCUMENT ME!
1554    * 
1555    * @param e
1556    *          DOCUMENT ME!
1557    */
1558   protected void pasteNew_actionPerformed(ActionEvent e)
1559   {
1560     paste(true);
1561   }
1562
1563   /**
1564    * DOCUMENT ME!
1565    * 
1566    * @param e
1567    *          DOCUMENT ME!
1568    */
1569   protected void pasteThis_actionPerformed(ActionEvent e)
1570   {
1571     paste(false);
1572   }
1573
1574   /**
1575    * Paste contents of Jalview clipboard
1576    * 
1577    * @param newAlignment
1578    *          true to paste to a new alignment, otherwise add to this.
1579    */
1580   void paste(boolean newAlignment)
1581   {
1582     boolean externalPaste = true;
1583     try
1584     {
1585       Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
1586       Transferable contents = c.getContents(this);
1587
1588       if (contents == null)
1589       {
1590         return;
1591       }
1592
1593       String str, format;
1594       try
1595       {
1596         str = (String) contents.getTransferData(DataFlavor.stringFlavor);
1597         if (str.length() < 1)
1598         {
1599           return;
1600         }
1601
1602         format = new IdentifyFile().Identify(str, "Paste");
1603
1604       } catch (OutOfMemoryError er)
1605       {
1606         new OOMWarning("Out of memory pasting sequences!!", er);
1607         return;
1608       }
1609
1610       SequenceI[] sequences;
1611       boolean annotationAdded = false;
1612       AlignmentI alignment = null;
1613
1614       if (Desktop.jalviewClipboard != null)
1615       {
1616         // The clipboard was filled from within Jalview, we must use the
1617         // sequences
1618         // And dataset from the copied alignment
1619         SequenceI[] newseq = (SequenceI[]) Desktop.jalviewClipboard[0];
1620         // be doubly sure that we create *new* sequence objects.
1621         sequences = new SequenceI[newseq.length];
1622         for (int i = 0; i < newseq.length; i++)
1623         {
1624           sequences[i] = new Sequence(newseq[i]);
1625         }
1626         alignment = new Alignment(sequences);
1627         externalPaste = false;
1628       }
1629       else
1630       {
1631         // parse the clipboard as an alignment.
1632         alignment = new FormatAdapter().readFile(str, "Paste", format);
1633         sequences = alignment.getSequencesArray();
1634       }
1635
1636       int alwidth = 0;
1637
1638       if (newAlignment)
1639       {
1640
1641         if (Desktop.jalviewClipboard != null)
1642         {
1643           // dataset is inherited
1644           alignment.setDataset((Alignment) Desktop.jalviewClipboard[1]);
1645         }
1646         else
1647         {
1648           // new dataset is constructed
1649           alignment.setDataset(null);
1650         }
1651         alwidth = alignment.getWidth() + 1;
1652       }
1653       else
1654       {
1655         AlignmentI pastedal = alignment; // preserve pasted alignment object
1656         // Add pasted sequences and dataset into existing alignment.
1657         alignment = viewport.getAlignment();
1658         alwidth = alignment.getWidth() + 1;
1659         // decide if we need to import sequences from an existing dataset
1660         boolean importDs = Desktop.jalviewClipboard != null
1661                 && Desktop.jalviewClipboard[1] != alignment.getDataset();
1662         // importDs==true instructs us to copy over new dataset sequences from
1663         // an existing alignment
1664         Vector newDs = (importDs) ? new Vector() : null; // used to create
1665         // minimum dataset set
1666
1667         for (int i = 0; i < sequences.length; i++)
1668         {
1669           if (importDs)
1670           {
1671             newDs.addElement(null);
1672           }
1673           SequenceI ds = sequences[i].getDatasetSequence(); // null for a simple
1674           // paste
1675           if (importDs && ds != null)
1676           {
1677             if (!newDs.contains(ds))
1678             {
1679               newDs.setElementAt(ds, i);
1680               ds = new Sequence(ds);
1681               // update with new dataset sequence
1682               sequences[i].setDatasetSequence(ds);
1683             }
1684             else
1685             {
1686               ds = sequences[newDs.indexOf(ds)].getDatasetSequence();
1687             }
1688           }
1689           else
1690           {
1691             // copy and derive new dataset sequence
1692             sequences[i] = sequences[i].deriveSequence();
1693             alignment.getDataset().addSequence(
1694                     sequences[i].getDatasetSequence());
1695             // TODO: avoid creation of duplicate dataset sequences with a
1696             // 'contains' method using SequenceI.equals()/SequenceI.contains()
1697           }
1698           alignment.addSequence(sequences[i]); // merges dataset
1699         }
1700         if (newDs != null)
1701         {
1702           newDs.clear(); // tidy up
1703         }
1704         if (pastedal.getAlignmentAnnotation() != null)
1705         {
1706           // Add any annotation attached to alignment.
1707           AlignmentAnnotation[] alann = pastedal.getAlignmentAnnotation();
1708           for (int i = 0; i < alann.length; i++)
1709           {
1710             annotationAdded = true;
1711             if (alann[i].sequenceRef == null && !alann[i].autoCalculated)
1712             {
1713               AlignmentAnnotation newann = new AlignmentAnnotation(alann[i]);
1714               newann.padAnnotation(alwidth);
1715               alignment.addAnnotation(newann);
1716             }
1717           }
1718         }
1719       }
1720       if (!newAlignment)
1721       {
1722         // /////
1723         // ADD HISTORY ITEM
1724         //
1725         addHistoryItem(new EditCommand("Add sequences", EditCommand.PASTE,
1726                 sequences, 0, alignment.getWidth(), alignment));
1727       }
1728       // Add any annotations attached to sequences
1729       for (int i = 0; i < sequences.length; i++)
1730       {
1731         if (sequences[i].getAnnotation() != null)
1732         {
1733           for (int a = 0; a < sequences[i].getAnnotation().length; a++)
1734           {
1735             annotationAdded = true;
1736             sequences[i].getAnnotation()[a].adjustForAlignment();
1737             sequences[i].getAnnotation()[a].padAnnotation(alwidth);
1738             alignment.addAnnotation(sequences[i].getAnnotation()[a]); // annotation
1739             // was
1740             // duplicated
1741             // earlier
1742             alignment
1743                     .setAnnotationIndex(sequences[i].getAnnotation()[a], a);
1744           }
1745         }
1746       }
1747       if (!newAlignment)
1748       {
1749
1750         // propagate alignment changed.
1751         viewport.setEndSeq(alignment.getHeight());
1752         if (annotationAdded)
1753         {
1754           // Duplicate sequence annotation in all views.
1755           AlignmentI[] alview = this.getViewAlignments();
1756           for (int i = 0; i < sequences.length; i++)
1757           {
1758             AlignmentAnnotation sann[] = sequences[i].getAnnotation();
1759             if (sann == null)
1760               continue;
1761             for (int avnum = 0; avnum < alview.length; avnum++)
1762             {
1763               if (alview[avnum] != alignment)
1764               {
1765                 // duplicate in a view other than the one with input focus
1766                 int avwidth = alview[avnum].getWidth() + 1;
1767                 // this relies on sann being preserved after we
1768                 // modify the sequence's annotation array for each duplication
1769                 for (int a = 0; a < sann.length; a++)
1770                 {
1771                   AlignmentAnnotation newann = new AlignmentAnnotation(
1772                           sann[a]);
1773                   sequences[i].addAlignmentAnnotation(newann);
1774                   newann.padAnnotation(avwidth);
1775                   alview[avnum].addAnnotation(newann); // annotation was
1776                   // duplicated earlier
1777                   alview[avnum].setAnnotationIndex(newann, a);
1778                 }
1779               }
1780             }
1781           }
1782           buildSortByAnnotationScoresMenu();
1783         }
1784         viewport.firePropertyChange("alignment", null, alignment
1785                 .getSequences());
1786
1787       }
1788       else
1789       {
1790         AlignFrame af = new AlignFrame(alignment, DEFAULT_WIDTH,
1791                 DEFAULT_HEIGHT);
1792         String newtitle = new String("Copied sequences");
1793
1794         if (Desktop.jalviewClipboard != null
1795                 && Desktop.jalviewClipboard[2] != null)
1796         {
1797           Vector hc = (Vector) Desktop.jalviewClipboard[2];
1798           for (int i = 0; i < hc.size(); i++)
1799           {
1800             int[] region = (int[]) hc.elementAt(i);
1801             af.viewport.hideColumns(region[0], region[1]);
1802           }
1803         }
1804
1805         // >>>This is a fix for the moment, until a better solution is
1806         // found!!<<<
1807         af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer()
1808                 .transferSettings(
1809                         alignPanel.seqPanel.seqCanvas.getFeatureRenderer());
1810
1811         // TODO: maintain provenance of an alignment, rather than just make the
1812         // title a concatenation of operations.
1813         if (!externalPaste)
1814         {
1815           if (title.startsWith("Copied sequences"))
1816           {
1817             newtitle = title;
1818           }
1819           else
1820           {
1821             newtitle = newtitle.concat("- from " + title);
1822           }
1823         }
1824         else
1825         {
1826           newtitle = new String("Pasted sequences");
1827         }
1828
1829         Desktop.addInternalFrame(af, newtitle, DEFAULT_WIDTH,
1830                 DEFAULT_HEIGHT);
1831
1832       }
1833
1834     } catch (Exception ex)
1835     {
1836       ex.printStackTrace();
1837       System.out.println("Exception whilst pasting: " + ex);
1838       // could be anything being pasted in here
1839     }
1840
1841   }
1842
1843   /**
1844    * DOCUMENT ME!
1845    * 
1846    * @param e
1847    *          DOCUMENT ME!
1848    */
1849   protected void cut_actionPerformed(ActionEvent e)
1850   {
1851     copy_actionPerformed(null);
1852     delete_actionPerformed(null);
1853   }
1854
1855   /**
1856    * DOCUMENT ME!
1857    * 
1858    * @param e
1859    *          DOCUMENT ME!
1860    */
1861   protected void delete_actionPerformed(ActionEvent evt)
1862   {
1863
1864     SequenceGroup sg = viewport.getSelectionGroup();
1865     if (sg == null)
1866     {
1867       return;
1868     }
1869
1870     Vector seqs = new Vector();
1871     SequenceI seq;
1872     for (int i = 0; i < sg.getSize(); i++)
1873     {
1874       seq = sg.getSequenceAt(i);
1875       seqs.addElement(seq);
1876     }
1877
1878     // If the cut affects all sequences, remove highlighted columns
1879     if (sg.getSize() == viewport.alignment.getHeight())
1880     {
1881       viewport.getColumnSelection().removeElements(sg.getStartRes(),
1882               sg.getEndRes() + 1);
1883     }
1884
1885     SequenceI[] cut = new SequenceI[seqs.size()];
1886     for (int i = 0; i < seqs.size(); i++)
1887     {
1888       cut[i] = (SequenceI) seqs.elementAt(i);
1889     }
1890
1891     /*
1892      * //ADD HISTORY ITEM
1893      */
1894     addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT, cut,
1895             sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
1896             viewport.alignment));
1897
1898     viewport.setSelectionGroup(null);
1899     viewport.sendSelection();
1900     viewport.alignment.deleteGroup(sg);
1901
1902     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
1903             .getSequences());
1904     if (viewport.getAlignment().getHeight() < 1)
1905     {
1906       try
1907       {
1908         this.setClosed(true);
1909       } catch (Exception ex)
1910       {
1911       }
1912     }
1913   }
1914
1915   /**
1916    * DOCUMENT ME!
1917    * 
1918    * @param e
1919    *          DOCUMENT ME!
1920    */
1921   protected void deleteGroups_actionPerformed(ActionEvent e)
1922   {
1923     viewport.alignment.deleteAllGroups();
1924     viewport.sequenceColours = null;
1925     viewport.setSelectionGroup(null);
1926     PaintRefresher.Refresh(this, viewport.getSequenceSetId());
1927     alignPanel.updateAnnotation();
1928     alignPanel.paintAlignment(true);
1929   }
1930
1931   /**
1932    * DOCUMENT ME!
1933    * 
1934    * @param e
1935    *          DOCUMENT ME!
1936    */
1937   public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)
1938   {
1939     SequenceGroup sg = new SequenceGroup();
1940
1941     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
1942     {
1943       sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
1944     }
1945
1946     sg.setEndRes(viewport.alignment.getWidth() - 1);
1947     viewport.setSelectionGroup(sg);
1948     viewport.sendSelection();
1949     alignPanel.paintAlignment(true);
1950     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
1951   }
1952
1953   /**
1954    * DOCUMENT ME!
1955    * 
1956    * @param e
1957    *          DOCUMENT ME!
1958    */
1959   public void deselectAllSequenceMenuItem_actionPerformed(ActionEvent e)
1960   {
1961     if (viewport.cursorMode)
1962     {
1963       alignPanel.seqPanel.keyboardNo1 = null;
1964       alignPanel.seqPanel.keyboardNo2 = null;
1965     }
1966     viewport.setSelectionGroup(null);
1967     viewport.getColumnSelection().clear();
1968     viewport.setSelectionGroup(null);
1969     alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);
1970     alignPanel.idPanel.idCanvas.searchResults = null;
1971     alignPanel.paintAlignment(true);
1972     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
1973   }
1974
1975   /**
1976    * DOCUMENT ME!
1977    * 
1978    * @param e
1979    *          DOCUMENT ME!
1980    */
1981   public void invertSequenceMenuItem_actionPerformed(ActionEvent e)
1982   {
1983     SequenceGroup sg = viewport.getSelectionGroup();
1984
1985     if (sg == null)
1986     {
1987       selectAllSequenceMenuItem_actionPerformed(null);
1988
1989       return;
1990     }
1991
1992     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
1993     {
1994       sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
1995     }
1996
1997     alignPanel.paintAlignment(true);
1998     viewport.sendSelection();
1999     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2000   }
2001
2002   public void invertColSel_actionPerformed(ActionEvent e)
2003   {
2004     viewport.invertColumnSelection();
2005     alignPanel.paintAlignment(true);
2006   }
2007
2008   /**
2009    * DOCUMENT ME!
2010    * 
2011    * @param e
2012    *          DOCUMENT ME!
2013    */
2014   public void remove2LeftMenuItem_actionPerformed(ActionEvent e)
2015   {
2016     trimAlignment(true);
2017   }
2018
2019   /**
2020    * DOCUMENT ME!
2021    * 
2022    * @param e
2023    *          DOCUMENT ME!
2024    */
2025   public void remove2RightMenuItem_actionPerformed(ActionEvent e)
2026   {
2027     trimAlignment(false);
2028   }
2029
2030   void trimAlignment(boolean trimLeft)
2031   {
2032     ColumnSelection colSel = viewport.getColumnSelection();
2033     int column;
2034
2035     if (colSel.size() > 0)
2036     {
2037       if (trimLeft)
2038       {
2039         column = colSel.getMin();
2040       }
2041       else
2042       {
2043         column = colSel.getMax();
2044       }
2045
2046       SequenceI[] seqs;
2047       if (viewport.getSelectionGroup() != null)
2048       {
2049         seqs = viewport.getSelectionGroup().getSequencesAsArray(
2050                 viewport.hiddenRepSequences);
2051       }
2052       else
2053       {
2054         seqs = viewport.alignment.getSequencesArray();
2055       }
2056
2057       TrimRegionCommand trimRegion;
2058       if (trimLeft)
2059       {
2060         trimRegion = new TrimRegionCommand("Remove Left",
2061                 TrimRegionCommand.TRIM_LEFT, seqs, column,
2062                 viewport.alignment, viewport.colSel,
2063                 viewport.selectionGroup);
2064         viewport.setStartRes(0);
2065       }
2066       else
2067       {
2068         trimRegion = new TrimRegionCommand("Remove Right",
2069                 TrimRegionCommand.TRIM_RIGHT, seqs, column,
2070                 viewport.alignment, viewport.colSel,
2071                 viewport.selectionGroup);
2072       }
2073
2074       statusBar.setText("Removed " + trimRegion.getSize() + " columns.");
2075
2076       addHistoryItem(trimRegion);
2077
2078       Vector groups = viewport.alignment.getGroups();
2079
2080       for (int i = 0; i < groups.size(); i++)
2081       {
2082         SequenceGroup sg = (SequenceGroup) groups.get(i);
2083
2084         if ((trimLeft && !sg.adjustForRemoveLeft(column))
2085                 || (!trimLeft && !sg.adjustForRemoveRight(column)))
2086         {
2087           viewport.alignment.deleteGroup(sg);
2088         }
2089       }
2090
2091       viewport.firePropertyChange("alignment", null, viewport
2092               .getAlignment().getSequences());
2093     }
2094   }
2095
2096   /**
2097    * DOCUMENT ME!
2098    * 
2099    * @param e
2100    *          DOCUMENT ME!
2101    */
2102   public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e)
2103   {
2104     int start = 0, end = viewport.alignment.getWidth() - 1;
2105
2106     SequenceI[] seqs;
2107     if (viewport.getSelectionGroup() != null)
2108     {
2109       seqs = viewport.getSelectionGroup().getSequencesAsArray(
2110               viewport.hiddenRepSequences);
2111       start = viewport.getSelectionGroup().getStartRes();
2112       end = viewport.getSelectionGroup().getEndRes();
2113     }
2114     else
2115     {
2116       seqs = viewport.alignment.getSequencesArray();
2117     }
2118
2119     RemoveGapColCommand removeGapCols = new RemoveGapColCommand(
2120             "Remove Gapped Columns", seqs, start, end, viewport.alignment);
2121
2122     addHistoryItem(removeGapCols);
2123
2124     statusBar.setText("Removed " + removeGapCols.getSize()
2125             + " empty columns.");
2126
2127     // This is to maintain viewport position on first residue
2128     // of first sequence
2129     SequenceI seq = viewport.alignment.getSequenceAt(0);
2130     int startRes = seq.findPosition(viewport.startRes);
2131     // ShiftList shifts;
2132     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
2133     // edit.alColumnChanges=shifts.getInverse();
2134     // if (viewport.hasHiddenColumns)
2135     // viewport.getColumnSelection().compensateForEdits(shifts);
2136     viewport.setStartRes(seq.findIndex(startRes) - 1);
2137     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2138             .getSequences());
2139
2140   }
2141
2142   /**
2143    * DOCUMENT ME!
2144    * 
2145    * @param e
2146    *          DOCUMENT ME!
2147    */
2148   public void removeAllGapsMenuItem_actionPerformed(ActionEvent e)
2149   {
2150     int start = 0, end = viewport.alignment.getWidth() - 1;
2151
2152     SequenceI[] seqs;
2153     if (viewport.getSelectionGroup() != null)
2154     {
2155       seqs = viewport.getSelectionGroup().getSequencesAsArray(
2156               viewport.hiddenRepSequences);
2157       start = viewport.getSelectionGroup().getStartRes();
2158       end = viewport.getSelectionGroup().getEndRes();
2159     }
2160     else
2161     {
2162       seqs = viewport.alignment.getSequencesArray();
2163     }
2164
2165     // This is to maintain viewport position on first residue
2166     // of first sequence
2167     SequenceI seq = viewport.alignment.getSequenceAt(0);
2168     int startRes = seq.findPosition(viewport.startRes);
2169
2170     addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
2171             viewport.alignment));
2172
2173     viewport.setStartRes(seq.findIndex(startRes) - 1);
2174
2175     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2176             .getSequences());
2177
2178   }
2179
2180   /**
2181    * DOCUMENT ME!
2182    * 
2183    * @param e
2184    *          DOCUMENT ME!
2185    */
2186   public void padGapsMenuitem_actionPerformed(ActionEvent e)
2187   {
2188     viewport.padGaps = padGapsMenuitem.isSelected();
2189     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2190             .getSequences());
2191   }
2192
2193   // else
2194   {
2195     // if (justifySeqs>0)
2196     {
2197       // alignment.justify(justifySeqs!=RIGHT_JUSTIFY);
2198     }
2199   }
2200
2201   // }
2202
2203   /**
2204    * DOCUMENT ME!
2205    * 
2206    * @param e
2207    *          DOCUMENT ME!
2208    */
2209   public void findMenuItem_actionPerformed(ActionEvent e)
2210   {
2211     new Finder();
2212   }
2213
2214   public void newView_actionPerformed(ActionEvent e)
2215   {
2216     AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel,
2217             true);
2218
2219     newap.av.gatherViewsHere = false;
2220
2221     if (viewport.viewName == null)
2222     {
2223       viewport.viewName = "Original";
2224     }
2225
2226     newap.av.historyList = viewport.historyList;
2227     newap.av.redoList = viewport.redoList;
2228
2229     int index = Desktop.getViewCount(viewport.getSequenceSetId());
2230     String newViewName = "View " + index;
2231
2232     Vector comps = (Vector) PaintRefresher.components.get(viewport
2233             .getSequenceSetId());
2234     Vector existingNames = new Vector();
2235     for (int i = 0; i < comps.size(); i++)
2236     {
2237       if (comps.elementAt(i) instanceof AlignmentPanel)
2238       {
2239         AlignmentPanel ap = (AlignmentPanel) comps.elementAt(i);
2240         if (!existingNames.contains(ap.av.viewName))
2241         {
2242           existingNames.addElement(ap.av.viewName);
2243         }
2244       }
2245     }
2246
2247     while (existingNames.contains(newViewName))
2248     {
2249       newViewName = "View " + (++index);
2250     }
2251
2252     newap.av.viewName = newViewName;
2253
2254     addAlignmentPanel(newap, true);
2255
2256     if (alignPanels.size() == 2)
2257     {
2258       viewport.gatherViewsHere = true;
2259     }
2260     tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
2261   }
2262
2263   public void expandViews_actionPerformed(ActionEvent e)
2264   {
2265     Desktop.instance.explodeViews(this);
2266   }
2267
2268   public void gatherViews_actionPerformed(ActionEvent e)
2269   {
2270     Desktop.instance.gatherViews(this);
2271   }
2272
2273   /**
2274    * DOCUMENT ME!
2275    * 
2276    * @param e
2277    *          DOCUMENT ME!
2278    */
2279   public void font_actionPerformed(ActionEvent e)
2280   {
2281     new FontChooser(alignPanel);
2282   }
2283
2284   /**
2285    * DOCUMENT ME!
2286    * 
2287    * @param e
2288    *          DOCUMENT ME!
2289    */
2290   protected void seqLimit_actionPerformed(ActionEvent e)
2291   {
2292     viewport.setShowJVSuffix(seqLimits.isSelected());
2293
2294     alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel
2295             .calculateIdWidth());
2296     alignPanel.paintAlignment(true);
2297   }
2298
2299   public void idRightAlign_actionPerformed(ActionEvent e)
2300   {
2301     viewport.rightAlignIds = idRightAlign.isSelected();
2302     alignPanel.paintAlignment(true);
2303   }
2304
2305   public void centreColumnLabels_actionPerformed(ActionEvent e)
2306   {
2307     viewport.centreColumnLabels = centreColumnLabelsMenuItem.getState();
2308     alignPanel.paintAlignment(true);
2309   }
2310
2311   /*
2312    * (non-Javadoc)
2313    * 
2314    * @see jalview.jbgui.GAlignFrame#followHighlight_actionPerformed()
2315    */
2316   protected void followHighlight_actionPerformed()
2317   {
2318     if (viewport.followHighlight = this.followHighlightMenuItem.getState())
2319     {
2320       alignPanel.scrollToPosition(
2321               alignPanel.seqPanel.seqCanvas.searchResults, false);
2322     }
2323   }
2324
2325   /**
2326    * DOCUMENT ME!
2327    * 
2328    * @param e
2329    *          DOCUMENT ME!
2330    */
2331   protected void colourTextMenuItem_actionPerformed(ActionEvent e)
2332   {
2333     viewport.setColourText(colourTextMenuItem.isSelected());
2334     alignPanel.paintAlignment(true);
2335   }
2336
2337   /**
2338    * DOCUMENT ME!
2339    * 
2340    * @param e
2341    *          DOCUMENT ME!
2342    */
2343   public void wrapMenuItem_actionPerformed(ActionEvent e)
2344   {
2345     scaleAbove.setVisible(wrapMenuItem.isSelected());
2346     scaleLeft.setVisible(wrapMenuItem.isSelected());
2347     scaleRight.setVisible(wrapMenuItem.isSelected());
2348     viewport.setWrapAlignment(wrapMenuItem.isSelected());
2349     alignPanel.setWrapAlignment(wrapMenuItem.isSelected());
2350   }
2351
2352   public void showAllSeqs_actionPerformed(ActionEvent e)
2353   {
2354     viewport.showAllHiddenSeqs();
2355   }
2356
2357   public void showAllColumns_actionPerformed(ActionEvent e)
2358   {
2359     viewport.showAllHiddenColumns();
2360     repaint();
2361   }
2362
2363   public void hideSelSequences_actionPerformed(ActionEvent e)
2364   {
2365     viewport.hideAllSelectedSeqs();
2366     alignPanel.paintAlignment(true);
2367   }
2368
2369   /**
2370    * called by key handler and the hide all/show all menu items
2371    * 
2372    * @param toggleSeqs
2373    * @param toggleCols
2374    */
2375   private void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
2376   {
2377
2378     boolean hide = false;
2379     SequenceGroup sg = viewport.getSelectionGroup();
2380     if (!toggleSeqs && !toggleCols)
2381     {
2382       // Hide everything by the current selection - this is a hack - we do the
2383       // invert and then hide
2384       // first check that there will be visible columns after the invert.
2385       if ((viewport.colSel != null && viewport.colSel.getSelected() != null && viewport.colSel
2386               .getSelected().size() > 0)
2387               || (sg != null && sg.getSize() > 0 && sg.getStartRes() <= sg
2388                       .getEndRes()))
2389       {
2390         // now invert the sequence set, if required - empty selection implies
2391         // that no hiding is required.
2392         if (sg != null)
2393         {
2394           invertSequenceMenuItem_actionPerformed(null);
2395           sg = viewport.getSelectionGroup();
2396           toggleSeqs = true;
2397
2398         }
2399         viewport.expandColSelection(sg, true);
2400         // finally invert the column selection and get the new sequence
2401         // selection.
2402         invertColSel_actionPerformed(null);
2403         toggleCols = true;
2404       }
2405     }
2406
2407     if (toggleSeqs)
2408     {
2409       if (sg != null && sg.getSize() != viewport.alignment.getHeight())
2410       {
2411         hideSelSequences_actionPerformed(null);
2412         hide = true;
2413       }
2414       else if (!(toggleCols && viewport.colSel.getSelected().size() > 0))
2415       {
2416         showAllSeqs_actionPerformed(null);
2417       }
2418     }
2419
2420     if (toggleCols)
2421     {
2422       if (viewport.colSel.getSelected().size() > 0)
2423       {
2424         hideSelColumns_actionPerformed(null);
2425         if (!toggleSeqs)
2426         {
2427           viewport.selectionGroup = sg;
2428         }
2429       }
2430       else if (!hide)
2431       {
2432         showAllColumns_actionPerformed(null);
2433       }
2434     }
2435   }
2436
2437   /*
2438    * (non-Javadoc)
2439    * 
2440    * @see
2441    * jalview.jbgui.GAlignFrame#hideAllButSelection_actionPerformed(java.awt.
2442    * event.ActionEvent)
2443    */
2444   public void hideAllButSelection_actionPerformed(ActionEvent e)
2445   {
2446     toggleHiddenRegions(false, false);
2447   }
2448
2449   /*
2450    * (non-Javadoc)
2451    * 
2452    * @see
2453    * jalview.jbgui.GAlignFrame#hideAllSelection_actionPerformed(java.awt.event
2454    * .ActionEvent)
2455    */
2456   public void hideAllSelection_actionPerformed(ActionEvent e)
2457   {
2458     SequenceGroup sg = viewport.getSelectionGroup();
2459     viewport.expandColSelection(sg, false);
2460     viewport.hideAllSelectedSeqs();
2461     viewport.hideSelectedColumns();
2462     alignPanel.paintAlignment(true);
2463   }
2464
2465   /*
2466    * (non-Javadoc)
2467    * 
2468    * @see
2469    * jalview.jbgui.GAlignFrame#showAllhidden_actionPerformed(java.awt.event.
2470    * ActionEvent)
2471    */
2472   public void showAllhidden_actionPerformed(ActionEvent e)
2473   {
2474     viewport.showAllHiddenColumns();
2475     viewport.showAllHiddenSeqs();
2476     alignPanel.paintAlignment(true);
2477   }
2478
2479   public void hideSelColumns_actionPerformed(ActionEvent e)
2480   {
2481     viewport.hideSelectedColumns();
2482     alignPanel.paintAlignment(true);
2483   }
2484
2485   public void hiddenMarkers_actionPerformed(ActionEvent e)
2486   {
2487     viewport.setShowHiddenMarkers(hiddenMarkers.isSelected());
2488     repaint();
2489   }
2490
2491   /**
2492    * DOCUMENT ME!
2493    * 
2494    * @param e
2495    *          DOCUMENT ME!
2496    */
2497   protected void scaleAbove_actionPerformed(ActionEvent e)
2498   {
2499     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
2500     alignPanel.paintAlignment(true);
2501   }
2502
2503   /**
2504    * DOCUMENT ME!
2505    * 
2506    * @param e
2507    *          DOCUMENT ME!
2508    */
2509   protected void scaleLeft_actionPerformed(ActionEvent e)
2510   {
2511     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
2512     alignPanel.paintAlignment(true);
2513   }
2514
2515   /**
2516    * DOCUMENT ME!
2517    * 
2518    * @param e
2519    *          DOCUMENT ME!
2520    */
2521   protected void scaleRight_actionPerformed(ActionEvent e)
2522   {
2523     viewport.setScaleRightWrapped(scaleRight.isSelected());
2524     alignPanel.paintAlignment(true);
2525   }
2526
2527   /**
2528    * DOCUMENT ME!
2529    * 
2530    * @param e
2531    *          DOCUMENT ME!
2532    */
2533   public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
2534   {
2535     viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
2536     alignPanel.paintAlignment(true);
2537   }
2538
2539   /**
2540    * DOCUMENT ME!
2541    * 
2542    * @param e
2543    *          DOCUMENT ME!
2544    */
2545   public void viewTextMenuItem_actionPerformed(ActionEvent e)
2546   {
2547     viewport.setShowText(viewTextMenuItem.isSelected());
2548     alignPanel.paintAlignment(true);
2549   }
2550
2551   /**
2552    * DOCUMENT ME!
2553    * 
2554    * @param e
2555    *          DOCUMENT ME!
2556    */
2557   protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
2558   {
2559     viewport.setRenderGaps(renderGapsMenuItem.isSelected());
2560     alignPanel.paintAlignment(true);
2561   }
2562
2563   public FeatureSettings featureSettings;
2564
2565   public void featureSettings_actionPerformed(ActionEvent e)
2566   {
2567     if (featureSettings != null)
2568     {
2569       featureSettings.close();
2570       featureSettings = null;
2571     }
2572     if (!showSeqFeatures.isSelected())
2573     {
2574       // make sure features are actually displayed
2575       showSeqFeatures.setSelected(true);
2576       showSeqFeatures_actionPerformed(null);
2577     }
2578     featureSettings = new FeatureSettings(this);
2579   }
2580
2581   /**
2582    * Set or clear 'Show Sequence Features'
2583    * 
2584    * @param evt
2585    *          DOCUMENT ME!
2586    */
2587   public void showSeqFeatures_actionPerformed(ActionEvent evt)
2588   {
2589     viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
2590     alignPanel.paintAlignment(true);
2591     if (alignPanel.getOverviewPanel() != null)
2592     {
2593       alignPanel.getOverviewPanel().updateOverviewImage();
2594     }
2595   }
2596
2597   /**
2598    * Set or clear 'Show Sequence Features'
2599    * 
2600    * @param evt
2601    *          DOCUMENT ME!
2602    */
2603   public void showSeqFeaturesHeight_actionPerformed(ActionEvent evt)
2604   {
2605     viewport.setShowSequenceFeaturesHeight(showSeqFeaturesHeight
2606             .isSelected());
2607     if (viewport.getShowSequenceFeaturesHeight())
2608     {
2609       // ensure we're actually displaying features
2610       viewport.setShowSequenceFeatures(true);
2611       showSeqFeatures.setSelected(true);
2612     }
2613     alignPanel.paintAlignment(true);
2614     if (alignPanel.getOverviewPanel() != null)
2615     {
2616       alignPanel.getOverviewPanel().updateOverviewImage();
2617     }
2618   }
2619
2620   /**
2621    * DOCUMENT ME!
2622    * 
2623    * @param e
2624    *          DOCUMENT ME!
2625    */
2626   public void annotationPanelMenuItem_actionPerformed(ActionEvent e)
2627   {
2628     viewport.setShowAnnotation(annotationPanelMenuItem.isSelected());
2629     alignPanel.setAnnotationVisible(annotationPanelMenuItem.isSelected());
2630   }
2631
2632   public void alignmentProperties()
2633   {
2634     JEditorPane editPane = new JEditorPane("text/html", "");
2635     editPane.setEditable(false);
2636     StringBuffer contents = new StringBuffer("<html>");
2637
2638     float avg = 0;
2639     int min = Integer.MAX_VALUE, max = 0;
2640     for (int i = 0; i < viewport.alignment.getHeight(); i++)
2641     {
2642       int size = viewport.alignment.getSequenceAt(i).getEnd()
2643               - viewport.alignment.getSequenceAt(i).getStart();
2644       avg += size;
2645       if (size > max)
2646         max = size;
2647       if (size < min)
2648         min = size;
2649     }
2650     avg = avg / (float) viewport.alignment.getHeight();
2651
2652     contents.append("<br>Sequences: " + viewport.alignment.getHeight());
2653     contents.append("<br>Minimum Sequence Length: " + min);
2654     contents.append("<br>Maximum Sequence Length: " + max);
2655     contents.append("<br>Average Length: " + (int) avg);
2656
2657     if (((Alignment) viewport.alignment).getProperties() != null)
2658     {
2659       Hashtable props = ((Alignment) viewport.alignment).getProperties();
2660       Enumeration en = props.keys();
2661       contents.append("<br><br><table border=\"1\">");
2662       while (en.hasMoreElements())
2663       {
2664         String key = en.nextElement().toString();
2665         StringBuffer val = new StringBuffer();
2666         String vals = props.get(key).toString();
2667         int pos = 0, npos;
2668         do
2669         {
2670           npos = vals.indexOf("\n", pos);
2671           if (npos == -1)
2672           {
2673             val.append(vals.substring(pos));
2674           }
2675           else
2676           {
2677             val.append(vals.substring(pos, npos));
2678             val.append("<br>");
2679           }
2680           pos = npos + 1;
2681         } while (npos != -1);
2682         contents
2683                 .append("<tr><td>" + key + "</td><td>" + val + "</td></tr>");
2684       }
2685       contents.append("</table>");
2686     }
2687     editPane.setText(contents.toString() + "</html>");
2688     JInternalFrame frame = new JInternalFrame();
2689     frame.getContentPane().add(new JScrollPane(editPane));
2690
2691     Desktop.instance.addInternalFrame(frame, "Alignment Properties: "
2692             + getTitle(), 500, 400);
2693   }
2694
2695   /**
2696    * DOCUMENT ME!
2697    * 
2698    * @param e
2699    *          DOCUMENT ME!
2700    */
2701   public void overviewMenuItem_actionPerformed(ActionEvent e)
2702   {
2703     if (alignPanel.overviewPanel != null)
2704     {
2705       return;
2706     }
2707
2708     JInternalFrame frame = new JInternalFrame();
2709     OverviewPanel overview = new OverviewPanel(alignPanel);
2710     frame.setContentPane(overview);
2711     Desktop.addInternalFrame(frame, "Overview " + this.getTitle(), frame
2712             .getWidth(), frame.getHeight());
2713     frame.pack();
2714     frame.setLayer(JLayeredPane.PALETTE_LAYER);
2715     frame
2716             .addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
2717             {
2718               public void internalFrameClosed(
2719                       javax.swing.event.InternalFrameEvent evt)
2720               {
2721                 alignPanel.setOverviewPanel(null);
2722               };
2723             });
2724
2725     alignPanel.setOverviewPanel(overview);
2726   }
2727
2728   public void textColour_actionPerformed(ActionEvent e)
2729   {
2730     new TextColourChooser().chooseColour(alignPanel, null);
2731   }
2732
2733   /**
2734    * DOCUMENT ME!
2735    * 
2736    * @param e
2737    *          DOCUMENT ME!
2738    */
2739   protected void noColourmenuItem_actionPerformed(ActionEvent e)
2740   {
2741     changeColour(null);
2742   }
2743
2744   /**
2745    * DOCUMENT ME!
2746    * 
2747    * @param e
2748    *          DOCUMENT ME!
2749    */
2750   public void clustalColour_actionPerformed(ActionEvent e)
2751   {
2752     changeColour(new ClustalxColourScheme(
2753             viewport.alignment.getSequences(), viewport.alignment
2754                     .getWidth()));
2755   }
2756
2757   /**
2758    * DOCUMENT ME!
2759    * 
2760    * @param e
2761    *          DOCUMENT ME!
2762    */
2763   public void zappoColour_actionPerformed(ActionEvent e)
2764   {
2765     changeColour(new ZappoColourScheme());
2766   }
2767
2768   /**
2769    * DOCUMENT ME!
2770    * 
2771    * @param e
2772    *          DOCUMENT ME!
2773    */
2774   public void taylorColour_actionPerformed(ActionEvent e)
2775   {
2776     changeColour(new TaylorColourScheme());
2777   }
2778
2779   /**
2780    * DOCUMENT ME!
2781    * 
2782    * @param e
2783    *          DOCUMENT ME!
2784    */
2785   public void hydrophobicityColour_actionPerformed(ActionEvent e)
2786   {
2787     changeColour(new HydrophobicColourScheme());
2788   }
2789
2790   /**
2791    * DOCUMENT ME!
2792    * 
2793    * @param e
2794    *          DOCUMENT ME!
2795    */
2796   public void helixColour_actionPerformed(ActionEvent e)
2797   {
2798     changeColour(new HelixColourScheme());
2799   }
2800
2801   /**
2802    * DOCUMENT ME!
2803    * 
2804    * @param e
2805    *          DOCUMENT ME!
2806    */
2807   public void strandColour_actionPerformed(ActionEvent e)
2808   {
2809     changeColour(new StrandColourScheme());
2810   }
2811
2812   /**
2813    * DOCUMENT ME!
2814    * 
2815    * @param e
2816    *          DOCUMENT ME!
2817    */
2818   public void turnColour_actionPerformed(ActionEvent e)
2819   {
2820     changeColour(new TurnColourScheme());
2821   }
2822
2823   /**
2824    * DOCUMENT ME!
2825    * 
2826    * @param e
2827    *          DOCUMENT ME!
2828    */
2829   public void buriedColour_actionPerformed(ActionEvent e)
2830   {
2831     changeColour(new BuriedColourScheme());
2832   }
2833
2834   /**
2835    * DOCUMENT ME!
2836    * 
2837    * @param e
2838    *          DOCUMENT ME!
2839    */
2840   public void nucleotideColour_actionPerformed(ActionEvent e)
2841   {
2842     changeColour(new NucleotideColourScheme());
2843   }
2844
2845   public void annotationColour_actionPerformed(ActionEvent e)
2846   {
2847     new AnnotationColourChooser(viewport, alignPanel);
2848   }
2849
2850   /**
2851    * DOCUMENT ME!
2852    * 
2853    * @param e
2854    *          DOCUMENT ME!
2855    */
2856   protected void applyToAllGroups_actionPerformed(ActionEvent e)
2857   {
2858     viewport.setColourAppliesToAllGroups(applyToAllGroups.isSelected());
2859   }
2860
2861   /**
2862    * DOCUMENT ME!
2863    * 
2864    * @param cs
2865    *          DOCUMENT ME!
2866    */
2867   public void changeColour(ColourSchemeI cs)
2868   {
2869     int threshold = 0;
2870
2871     if (cs != null)
2872     {
2873       if (viewport.getAbovePIDThreshold())
2874       {
2875         threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
2876                 "Background");
2877
2878         cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
2879
2880         viewport.setGlobalColourScheme(cs);
2881       }
2882       else
2883       {
2884         cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
2885       }
2886
2887       if (viewport.getConservationSelected())
2888       {
2889
2890         Alignment al = (Alignment) viewport.alignment;
2891         Conservation c = new Conservation("All",
2892                 ResidueProperties.propHash, 3, al.getSequences(), 0, al
2893                         .getWidth() - 1);
2894
2895         c.calculate();
2896         c.verdict(false, viewport.ConsPercGaps);
2897
2898         cs.setConservation(c);
2899
2900         cs.setConservationInc(SliderPanel.setConservationSlider(alignPanel,
2901                 cs, "Background"));
2902       }
2903       else
2904       {
2905         cs.setConservation(null);
2906       }
2907
2908       cs.setConsensus(viewport.hconsensus);
2909     }
2910
2911     viewport.setGlobalColourScheme(cs);
2912
2913     if (viewport.getColourAppliesToAllGroups())
2914     {
2915       Vector groups = viewport.alignment.getGroups();
2916
2917       for (int i = 0; i < groups.size(); i++)
2918       {
2919         SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
2920
2921         if (cs == null)
2922         {
2923           sg.cs = null;
2924           continue;
2925         }
2926
2927         if (cs instanceof ClustalxColourScheme)
2928         {
2929           sg.cs = new ClustalxColourScheme(sg
2930                   .getSequences(viewport.hiddenRepSequences), sg.getWidth());
2931         }
2932         else if (cs instanceof UserColourScheme)
2933         {
2934           sg.cs = new UserColourScheme(((UserColourScheme) cs).getColours());
2935         }
2936         else
2937         {
2938           try
2939           {
2940             sg.cs = (ColourSchemeI) cs.getClass().newInstance();
2941           } catch (Exception ex)
2942           {
2943           }
2944         }
2945
2946         if (viewport.getAbovePIDThreshold()
2947                 || cs instanceof PIDColourScheme
2948                 || cs instanceof Blosum62ColourScheme)
2949         {
2950           sg.cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
2951
2952           sg.cs.setConsensus(AAFrequency.calculate(sg
2953                   .getSequences(viewport.hiddenRepSequences), sg
2954                   .getStartRes(), sg.getEndRes() + 1));
2955         }
2956         else
2957         {
2958           sg.cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
2959         }
2960
2961         if (viewport.getConservationSelected())
2962         {
2963           Conservation c = new Conservation("Group",
2964                   ResidueProperties.propHash, 3, sg
2965                           .getSequences(viewport.hiddenRepSequences), sg
2966                           .getStartRes(), sg.getEndRes() + 1);
2967           c.calculate();
2968           c.verdict(false, viewport.ConsPercGaps);
2969           sg.cs.setConservation(c);
2970         }
2971         else
2972         {
2973           sg.cs.setConservation(null);
2974         }
2975       }
2976     }
2977
2978     if (alignPanel.getOverviewPanel() != null)
2979     {
2980       alignPanel.getOverviewPanel().updateOverviewImage();
2981     }
2982
2983     alignPanel.paintAlignment(true);
2984   }
2985
2986   /**
2987    * DOCUMENT ME!
2988    * 
2989    * @param e
2990    *          DOCUMENT ME!
2991    */
2992   protected void modifyPID_actionPerformed(ActionEvent e)
2993   {
2994     if (viewport.getAbovePIDThreshold()
2995             && viewport.globalColourScheme != null)
2996     {
2997       SliderPanel.setPIDSliderSource(alignPanel, viewport
2998               .getGlobalColourScheme(), "Background");
2999       SliderPanel.showPIDSlider();
3000     }
3001   }
3002
3003   /**
3004    * DOCUMENT ME!
3005    * 
3006    * @param e
3007    *          DOCUMENT ME!
3008    */
3009   protected void modifyConservation_actionPerformed(ActionEvent e)
3010   {
3011     if (viewport.getConservationSelected()
3012             && viewport.globalColourScheme != null)
3013     {
3014       SliderPanel.setConservationSlider(alignPanel,
3015               viewport.globalColourScheme, "Background");
3016       SliderPanel.showConservationSlider();
3017     }
3018   }
3019
3020   /**
3021    * DOCUMENT ME!
3022    * 
3023    * @param e
3024    *          DOCUMENT ME!
3025    */
3026   protected void conservationMenuItem_actionPerformed(ActionEvent e)
3027   {
3028     viewport.setConservationSelected(conservationMenuItem.isSelected());
3029
3030     viewport.setAbovePIDThreshold(false);
3031     abovePIDThreshold.setSelected(false);
3032
3033     changeColour(viewport.getGlobalColourScheme());
3034
3035     modifyConservation_actionPerformed(null);
3036   }
3037
3038   /**
3039    * DOCUMENT ME!
3040    * 
3041    * @param e
3042    *          DOCUMENT ME!
3043    */
3044   public void abovePIDThreshold_actionPerformed(ActionEvent e)
3045   {
3046     viewport.setAbovePIDThreshold(abovePIDThreshold.isSelected());
3047
3048     conservationMenuItem.setSelected(false);
3049     viewport.setConservationSelected(false);
3050
3051     changeColour(viewport.getGlobalColourScheme());
3052
3053     modifyPID_actionPerformed(null);
3054   }
3055
3056   /**
3057    * DOCUMENT ME!
3058    * 
3059    * @param e
3060    *          DOCUMENT ME!
3061    */
3062   public void userDefinedColour_actionPerformed(ActionEvent e)
3063   {
3064     if (e.getActionCommand().equals("User Defined..."))
3065     {
3066       new UserDefinedColours(alignPanel, null);
3067     }
3068     else
3069     {
3070       UserColourScheme udc = (UserColourScheme) UserDefinedColours
3071               .getUserColourSchemes().get(e.getActionCommand());
3072
3073       changeColour(udc);
3074     }
3075   }
3076
3077   public void updateUserColourMenu()
3078   {
3079
3080     Component[] menuItems = colourMenu.getMenuComponents();
3081     int i, iSize = menuItems.length;
3082     for (i = 0; i < iSize; i++)
3083     {
3084       if (menuItems[i].getName() != null
3085               && menuItems[i].getName().equals("USER_DEFINED"))
3086       {
3087         colourMenu.remove(menuItems[i]);
3088         iSize--;
3089       }
3090     }
3091     if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)
3092     {
3093       java.util.Enumeration userColours = jalview.gui.UserDefinedColours
3094               .getUserColourSchemes().keys();
3095
3096       while (userColours.hasMoreElements())
3097       {
3098         final JRadioButtonMenuItem radioItem = new JRadioButtonMenuItem(
3099                 userColours.nextElement().toString());
3100         radioItem.setName("USER_DEFINED");
3101         radioItem.addMouseListener(new MouseAdapter()
3102         {
3103           public void mousePressed(MouseEvent evt)
3104           {
3105             if (evt.isControlDown()
3106                     || SwingUtilities.isRightMouseButton(evt))
3107             {
3108               radioItem
3109                       .removeActionListener(radioItem.getActionListeners()[0]);
3110
3111               int option = JOptionPane.showInternalConfirmDialog(
3112                       jalview.gui.Desktop.desktop,
3113                       "Remove from default list?",
3114                       "Remove user defined colour",
3115                       JOptionPane.YES_NO_OPTION);
3116               if (option == JOptionPane.YES_OPTION)
3117               {
3118                 jalview.gui.UserDefinedColours
3119                         .removeColourFromDefaults(radioItem.getText());
3120                 colourMenu.remove(radioItem);
3121               }
3122               else
3123               {
3124                 radioItem.addActionListener(new ActionListener()
3125                 {
3126                   public void actionPerformed(ActionEvent evt)
3127                   {
3128                     userDefinedColour_actionPerformed(evt);
3129                   }
3130                 });
3131               }
3132             }
3133           }
3134         });
3135         radioItem.addActionListener(new ActionListener()
3136         {
3137           public void actionPerformed(ActionEvent evt)
3138           {
3139             userDefinedColour_actionPerformed(evt);
3140           }
3141         });
3142
3143         colourMenu.insert(radioItem, 15);
3144         colours.add(radioItem);
3145       }
3146     }
3147   }
3148
3149   /**
3150    * DOCUMENT ME!
3151    * 
3152    * @param e
3153    *          DOCUMENT ME!
3154    */
3155   public void PIDColour_actionPerformed(ActionEvent e)
3156   {
3157     changeColour(new PIDColourScheme());
3158   }
3159
3160   /**
3161    * DOCUMENT ME!
3162    * 
3163    * @param e
3164    *          DOCUMENT ME!
3165    */
3166   public void BLOSUM62Colour_actionPerformed(ActionEvent e)
3167   {
3168     changeColour(new Blosum62ColourScheme());
3169   }
3170
3171   /**
3172    * DOCUMENT ME!
3173    * 
3174    * @param e
3175    *          DOCUMENT ME!
3176    */
3177   public void sortPairwiseMenuItem_actionPerformed(ActionEvent e)
3178   {
3179     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3180     AlignmentSorter.sortByPID(viewport.getAlignment(), viewport
3181             .getAlignment().getSequenceAt(0), null);
3182     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
3183             viewport.alignment));
3184     alignPanel.paintAlignment(true);
3185   }
3186
3187   /**
3188    * DOCUMENT ME!
3189    * 
3190    * @param e
3191    *          DOCUMENT ME!
3192    */
3193   public void sortIDMenuItem_actionPerformed(ActionEvent e)
3194   {
3195     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3196     AlignmentSorter.sortByID(viewport.getAlignment());
3197     addHistoryItem(new OrderCommand("ID Sort", oldOrder, viewport.alignment));
3198     alignPanel.paintAlignment(true);
3199   }
3200
3201   /**
3202    * DOCUMENT ME!
3203    * 
3204    * @param e
3205    *          DOCUMENT ME!
3206    */
3207   public void sortLengthMenuItem_actionPerformed(ActionEvent e)
3208   {
3209     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3210     AlignmentSorter.sortByLength(viewport.getAlignment());
3211     addHistoryItem(new OrderCommand("Length Sort", oldOrder,
3212             viewport.alignment));
3213     alignPanel.paintAlignment(true);
3214   }
3215
3216   /**
3217    * DOCUMENT ME!
3218    * 
3219    * @param e
3220    *          DOCUMENT ME!
3221    */
3222   public void sortGroupMenuItem_actionPerformed(ActionEvent e)
3223   {
3224     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3225     AlignmentSorter.sortByGroup(viewport.getAlignment());
3226     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
3227             viewport.alignment));
3228
3229     alignPanel.paintAlignment(true);
3230   }
3231
3232   /**
3233    * DOCUMENT ME!
3234    * 
3235    * @param e
3236    *          DOCUMENT ME!
3237    */
3238   public void removeRedundancyMenuItem_actionPerformed(ActionEvent e)
3239   {
3240     new RedundancyPanel(alignPanel, this);
3241   }
3242
3243   /**
3244    * DOCUMENT ME!
3245    * 
3246    * @param e
3247    *          DOCUMENT ME!
3248    */
3249   public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e)
3250   {
3251     if ((viewport.getSelectionGroup() == null)
3252             || (viewport.getSelectionGroup().getSize() < 2))
3253     {
3254       JOptionPane.showInternalMessageDialog(this,
3255               "You must select at least 2 sequences.", "Invalid Selection",
3256               JOptionPane.WARNING_MESSAGE);
3257     }
3258     else
3259     {
3260       JInternalFrame frame = new JInternalFrame();
3261       frame.setContentPane(new PairwiseAlignPanel(viewport));
3262       Desktop.addInternalFrame(frame, "Pairwise Alignment", 600, 500);
3263     }
3264   }
3265
3266   /**
3267    * DOCUMENT ME!
3268    * 
3269    * @param e
3270    *          DOCUMENT ME!
3271    */
3272   public void PCAMenuItem_actionPerformed(ActionEvent e)
3273   {
3274     if (((viewport.getSelectionGroup() != null)
3275             && (viewport.getSelectionGroup().getSize() < 4) && (viewport
3276             .getSelectionGroup().getSize() > 0))
3277             || (viewport.getAlignment().getHeight() < 4))
3278     {
3279       JOptionPane.showInternalMessageDialog(this,
3280               "Principal component analysis must take\n"
3281                       + "at least 4 input sequences.",
3282               "Sequence selection insufficient",
3283               JOptionPane.WARNING_MESSAGE);
3284
3285       return;
3286     }
3287
3288     new PCAPanel(alignPanel);
3289   }
3290
3291   public void autoCalculate_actionPerformed(ActionEvent e)
3292   {
3293     viewport.autoCalculateConsensus = autoCalculate.isSelected();
3294     if (viewport.autoCalculateConsensus)
3295     {
3296       viewport.firePropertyChange("alignment", null, viewport
3297               .getAlignment().getSequences());
3298     }
3299   }
3300
3301   /**
3302    * DOCUMENT ME!
3303    * 
3304    * @param e
3305    *          DOCUMENT ME!
3306    */
3307   public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)
3308   {
3309     NewTreePanel("AV", "PID", "Average distance tree using PID");
3310   }
3311
3312   /**
3313    * DOCUMENT ME!
3314    * 
3315    * @param e
3316    *          DOCUMENT ME!
3317    */
3318   public void neighbourTreeMenuItem_actionPerformed(ActionEvent e)
3319   {
3320     NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
3321   }
3322
3323   /**
3324    * DOCUMENT ME!
3325    * 
3326    * @param e
3327    *          DOCUMENT ME!
3328    */
3329   protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)
3330   {
3331     NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
3332   }
3333
3334   /**
3335    * DOCUMENT ME!
3336    * 
3337    * @param e
3338    *          DOCUMENT ME!
3339    */
3340   protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e)
3341   {
3342     NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
3343   }
3344
3345   /**
3346    * DOCUMENT ME!
3347    * 
3348    * @param type
3349    *          DOCUMENT ME!
3350    * @param pwType
3351    *          DOCUMENT ME!
3352    * @param title
3353    *          DOCUMENT ME!
3354    */
3355   void NewTreePanel(String type, String pwType, String title)
3356   {
3357     TreePanel tp;
3358
3359     if (viewport.getSelectionGroup() != null)
3360     {
3361       if (viewport.getSelectionGroup().getSize() < 3)
3362       {
3363         JOptionPane
3364                 .showMessageDialog(
3365                         Desktop.desktop,
3366                         "You need to have more than two sequences selected to build a tree!",
3367                         "Not enough sequences", JOptionPane.WARNING_MESSAGE);
3368         return;
3369       }
3370
3371       int s = 0;
3372       SequenceGroup sg = viewport.getSelectionGroup();
3373
3374       /* Decide if the selection is a column region */
3375       while (s < sg.getSize())
3376       {
3377         if (((SequenceI) sg.getSequences(null).elementAt(s++)).getLength() < sg
3378                 .getEndRes())
3379         {
3380           JOptionPane
3381                   .showMessageDialog(
3382                           Desktop.desktop,
3383                           "The selected region to create a tree may\nonly contain residues or gaps.\n"
3384                                   + "Try using the Pad function in the edit menu,\n"
3385                                   + "or one of the multiple sequence alignment web services.",
3386                           "Sequences in selection are not aligned",
3387                           JOptionPane.WARNING_MESSAGE);
3388
3389           return;
3390         }
3391       }
3392
3393       title = title + " on region";
3394       tp = new TreePanel(alignPanel, type, pwType);
3395     }
3396     else
3397     {
3398       // are the visible sequences aligned?
3399       if (!viewport.alignment.isAligned(false))
3400       {
3401         JOptionPane
3402                 .showMessageDialog(
3403                         Desktop.desktop,
3404                         "The sequences must be aligned before creating a tree.\n"
3405                                 + "Try using the Pad function in the edit menu,\n"
3406                                 + "or one of the multiple sequence alignment web services.",
3407                         "Sequences not aligned",
3408                         JOptionPane.WARNING_MESSAGE);
3409
3410         return;
3411       }
3412
3413       if (viewport.alignment.getHeight() < 2)
3414       {
3415         return;
3416       }
3417
3418       tp = new TreePanel(alignPanel, type, pwType);
3419     }
3420
3421     title += " from ";
3422
3423     if (viewport.viewName != null)
3424     {
3425       title += viewport.viewName + " of ";
3426     }
3427
3428     title += this.title;
3429
3430     Desktop.addInternalFrame(tp, title, 600, 500);
3431   }
3432
3433   /**
3434    * DOCUMENT ME!
3435    * 
3436    * @param title
3437    *          DOCUMENT ME!
3438    * @param order
3439    *          DOCUMENT ME!
3440    */
3441   public void addSortByOrderMenuItem(String title,
3442           final AlignmentOrder order)
3443   {
3444     final JMenuItem item = new JMenuItem("by " + title);
3445     sort.add(item);
3446     item.addActionListener(new java.awt.event.ActionListener()
3447     {
3448       public void actionPerformed(ActionEvent e)
3449       {
3450         SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3451
3452         // TODO: JBPNote - have to map order entries to curent SequenceI
3453         // pointers
3454         AlignmentSorter.sortBy(viewport.getAlignment(), order);
3455
3456         addHistoryItem(new OrderCommand(order.getName(), oldOrder,
3457                 viewport.alignment));
3458
3459         alignPanel.paintAlignment(true);
3460       }
3461     });
3462   }
3463
3464   /**
3465    * Add a new sort by annotation score menu item
3466    * 
3467    * @param sort
3468    *          the menu to add the option to
3469    * @param scoreLabel
3470    *          the label used to retrieve scores for each sequence on the
3471    *          alignment
3472    */
3473   public void addSortByAnnotScoreMenuItem(JMenu sort,
3474           final String scoreLabel)
3475   {
3476     final JMenuItem item = new JMenuItem(scoreLabel);
3477     sort.add(item);
3478     item.addActionListener(new java.awt.event.ActionListener()
3479     {
3480       public void actionPerformed(ActionEvent e)
3481       {
3482         SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3483         AlignmentSorter.sortByAnnotationScore(scoreLabel, viewport
3484                 .getAlignment());// ,viewport.getSelectionGroup());
3485         addHistoryItem(new OrderCommand("Sort by " + scoreLabel, oldOrder,
3486                 viewport.alignment));
3487         alignPanel.paintAlignment(true);
3488       }
3489     });
3490   }
3491
3492   /**
3493    * last hash for alignment's annotation array - used to minimise cost of
3494    * rebuild.
3495    */
3496   protected int _annotationScoreVectorHash;
3497
3498   /**
3499    * search the alignment and rebuild the sort by annotation score submenu the
3500    * last alignment annotation vector hash is stored to minimize cost of
3501    * rebuilding in subsequence calls.
3502    * 
3503    */
3504   public void buildSortByAnnotationScoresMenu()
3505   {
3506     if (viewport.alignment.getAlignmentAnnotation() == null)
3507     {
3508       return;
3509     }
3510
3511     if (viewport.alignment.getAlignmentAnnotation().hashCode() != _annotationScoreVectorHash)
3512     {
3513       sortByAnnotScore.removeAll();
3514       // almost certainly a quicker way to do this - but we keep it simple
3515       Hashtable scoreSorts = new Hashtable();
3516       AlignmentAnnotation aann[];
3517       Enumeration sq = viewport.alignment.getSequences().elements();
3518       while (sq.hasMoreElements())
3519       {
3520         aann = ((SequenceI) sq.nextElement()).getAnnotation();
3521         for (int i = 0; aann != null && i < aann.length; i++)
3522         {
3523           if (aann[i].hasScore() && aann[i].sequenceRef != null)
3524           {
3525             scoreSorts.put(aann[i].label, aann[i].label);
3526           }
3527         }
3528       }
3529       Enumeration labels = scoreSorts.keys();
3530       while (labels.hasMoreElements())
3531       {
3532         addSortByAnnotScoreMenuItem(sortByAnnotScore, (String) labels
3533                 .nextElement());
3534       }
3535       sortByAnnotScore.setVisible(scoreSorts.size() > 0);
3536       scoreSorts.clear();
3537
3538       _annotationScoreVectorHash = viewport.alignment
3539               .getAlignmentAnnotation().hashCode();
3540     }
3541   }
3542
3543   /**
3544    * Maintain the Order by->Displayed Tree menu. Creates a new menu item for a
3545    * TreePanel with an appropriate <code>jalview.analysis.AlignmentSorter</code>
3546    * call. Listeners are added to remove the menu item when the treePanel is
3547    * closed, and adjust the tree leaf to sequence mapping when the alignment is
3548    * modified.
3549    * 
3550    * @param treePanel
3551    *          Displayed tree window.
3552    * @param title
3553    *          SortBy menu item title.
3554    */
3555   public void buildTreeMenu()
3556   {
3557     sortByTreeMenu.removeAll();
3558
3559     Vector comps = (Vector) PaintRefresher.components.get(viewport
3560             .getSequenceSetId());
3561     Vector treePanels = new Vector();
3562     int i, iSize = comps.size();
3563     for (i = 0; i < iSize; i++)
3564     {
3565       if (comps.elementAt(i) instanceof TreePanel)
3566       {
3567         treePanels.add(comps.elementAt(i));
3568       }
3569     }
3570
3571     iSize = treePanels.size();
3572
3573     if (iSize < 1)
3574     {
3575       sortByTreeMenu.setVisible(false);
3576       return;
3577     }
3578
3579     sortByTreeMenu.setVisible(true);
3580
3581     for (i = 0; i < treePanels.size(); i++)
3582     {
3583       TreePanel tp = (TreePanel) treePanels.elementAt(i);
3584       final JMenuItem item = new JMenuItem(tp.getTitle());
3585       final NJTree tree = ((TreePanel) treePanels.elementAt(i)).getTree();
3586       item.addActionListener(new java.awt.event.ActionListener()
3587       {
3588         public void actionPerformed(ActionEvent e)
3589         {
3590           SequenceI[] oldOrder = viewport.getAlignment()
3591                   .getSequencesArray();
3592           AlignmentSorter.sortByTree(viewport.getAlignment(), tree);
3593
3594           addHistoryItem(new OrderCommand("Tree Sort", oldOrder,
3595                   viewport.alignment));
3596
3597           alignPanel.paintAlignment(true);
3598         }
3599       });
3600
3601       sortByTreeMenu.add(item);
3602     }
3603   }
3604
3605   /**
3606    * Work out whether the whole set of sequences or just the selected set will
3607    * be submitted for multiple alignment.
3608    * 
3609    */
3610   public jalview.datamodel.AlignmentView gatherSequencesForAlignment()
3611   {
3612     // Now, check we have enough sequences
3613     AlignmentView msa = null;
3614
3615     if ((viewport.getSelectionGroup() != null)
3616             && (viewport.getSelectionGroup().getSize() > 1))
3617     {
3618       // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to
3619       // some common interface!
3620       /*
3621        * SequenceGroup seqs = viewport.getSelectionGroup(); int sz; msa = new
3622        * SequenceI[sz = seqs.getSize(false)];
3623        * 
3624        * for (int i = 0; i < sz; i++) { msa[i] = (SequenceI)
3625        * seqs.getSequenceAt(i); }
3626        */
3627       msa = viewport.getAlignmentView(true);
3628     }
3629     else
3630     {
3631       /*
3632        * Vector seqs = viewport.getAlignment().getSequences();
3633        * 
3634        * if (seqs.size() > 1) { msa = new SequenceI[seqs.size()];
3635        * 
3636        * for (int i = 0; i < seqs.size(); i++) { msa[i] = (SequenceI)
3637        * seqs.elementAt(i); } }
3638        */
3639       msa = viewport.getAlignmentView(false);
3640     }
3641     return msa;
3642   }
3643
3644   /**
3645    * Decides what is submitted to a secondary structure prediction service: the
3646    * first sequence in the alignment, or in the current selection, or, if the
3647    * alignment is 'aligned' (ie padded with gaps), then the currently selected
3648    * region or the whole alignment. (where the first sequence in the set is the
3649    * one that the prediction will be for).
3650    */
3651   public AlignmentView gatherSeqOrMsaForSecStrPrediction()
3652   {
3653     AlignmentView seqs = null;
3654
3655     if ((viewport.getSelectionGroup() != null)
3656             && (viewport.getSelectionGroup().getSize() > 0))
3657     {
3658       seqs = viewport.getAlignmentView(true);
3659     }
3660     else
3661     {
3662       seqs = viewport.getAlignmentView(false);
3663     }
3664     // limit sequences - JBPNote in future - could spawn multiple prediction
3665     // jobs
3666     // TODO: viewport.alignment.isAligned is a global state - the local
3667     // selection may well be aligned - we preserve 2.0.8 behaviour for moment.
3668     if (!viewport.alignment.isAligned(false))
3669     {
3670       seqs.setSequences(new SeqCigar[]
3671       { seqs.getSequences()[0] });
3672       // TODO: if seqs.getSequences().length>1 then should really have warned
3673       // user!
3674
3675     }
3676     return seqs;
3677   }
3678
3679   /**
3680    * DOCUMENT ME!
3681    * 
3682    * @param e
3683    *          DOCUMENT ME!
3684    */
3685   protected void LoadtreeMenuItem_actionPerformed(ActionEvent e)
3686   {
3687     // Pick the tree file
3688     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
3689             .getProperty("LAST_DIRECTORY"));
3690     chooser.setFileView(new JalviewFileView());
3691     chooser.setDialogTitle("Select a newick-like tree file");
3692     chooser.setToolTipText("Load a tree file");
3693
3694     int value = chooser.showOpenDialog(null);
3695
3696     if (value == JalviewFileChooser.APPROVE_OPTION)
3697     {
3698       String choice = chooser.getSelectedFile().getPath();
3699       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
3700       jalview.io.NewickFile fin = null;
3701       try
3702       {
3703         fin = new jalview.io.NewickFile(choice, "File");
3704         viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
3705       } catch (Exception ex)
3706       {
3707         JOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(),
3708                 "Problem reading tree file", JOptionPane.WARNING_MESSAGE);
3709         ex.printStackTrace();
3710       }
3711       if (fin != null && fin.hasWarningMessage())
3712       {
3713         JOptionPane.showMessageDialog(Desktop.desktop, fin
3714                 .getWarningMessage(), "Possible problem with tree file",
3715                 JOptionPane.WARNING_MESSAGE);
3716       }
3717     }
3718   }
3719
3720   public TreePanel ShowNewickTree(NewickFile nf, String title)
3721   {
3722     return ShowNewickTree(nf, title, 600, 500, 4, 5);
3723   }
3724
3725   public TreePanel ShowNewickTree(NewickFile nf, String title,
3726           AlignmentView input)
3727   {
3728     return ShowNewickTree(nf, title, input, 600, 500, 4, 5);
3729   }
3730
3731   public TreePanel ShowNewickTree(NewickFile nf, String title, int w,
3732           int h, int x, int y)
3733   {
3734     return ShowNewickTree(nf, title, null, w, h, x, y);
3735   }
3736
3737   /**
3738    * Add a treeviewer for the tree extracted from a newick file object to the
3739    * current alignment view
3740    * 
3741    * @param nf
3742    *          the tree
3743    * @param title
3744    *          tree viewer title
3745    * @param input
3746    *          Associated alignment input data (or null)
3747    * @param w
3748    *          width
3749    * @param h
3750    *          height
3751    * @param x
3752    *          position
3753    * @param y
3754    *          position
3755    * @return TreePanel handle
3756    */
3757   public TreePanel ShowNewickTree(NewickFile nf, String title,
3758           AlignmentView input, int w, int h, int x, int y)
3759   {
3760     TreePanel tp = null;
3761
3762     try
3763     {
3764       nf.parse();
3765
3766       if (nf.getTree() != null)
3767       {
3768         tp = new TreePanel(alignPanel, "FromFile", title, nf, input);
3769
3770         tp.setSize(w, h);
3771
3772         if (x > 0 && y > 0)
3773         {
3774           tp.setLocation(x, y);
3775         }
3776
3777         Desktop.addInternalFrame(tp, title, w, h);
3778       }
3779     } catch (Exception ex)
3780     {
3781       ex.printStackTrace();
3782     }
3783
3784     return tp;
3785   }
3786
3787   /**
3788    * Generates menu items and listener event actions for web service clients
3789    * 
3790    */
3791   public void BuildWebServiceMenu()
3792   {
3793     // TODO: add support for context dependent disabling of services based on
3794     // alignment and current selection
3795     // TODO: add additional serviceHandle parameter to specify abstract handler
3796     // class independently of AbstractName
3797     // TODO: add in rediscovery GUI function to restart discoverer
3798     // TODO: group services by location as well as function and/or introduce
3799     // object broker mechanism.
3800     if ((Discoverer.services != null) && (Discoverer.services.size() > 0))
3801     {
3802       // TODO: refactor to allow list of AbstractName/Handler bindings to be
3803       // stored or retrieved from elsewhere
3804       Vector msaws = (Vector) Discoverer.services.get("MsaWS");
3805       Vector secstrpr = (Vector) Discoverer.services.get("SecStrPred");
3806       Vector seqsrch = (Vector) Discoverer.services.get("SeqSearch");
3807       // TODO: move GUI generation code onto service implementation - so a
3808       // client instance attaches itself to the GUI with method call like
3809       // jalview.ws.MsaWSClient.bind(servicehandle, Desktop.instance,
3810       // alignframe)
3811       Vector wsmenu = new Vector();
3812       final IProgressIndicator af = this;
3813       if (msaws != null)
3814       {
3815         // Add any Multiple Sequence Alignment Services
3816         final JMenu msawsmenu = new JMenu("Alignment");
3817         for (int i = 0, j = msaws.size(); i < j; i++)
3818         {
3819           final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) msaws
3820                   .get(i);
3821           jalview.ws.WSClient impl = jalview.ws.Discoverer
3822                   .getServiceClient(sh);
3823           impl.attachWSMenuEntry(msawsmenu, this);
3824
3825         }
3826         wsmenu.add(msawsmenu);
3827       }
3828       if (secstrpr != null)
3829       {
3830         // Add any secondary structure prediction services
3831         final JMenu secstrmenu = new JMenu("Secondary Structure Prediction");
3832         for (int i = 0, j = secstrpr.size(); i < j; i++)
3833         {
3834           final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr
3835                   .get(i);
3836           jalview.ws.WSClient impl = jalview.ws.Discoverer
3837                   .getServiceClient(sh);
3838           impl.attachWSMenuEntry(secstrmenu, this);
3839         }
3840         wsmenu.add(secstrmenu);
3841       }
3842       if (seqsrch != null)
3843       {
3844         // Add any sequence search services
3845         final JMenu seqsrchmenu = new JMenu("Sequence Database Search");
3846         for (int i = 0, j = seqsrch.size(); i < j; i++)
3847         {
3848           final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) seqsrch
3849                   .elementAt(i);
3850           jalview.ws.WSClient impl = jalview.ws.Discoverer
3851                   .getServiceClient(sh);
3852           impl.attachWSMenuEntry(seqsrchmenu, this);
3853         }
3854         wsmenu.add(seqsrchmenu);
3855       }
3856       // finally, add the whole shebang onto the webservices menu
3857       resetWebServiceMenu();
3858       for (int i = 0, j = wsmenu.size(); i < j; i++)
3859       {
3860         webService.add((JMenu) wsmenu.get(i));
3861       }
3862     }
3863     else
3864     {
3865       resetWebServiceMenu();
3866       this.webService.add(this.webServiceNoServices);
3867     }
3868   }
3869
3870   /**
3871    * empty the web service menu and add any ad-hoc functions not dynamically
3872    * discovered.
3873    * 
3874    */
3875   private void resetWebServiceMenu()
3876   {
3877     webService.removeAll();
3878     build_fetchdbmenu(webService);
3879     build_urlServiceMenu(webService);
3880   }
3881
3882   /**
3883    * construct any groupURL type service menu entries.
3884    * 
3885    * @param webService
3886    */
3887   private void build_urlServiceMenu(JMenu webService)
3888   {
3889     jalview.ws.EnfinEnvision2OneWay.getInstance().attachWSMenuEntry(
3890             webService, this);
3891   }
3892
3893   /*
3894    * public void vamsasStore_actionPerformed(ActionEvent e) { JalviewFileChooser
3895    * chooser = new JalviewFileChooser(jalview.bin.Cache.
3896    * getProperty("LAST_DIRECTORY"));
3897    * 
3898    * chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle("Export
3899    * to Vamsas file"); chooser.setToolTipText("Export");
3900    * 
3901    * int value = chooser.showSaveDialog(this);
3902    * 
3903    * if (value == JalviewFileChooser.APPROVE_OPTION) {
3904    * jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport);
3905    * //vs.store(chooser.getSelectedFile().getAbsolutePath() ); vs.storeJalview(
3906    * chooser.getSelectedFile().getAbsolutePath(), this); } }
3907    */
3908   /**
3909    * prototype of an automatically enabled/disabled analysis function
3910    * 
3911    */
3912   protected void setShowProductsEnabled()
3913   {
3914     SequenceI[] selection = viewport.getSequenceSelection();
3915     if (canShowProducts(selection, viewport.getSelectionGroup() != null,
3916             viewport.getAlignment().getDataset()))
3917     {
3918       showProducts.setEnabled(true);
3919
3920     }
3921     else
3922     {
3923       showProducts.setEnabled(false);
3924     }
3925   }
3926
3927   /**
3928    * search selection for sequence xRef products and build the show products
3929    * menu.
3930    * 
3931    * @param selection
3932    * @param dataset
3933    * @return true if showProducts menu should be enabled.
3934    */
3935   public boolean canShowProducts(SequenceI[] selection,
3936           boolean isRegionSelection, Alignment dataset)
3937   {
3938     boolean showp = false;
3939     try
3940     {
3941       showProducts.removeAll();
3942       final boolean dna = viewport.getAlignment().isNucleotide();
3943       final Alignment ds = dataset;
3944       String[] ptypes = (selection == null || selection.length == 0) ? null
3945               : CrossRef.findSequenceXrefTypes(dna, selection, dataset);
3946       // Object[] prods =
3947       // CrossRef.buildXProductsList(viewport.getAlignment().isNucleotide(),
3948       // selection, dataset, true);
3949       final SequenceI[] sel = selection;
3950       for (int t = 0; ptypes != null && t < ptypes.length; t++)
3951       {
3952         showp = true;
3953         final boolean isRegSel = isRegionSelection;
3954         final AlignFrame af = this;
3955         final String source = ptypes[t];
3956         JMenuItem xtype = new JMenuItem(ptypes[t]);
3957         xtype.addActionListener(new ActionListener()
3958         {
3959
3960           public void actionPerformed(ActionEvent e)
3961           {
3962             // TODO: new thread for this call with vis-delay
3963             af.showProductsFor(af.viewport.getSequenceSelection(), ds,
3964                     isRegSel, dna, source);
3965           }
3966
3967         });
3968         showProducts.add(xtype);
3969       }
3970       showProducts.setVisible(showp);
3971       showProducts.setEnabled(showp);
3972     } catch (Exception e)
3973     {
3974       jalview.bin.Cache.log
3975               .warn(
3976                       "canTranslate threw an exception - please report to help@jalview.org",
3977                       e);
3978       return false;
3979     }
3980     return showp;
3981   }
3982
3983   protected void showProductsFor(SequenceI[] sel, Alignment ds,
3984           boolean isRegSel, boolean dna, String source)
3985   {
3986     final boolean fisRegSel = isRegSel;
3987     final boolean fdna = dna;
3988     final String fsrc = source;
3989     final AlignFrame ths = this;
3990     final SequenceI[] fsel = sel;
3991     Runnable foo = new Runnable()
3992     {
3993
3994       public void run()
3995       {
3996         final long sttime = System.currentTimeMillis();
3997         ths.setProgressBar("Searching for sequences from " + fsrc, sttime);
3998         try
3999         {
4000           Alignment ds = ths.getViewport().alignment.getDataset(); // update
4001           // our local
4002           // dataset
4003           // reference
4004           Alignment prods = CrossRef
4005                   .findXrefSequences(fsel, fdna, fsrc, ds);
4006           if (prods != null)
4007           {
4008             SequenceI[] sprods = new SequenceI[prods.getHeight()];
4009             for (int s = 0; s < sprods.length; s++)
4010             {
4011               sprods[s] = (prods.getSequenceAt(s)).deriveSequence();
4012               if (ds.getSequences() == null
4013                       || !ds.getSequences().contains(
4014                               sprods[s].getDatasetSequence()))
4015                 ds.addSequence(sprods[s].getDatasetSequence());
4016               sprods[s].updatePDBIds();
4017             }
4018             Alignment al = new Alignment(sprods);
4019             AlignedCodonFrame[] cf = prods.getCodonFrames();
4020             al.setDataset(ds);
4021             for (int s = 0; cf != null && s < cf.length; s++)
4022             {
4023               al.addCodonFrame(cf[s]);
4024               cf[s] = null;
4025             }
4026             AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH,
4027                     DEFAULT_HEIGHT);
4028             String newtitle = "" + ((fdna) ? "Proteins " : "Nucleotides ")
4029                     + " for " + ((fisRegSel) ? "selected region of " : "")
4030                     + getTitle();
4031             Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,
4032                     DEFAULT_HEIGHT);
4033           }
4034           else
4035           {
4036             System.err.println("No Sequences generated for xRef type "
4037                     + fsrc);
4038           }
4039         } catch (Exception e)
4040         {
4041           jalview.bin.Cache.log.error(
4042                   "Exception when finding crossreferences", e);
4043         } catch (OutOfMemoryError e)
4044         {
4045           new OOMWarning("whilst fetching crossreferences", e);
4046         } catch (Error e)
4047         {
4048           jalview.bin.Cache.log.error("Error when finding crossreferences",
4049                   e);
4050         }
4051         ths.setProgressBar("Finished searching for sequences from " + fsrc,
4052                 sttime);
4053       }
4054
4055     };
4056     Thread frunner = new Thread(foo);
4057     frunner.start();
4058   }
4059
4060   public boolean canShowTranslationProducts(SequenceI[] selection,
4061           AlignmentI alignment)
4062   {
4063     // old way
4064     try
4065     {
4066       return (jalview.analysis.Dna.canTranslate(selection, viewport
4067               .getViewAsVisibleContigs(true)));
4068     } catch (Exception e)
4069     {
4070       jalview.bin.Cache.log
4071               .warn(
4072                       "canTranslate threw an exception - please report to help@jalview.org",
4073                       e);
4074       return false;
4075     }
4076   }
4077
4078   public void showProducts_actionPerformed(ActionEvent e)
4079   {
4080     // /////////////////////////////
4081     // Collect Data to be translated/transferred
4082
4083     SequenceI[] selection = viewport.getSequenceSelection();
4084     AlignmentI al = null;
4085     try
4086     {
4087       al = jalview.analysis.Dna.CdnaTranslate(selection, viewport
4088               .getViewAsVisibleContigs(true), viewport.getGapCharacter(),
4089               viewport.getAlignment().getDataset());
4090     } catch (Exception ex)
4091     {
4092       al = null;
4093       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4094     }
4095     if (al == null)
4096     {
4097       JOptionPane
4098               .showMessageDialog(
4099                       Desktop.desktop,
4100                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4101                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4102     }
4103     else
4104     {
4105       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4106       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4107               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4108     }
4109   }
4110
4111   public void showTranslation_actionPerformed(ActionEvent e)
4112   {
4113     // /////////////////////////////
4114     // Collect Data to be translated/transferred
4115
4116     SequenceI[] selection = viewport.getSequenceSelection();
4117     String[] seqstring = viewport.getViewAsString(true);
4118     AlignmentI al = null;
4119     try
4120     {
4121       al = jalview.analysis.Dna.CdnaTranslate(selection, seqstring,
4122               viewport.getViewAsVisibleContigs(true), viewport
4123                       .getGapCharacter(), viewport.alignment
4124                       .getAlignmentAnnotation(), viewport.alignment
4125                       .getWidth(), viewport.getAlignment().getDataset());
4126     } catch (Exception ex)
4127     {
4128       al = null;
4129       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4130     }
4131     if (al == null)
4132     {
4133       JOptionPane
4134               .showMessageDialog(
4135                       Desktop.desktop,
4136                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4137                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4138     }
4139     else
4140     {
4141       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4142       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4143               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4144     }
4145   }
4146
4147   /**
4148    * Try to load a features file onto the alignment.
4149    * 
4150    * @param file
4151    *          contents or path to retrieve file
4152    * @param type
4153    *          access mode of file (see jalview.io.AlignFile)
4154    * @return true if features file was parsed corectly.
4155    */
4156   public boolean parseFeaturesFile(String file, String type)
4157   {
4158     boolean featuresFile = false;
4159     try
4160     {
4161       featuresFile = new FeaturesFile(file, type).parse(viewport.alignment
4162               .getDataset(), alignPanel.seqPanel.seqCanvas
4163               .getFeatureRenderer().featureColours, false);
4164     } catch (Exception ex)
4165     {
4166       ex.printStackTrace();
4167     }
4168
4169     if (featuresFile)
4170     {
4171       viewport.showSequenceFeatures = true;
4172       showSeqFeatures.setSelected(true);
4173       if (alignPanel.seqPanel.seqCanvas.fr != null)
4174       {
4175         // update the min/max ranges where necessary
4176         alignPanel.seqPanel.seqCanvas.fr.findAllFeatures(true);
4177       }
4178       if (featureSettings != null)
4179       {
4180         featureSettings.setTableData();
4181       }
4182       alignPanel.paintAlignment(true);
4183     }
4184
4185     return featuresFile;
4186   }
4187
4188   public void dragEnter(DropTargetDragEvent evt)
4189   {
4190   }
4191
4192   public void dragExit(DropTargetEvent evt)
4193   {
4194   }
4195
4196   public void dragOver(DropTargetDragEvent evt)
4197   {
4198   }
4199
4200   public void dropActionChanged(DropTargetDragEvent evt)
4201   {
4202   }
4203
4204   public void drop(DropTargetDropEvent evt)
4205   {
4206     Transferable t = evt.getTransferable();
4207     java.util.List files = null;
4208
4209     try
4210     {
4211       DataFlavor uriListFlavor = new DataFlavor(
4212               "text/uri-list;class=java.lang.String");
4213       if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
4214       {
4215         // Works on Windows and MacOSX
4216         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4217         files = (java.util.List) t
4218                 .getTransferData(DataFlavor.javaFileListFlavor);
4219       }
4220       else if (t.isDataFlavorSupported(uriListFlavor))
4221       {
4222         // This is used by Unix drag system
4223         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4224         String data = (String) t.getTransferData(uriListFlavor);
4225         files = new java.util.ArrayList(1);
4226         for (java.util.StringTokenizer st = new java.util.StringTokenizer(
4227                 data, "\r\n"); st.hasMoreTokens();)
4228         {
4229           String s = st.nextToken();
4230           if (s.startsWith("#"))
4231           {
4232             // the line is a comment (as per the RFC 2483)
4233             continue;
4234           }
4235
4236           java.net.URI uri = new java.net.URI(s);
4237           // check to see if we can handle this kind of URI
4238           if (uri.getScheme().toLowerCase().startsWith("http"))
4239           {
4240             files.add(uri.toString());
4241           }
4242           else
4243           {
4244             // otherwise preserve old behaviour: catch all for file objects
4245             java.io.File file = new java.io.File(uri);
4246             files.add(file.toString());
4247           }
4248         }
4249       }
4250     } catch (Exception e)
4251     {
4252       e.printStackTrace();
4253     }
4254     if (files != null)
4255     {
4256       try
4257       {
4258
4259         for (int i = 0; i < files.size(); i++)
4260         {
4261           loadJalviewDataFile(files.get(i).toString());
4262         }
4263       } catch (Exception ex)
4264       {
4265         ex.printStackTrace();
4266       }
4267     }
4268   }
4269
4270   /**
4271    * Attempt to load a "dropped" file or URL string: First by testing whether
4272    * it's and Annotation file, then a JNet file, and finally a features file. If
4273    * all are false then the user may have dropped an alignment file onto this
4274    * AlignFrame.
4275    * 
4276    * @param file
4277    *          either a filename or a URL string.
4278    */
4279   public void loadJalviewDataFile(String file)
4280   {
4281     try
4282     {
4283       String protocol = jalview.io.FormatAdapter.FILE;
4284       String f = file.toLowerCase();
4285       if (f.indexOf("http:") == 0 || f.indexOf("https:") == 0
4286               || f.indexOf("file:") == 0)
4287       {
4288         protocol = jalview.io.FormatAdapter.URL;
4289       }
4290
4291       boolean isAnnotation = new AnnotationFile().readAnnotationFile(
4292               viewport.alignment, file, protocol);
4293
4294       if (!isAnnotation)
4295       {
4296         // try to see if its a JNet 'concise' style annotation file *before* we
4297         // try to parse it as a features file
4298         String format = new IdentifyFile().Identify(file, protocol);
4299         if (format.equalsIgnoreCase("JnetFile"))
4300         {
4301           jalview.io.JPredFile predictions = new jalview.io.JPredFile(file,
4302                   protocol);
4303           new JnetAnnotationMaker().add_annotation(predictions, viewport
4304                   .getAlignment(), 0, false);
4305           isAnnotation = true;
4306         }
4307         else
4308         {
4309           // try to parse it as a features file
4310           boolean isGroupsFile = parseFeaturesFile(file, protocol);
4311           // if it wasn't a features file then we just treat it as a general
4312           // alignment file to load into the current view.
4313           if (!isGroupsFile)
4314           {
4315             new FileLoader().LoadFile(viewport, file, protocol, format);
4316           }
4317           else
4318           {
4319             alignPanel.paintAlignment(true);
4320           }
4321         }
4322       }
4323       if (isAnnotation)
4324       {
4325
4326         alignPanel.adjustAnnotationHeight();
4327         viewport.updateSequenceIdColours();
4328         buildSortByAnnotationScoresMenu();
4329         alignPanel.paintAlignment(true);
4330       }
4331     } catch (Exception ex)
4332     {
4333       ex.printStackTrace();
4334     }
4335   }
4336
4337   public void tabSelectionChanged(int index)
4338   {
4339     if (index > -1)
4340     {
4341       alignPanel = (AlignmentPanel) alignPanels.elementAt(index);
4342       viewport = alignPanel.av;
4343       setMenusFromViewport(viewport);
4344     }
4345   }
4346
4347   public void tabbedPane_mousePressed(MouseEvent e)
4348   {
4349     if (SwingUtilities.isRightMouseButton(e))
4350     {
4351       String reply = JOptionPane.showInternalInputDialog(this,
4352               "Enter View Name", "Edit View Name",
4353               JOptionPane.QUESTION_MESSAGE);
4354
4355       if (reply != null)
4356       {
4357         viewport.viewName = reply;
4358         tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
4359       }
4360     }
4361   }
4362
4363   public AlignViewport getCurrentView()
4364   {
4365     return viewport;
4366   }
4367
4368   /**
4369    * Open the dialog for regex description parsing.
4370    */
4371   protected void extractScores_actionPerformed(ActionEvent e)
4372   {
4373     ParseProperties pp = new jalview.analysis.ParseProperties(
4374             viewport.alignment);
4375     // TODO: verify regex and introduce GUI dialog for version 2.5
4376     // if (pp.getScoresFromDescription("col", "score column ",
4377     // "\\W*([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)",
4378     // true)>0)
4379     if (pp.getScoresFromDescription("description column",
4380             "score in description column ", "\\W*([-+eE0-9.]+)", true) > 0)
4381     {
4382       buildSortByAnnotationScoresMenu();
4383     }
4384   }
4385
4386   /*
4387    * (non-Javadoc)
4388    * 
4389    * @see
4390    * jalview.jbgui.GAlignFrame#showDbRefs_actionPerformed(java.awt.event.ActionEvent
4391    * )
4392    */
4393   protected void showDbRefs_actionPerformed(ActionEvent e)
4394   {
4395     viewport.setShowDbRefs(showDbRefsMenuitem.isSelected());
4396   }
4397
4398   /*
4399    * (non-Javadoc)
4400    * 
4401    * @seejalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event.
4402    * ActionEvent)
4403    */
4404   protected void showNpFeats_actionPerformed(ActionEvent e)
4405   {
4406     viewport.setShowNpFeats(showNpFeatsMenuitem.isSelected());
4407   }
4408
4409   /**
4410    * find the viewport amongst the tabs in this alignment frame and close that
4411    * tab
4412    * 
4413    * @param av
4414    */
4415   public boolean closeView(AlignViewport av)
4416   {
4417     if (viewport == av)
4418     {
4419       this.closeMenuItem_actionPerformed(false);
4420       return true;
4421     }
4422     Component[] comp = tabbedPane.getComponents();
4423     for (int i = 0; comp != null && i < comp.length; i++)
4424     {
4425       if (comp[i] instanceof AlignmentPanel)
4426       {
4427         if (((AlignmentPanel) comp[i]).av == av)
4428         {
4429           // close the view.
4430           closeView((AlignmentPanel) comp[i]);
4431           return true;
4432         }
4433       }
4434     }
4435     return false;
4436   }
4437
4438   protected void build_fetchdbmenu(JMenu webService)
4439   {
4440     // Temporary hack - DBRef Fetcher always top level ws entry.
4441     // TODO We probably want to store a sequence database checklist in
4442     // preferences and have checkboxes.. rather than individual sources selected
4443     // here
4444     JMenu rfetch = new JMenu("Fetch DB References");
4445     rfetch
4446             .setToolTipText("Retrieve and parse sequence database records for the alignment or the currently selected sequences");
4447     webService.add(rfetch);
4448
4449     JMenuItem fetchr = new JMenuItem("Standard Databases");
4450     fetchr
4451             .setToolTipText("Fetch from EMBL/EMBLCDS or Uniprot/PDB and any selected DAS sources");
4452     fetchr.addActionListener(new ActionListener()
4453     {
4454
4455       public void actionPerformed(ActionEvent e)
4456       {
4457         new Thread(new Runnable()
4458         {
4459
4460           public void run()
4461           {
4462             new jalview.ws.DBRefFetcher(alignPanel.av
4463                     .getSequenceSelection(), alignPanel.alignFrame)
4464                     .fetchDBRefs(false);
4465           }
4466         }).start();
4467
4468       }
4469
4470     });
4471     rfetch.add(fetchr);
4472     JMenu dfetch = new JMenu();
4473     rfetch.add(dfetch);
4474     jalview.ws.SequenceFetcher sf = SequenceFetcher
4475             .getSequenceFetcherSingleton(this);
4476     String[] otherdb = sf.getOrderedSupportedSources();
4477     // sf.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);
4478     // jalview.util.QuickSort.sort(otherdb, otherdb);
4479     int comp = 0, mcomp = 15;
4480     String mname = null;
4481     if (otherdb != null && otherdb.length > 0)
4482     {
4483       for (int i = 0; i < otherdb.length; i++)
4484       {
4485         String dbname = sf.getSourceProxy(otherdb[i]).getDbName();
4486         if (mname == null)
4487         {
4488           mname = "from '" + dbname + "'";
4489         }
4490         fetchr = new JMenuItem(otherdb[i]);
4491         final String[] dassource = new String[]
4492         { otherdb[i] };
4493         fetchr.addActionListener(new ActionListener()
4494         {
4495
4496           public void actionPerformed(ActionEvent e)
4497           {
4498             new Thread(new Runnable()
4499             {
4500
4501               public void run()
4502               {
4503                 new jalview.ws.DBRefFetcher(alignPanel.av
4504                         .getSequenceSelection(), alignPanel.alignFrame,
4505                         dassource).fetchDBRefs(false);
4506               }
4507             }).start();
4508           }
4509
4510         });
4511         fetchr.setToolTipText("Retrieve from " + dbname);
4512         dfetch.add(fetchr);
4513         if (comp++ == mcomp || i == (otherdb.length - 1))
4514         {
4515           dfetch.setText(mname + " to '" + dbname + "'");
4516           rfetch.add(dfetch);
4517           dfetch = new JMenu();
4518           mname = null;
4519           comp = 0;
4520         }
4521       }
4522     }
4523   }
4524
4525   /**
4526    * Left justify the whole alignment.
4527    */
4528   protected void justifyLeftMenuItem_actionPerformed(ActionEvent e)
4529   {
4530     AlignmentI al = viewport.getAlignment();
4531     al.justify(false);
4532     viewport.firePropertyChange("alignment", null, al);
4533   }
4534
4535   /**
4536    * Right justify the whole alignment.
4537    */
4538   protected void justifyRightMenuItem_actionPerformed(ActionEvent e)
4539   {
4540     AlignmentI al = viewport.getAlignment();
4541     al.justify(true);
4542     viewport.firePropertyChange("alignment", null, al);
4543   }
4544
4545   public void setShowSeqFeatures(boolean b)
4546   {
4547     showSeqFeatures.setSelected(true);
4548     viewport.setShowSequenceFeatures(true);
4549   }
4550
4551   /*
4552    * (non-Javadoc)
4553    * 
4554    * @see
4555    * jalview.jbgui.GAlignFrame#showUnconservedMenuItem_actionPerformed(java.
4556    * awt.event.ActionEvent)
4557    */
4558   protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)
4559   {
4560     viewport.setShowUnconserved(showNonconservedMenuItem.getState());
4561     alignPanel.paintAlignment(true);
4562   }
4563
4564   /*
4565    * (non-Javadoc)
4566    * 
4567    * @see
4568    * jalview.jbgui.GAlignFrame#showGroupConsensus_actionPerformed(java.awt.event
4569    * .ActionEvent)
4570    */
4571   protected void showGroupConsensus_actionPerformed(ActionEvent e)
4572   {
4573     viewport.setShowGroupConsensus(showGroupConsensus.getState());
4574     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4575
4576   }
4577
4578   /*
4579    * (non-Javadoc)
4580    * 
4581    * @see
4582    * jalview.jbgui.GAlignFrame#showGroupConservation_actionPerformed(java.awt
4583    * .event.ActionEvent)
4584    */
4585   protected void showGroupConservation_actionPerformed(ActionEvent e)
4586   {
4587     viewport.setShowGroupConservation(showGroupConservation.getState());
4588     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4589   }
4590
4591   /*
4592    * (non-Javadoc)
4593    * 
4594    * @see
4595    * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt
4596    * .event.ActionEvent)
4597    */
4598   protected void showConsensusHistogram_actionPerformed(ActionEvent e)
4599   {
4600     viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
4601     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4602   }
4603
4604   /*
4605    * (non-Javadoc)
4606    * 
4607    * @see
4608    * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt
4609    * .event.ActionEvent)
4610    */
4611   protected void showSequenceLogo_actionPerformed(ActionEvent e)
4612   {
4613     viewport.setShowSequenceLogo(showSequenceLogo.getState());
4614     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4615   }
4616
4617   protected void applyAutoAnnotationSettings_actionPerformed(ActionEvent e)
4618   {
4619     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4620   }
4621
4622   /*
4623    * (non-Javadoc)
4624    * 
4625    * @see
4626    * jalview.jbgui.GAlignFrame#makeGrpsFromSelection_actionPerformed(java.awt
4627    * .event.ActionEvent)
4628    */
4629   protected void makeGrpsFromSelection_actionPerformed(ActionEvent e)
4630   {
4631     if (viewport.getSelectionGroup() != null)
4632     {
4633       SequenceGroup[] gps = jalview.analysis.Grouping.makeGroupsFrom(
4634               viewport.getSequenceSelection(), viewport.getAlignmentView(
4635                       true).getSequenceStrings(viewport.getGapCharacter()),
4636               viewport.alignment.getGroups());
4637       viewport.alignment.deleteAllGroups();
4638       viewport.sequenceColours = null;
4639       viewport.setSelectionGroup(null);
4640       // set view properties for each group
4641       for (int g = 0; g < gps.length; g++)
4642       {
4643         gps[g].setShowNonconserved(viewport.getShowUnconserved());
4644         gps[g].setshowSequenceLogo(viewport.isShowSequenceLogo());
4645         viewport.alignment.addGroup(gps[g]);
4646         Color col = new Color((int) (Math.random() * 255), (int) (Math
4647                 .random() * 255), (int) (Math.random() * 255));
4648         col = col.brighter();
4649         for (Enumeration sq = gps[g].getSequences(null).elements(); sq
4650                 .hasMoreElements(); viewport.setSequenceColour(
4651                 (SequenceI) sq.nextElement(), col))
4652           ;
4653       }
4654       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
4655       alignPanel.updateAnnotation();
4656       alignPanel.paintAlignment(true);
4657     }
4658   }
4659 }
4660
4661 class PrintThread extends Thread
4662 {
4663   AlignmentPanel ap;
4664
4665   public PrintThread(AlignmentPanel ap)
4666   {
4667     this.ap = ap;
4668   }
4669
4670   static PageFormat pf;
4671
4672   public void run()
4673   {
4674     PrinterJob printJob = PrinterJob.getPrinterJob();
4675
4676     if (pf != null)
4677     {
4678       printJob.setPrintable(ap, pf);
4679     }
4680     else
4681     {
4682       printJob.setPrintable(ap);
4683     }
4684
4685     if (printJob.printDialog())
4686     {
4687       try
4688       {
4689         printJob.print();
4690       } catch (Exception PrintException)
4691       {
4692         PrintException.printStackTrace();
4693       }
4694     }
4695   }
4696 }