jalview 2.5 release banner
[jalview.git] / src / jalview / gui / AlignFrame.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5)
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     showUnconservedMenuItem.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();
1534       for (int i = 0; i < viewport.getColumnSelection().getHiddenColumns()
1535               .size(); i++)
1536       {
1537         int[] region = (int[]) viewport.getColumnSelection()
1538                 .getHiddenColumns().elementAt(i);
1539
1540         hiddenColumns.addElement(new int[]
1541         { region[0] - hiddenOffset, region[1] - hiddenOffset });
1542       }
1543     }
1544
1545     Desktop.jalviewClipboard = new Object[]
1546     { seqs, viewport.alignment.getDataset(), hiddenColumns };
1547     statusBar.setText("Copied " + seqs.length + " sequences to clipboard.");
1548   }
1549
1550   /**
1551    * DOCUMENT ME!
1552    * 
1553    * @param e
1554    *          DOCUMENT ME!
1555    */
1556   protected void pasteNew_actionPerformed(ActionEvent e)
1557   {
1558     paste(true);
1559   }
1560
1561   /**
1562    * DOCUMENT ME!
1563    * 
1564    * @param e
1565    *          DOCUMENT ME!
1566    */
1567   protected void pasteThis_actionPerformed(ActionEvent e)
1568   {
1569     paste(false);
1570   }
1571
1572   /**
1573    * Paste contents of Jalview clipboard
1574    * 
1575    * @param newAlignment
1576    *          true to paste to a new alignment, otherwise add to this.
1577    */
1578   void paste(boolean newAlignment)
1579   {
1580     boolean externalPaste = true;
1581     try
1582     {
1583       Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
1584       Transferable contents = c.getContents(this);
1585
1586       if (contents == null)
1587       {
1588         return;
1589       }
1590
1591       String str, format;
1592       try
1593       {
1594         str = (String) contents.getTransferData(DataFlavor.stringFlavor);
1595         if (str.length() < 1)
1596         {
1597           return;
1598         }
1599
1600         format = new IdentifyFile().Identify(str, "Paste");
1601
1602       } catch (OutOfMemoryError er)
1603       {
1604         new OOMWarning("Out of memory pasting sequences!!", er);
1605         return;
1606       }
1607
1608       SequenceI[] sequences;
1609       boolean annotationAdded = false;
1610       AlignmentI alignment = null;
1611
1612       if (Desktop.jalviewClipboard != null)
1613       {
1614         // The clipboard was filled from within Jalview, we must use the
1615         // sequences
1616         // And dataset from the copied alignment
1617         SequenceI[] newseq = (SequenceI[]) Desktop.jalviewClipboard[0];
1618         // be doubly sure that we create *new* sequence objects.
1619         sequences = new SequenceI[newseq.length];
1620         for (int i = 0; i < newseq.length; i++)
1621         {
1622           sequences[i] = new Sequence(newseq[i]);
1623         }
1624         alignment = new Alignment(sequences);
1625         externalPaste = false;
1626       }
1627       else
1628       {
1629         // parse the clipboard as an alignment.
1630         alignment = new FormatAdapter().readFile(str, "Paste", format);
1631         sequences = alignment.getSequencesArray();
1632       }
1633
1634       int alwidth = 0;
1635
1636       if (newAlignment)
1637       {
1638
1639         if (Desktop.jalviewClipboard != null)
1640         {
1641           // dataset is inherited
1642           alignment.setDataset((Alignment) Desktop.jalviewClipboard[1]);
1643         }
1644         else
1645         {
1646           // new dataset is constructed
1647           alignment.setDataset(null);
1648         }
1649         alwidth = alignment.getWidth() + 1;
1650       }
1651       else
1652       {
1653         AlignmentI pastedal = alignment; // preserve pasted alignment object
1654         // Add pasted sequences and dataset into existing alignment.
1655         alignment = viewport.getAlignment();
1656         alwidth = alignment.getWidth() + 1;
1657         // decide if we need to import sequences from an existing dataset
1658         boolean importDs = Desktop.jalviewClipboard != null
1659                 && Desktop.jalviewClipboard[1] != alignment.getDataset();
1660         // importDs==true instructs us to copy over new dataset sequences from
1661         // an existing alignment
1662         Vector newDs = (importDs) ? new Vector() : null; // used to create
1663         // minimum dataset set
1664
1665         for (int i = 0; i < sequences.length; i++)
1666         {
1667           if (importDs)
1668           {
1669             newDs.addElement(null);
1670           }
1671           SequenceI ds = sequences[i].getDatasetSequence(); // null for a simple
1672           // paste
1673           if (importDs && ds != null)
1674           {
1675             if (!newDs.contains(ds))
1676             {
1677               newDs.setElementAt(ds, i);
1678               ds = new Sequence(ds);
1679               // update with new dataset sequence
1680               sequences[i].setDatasetSequence(ds);
1681             }
1682             else
1683             {
1684               ds = sequences[newDs.indexOf(ds)].getDatasetSequence();
1685             }
1686           }
1687           else
1688           {
1689             // copy and derive new dataset sequence
1690             sequences[i] = sequences[i].deriveSequence();
1691             alignment.getDataset().addSequence(
1692                     sequences[i].getDatasetSequence());
1693             // TODO: avoid creation of duplicate dataset sequences with a
1694             // 'contains' method using SequenceI.equals()/SequenceI.contains()
1695           }
1696           alignment.addSequence(sequences[i]); // merges dataset
1697         }
1698         if (newDs != null)
1699         {
1700           newDs.clear(); // tidy up
1701         }
1702         if (pastedal.getAlignmentAnnotation() != null)
1703         {
1704           // Add any annotation attached to alignment.
1705           AlignmentAnnotation[] alann = pastedal.getAlignmentAnnotation();
1706           for (int i = 0; i < alann.length; i++)
1707           {
1708             annotationAdded = true;
1709             if (alann[i].sequenceRef == null && !alann[i].autoCalculated)
1710             {
1711               AlignmentAnnotation newann = new AlignmentAnnotation(alann[i]);
1712               newann.padAnnotation(alwidth);
1713               alignment.addAnnotation(newann);
1714             }
1715           }
1716         }
1717       }
1718       if (!newAlignment)
1719       {
1720         // /////
1721         // ADD HISTORY ITEM
1722         //
1723         addHistoryItem(new EditCommand("Add sequences", EditCommand.PASTE,
1724                 sequences, 0, alignment.getWidth(), alignment));
1725       }
1726       // Add any annotations attached to sequences
1727       for (int i = 0; i < sequences.length; i++)
1728       {
1729         if (sequences[i].getAnnotation() != null)
1730         {
1731           for (int a = 0; a < sequences[i].getAnnotation().length; a++)
1732           {
1733             annotationAdded = true;
1734             sequences[i].getAnnotation()[a].adjustForAlignment();
1735             sequences[i].getAnnotation()[a].padAnnotation(alwidth);
1736             alignment.addAnnotation(sequences[i].getAnnotation()[a]); // annotation
1737             // was
1738             // duplicated
1739             // earlier
1740             alignment
1741                     .setAnnotationIndex(sequences[i].getAnnotation()[a], a);
1742           }
1743         }
1744       }
1745       if (!newAlignment)
1746       {
1747
1748         // propagate alignment changed.
1749         viewport.setEndSeq(alignment.getHeight());
1750         if (annotationAdded)
1751         {
1752           // Duplicate sequence annotation in all views.
1753           AlignmentI[] alview = this.getViewAlignments();
1754           for (int i = 0; i < sequences.length; i++)
1755           {
1756             AlignmentAnnotation sann[] = sequences[i].getAnnotation();
1757             if (sann == null)
1758               continue;
1759             for (int avnum = 0; avnum < alview.length; avnum++)
1760             {
1761               if (alview[avnum] != alignment)
1762               {
1763                 // duplicate in a view other than the one with input focus
1764                 int avwidth = alview[avnum].getWidth() + 1;
1765                 // this relies on sann being preserved after we
1766                 // modify the sequence's annotation array for each duplication
1767                 for (int a = 0; a < sann.length; a++)
1768                 {
1769                   AlignmentAnnotation newann = new AlignmentAnnotation(
1770                           sann[a]);
1771                   sequences[i].addAlignmentAnnotation(newann);
1772                   newann.padAnnotation(avwidth);
1773                   alview[avnum].addAnnotation(newann); // annotation was
1774                   // duplicated earlier
1775                   alview[avnum].setAnnotationIndex(newann, a);
1776                 }
1777               }
1778             }
1779           }
1780           buildSortByAnnotationScoresMenu();
1781         }
1782         viewport.firePropertyChange("alignment", null, alignment
1783                 .getSequences());
1784
1785       }
1786       else
1787       {
1788         AlignFrame af = new AlignFrame(alignment, DEFAULT_WIDTH,
1789                 DEFAULT_HEIGHT);
1790         String newtitle = new String("Copied sequences");
1791
1792         if (Desktop.jalviewClipboard != null
1793                 && Desktop.jalviewClipboard[2] != null)
1794         {
1795           Vector hc = (Vector) Desktop.jalviewClipboard[2];
1796           for (int i = 0; i < hc.size(); i++)
1797           {
1798             int[] region = (int[]) hc.elementAt(i);
1799             af.viewport.hideColumns(region[0], region[1]);
1800           }
1801         }
1802
1803         // >>>This is a fix for the moment, until a better solution is
1804         // found!!<<<
1805         af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer()
1806                 .transferSettings(
1807                         alignPanel.seqPanel.seqCanvas.getFeatureRenderer());
1808
1809         // TODO: maintain provenance of an alignment, rather than just make the
1810         // title a concatenation of operations.
1811         if (!externalPaste)
1812         {
1813           if (title.startsWith("Copied sequences"))
1814           {
1815             newtitle = title;
1816           }
1817           else
1818           {
1819             newtitle = newtitle.concat("- from " + title);
1820           }
1821         }
1822         else
1823         {
1824           newtitle = new String("Pasted sequences");
1825         }
1826
1827         Desktop.addInternalFrame(af, newtitle, DEFAULT_WIDTH,
1828                 DEFAULT_HEIGHT);
1829
1830       }
1831
1832     } catch (Exception ex)
1833     {
1834       ex.printStackTrace();
1835       System.out.println("Exception whilst pasting: " + ex);
1836       // could be anything being pasted in here
1837     }
1838
1839   }
1840
1841   /**
1842    * DOCUMENT ME!
1843    * 
1844    * @param e
1845    *          DOCUMENT ME!
1846    */
1847   protected void cut_actionPerformed(ActionEvent e)
1848   {
1849     copy_actionPerformed(null);
1850     delete_actionPerformed(null);
1851   }
1852
1853   /**
1854    * DOCUMENT ME!
1855    * 
1856    * @param e
1857    *          DOCUMENT ME!
1858    */
1859   protected void delete_actionPerformed(ActionEvent evt)
1860   {
1861
1862     SequenceGroup sg = viewport.getSelectionGroup();
1863     if (sg == null)
1864     {
1865       return;
1866     }
1867
1868     Vector seqs = new Vector();
1869     SequenceI seq;
1870     for (int i = 0; i < sg.getSize(); i++)
1871     {
1872       seq = sg.getSequenceAt(i);
1873       seqs.addElement(seq);
1874     }
1875
1876     // If the cut affects all sequences, remove highlighted columns
1877     if (sg.getSize() == viewport.alignment.getHeight())
1878     {
1879       viewport.getColumnSelection().removeElements(sg.getStartRes(),
1880               sg.getEndRes() + 1);
1881     }
1882
1883     SequenceI[] cut = new SequenceI[seqs.size()];
1884     for (int i = 0; i < seqs.size(); i++)
1885     {
1886       cut[i] = (SequenceI) seqs.elementAt(i);
1887     }
1888
1889     /*
1890      * //ADD HISTORY ITEM
1891      */
1892     addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT, cut,
1893             sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
1894             viewport.alignment));
1895
1896     viewport.setSelectionGroup(null);
1897     viewport.sendSelection();
1898     viewport.alignment.deleteGroup(sg);
1899
1900     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
1901             .getSequences());
1902     if (viewport.getAlignment().getHeight() < 1)
1903     {
1904       try
1905       {
1906         this.setClosed(true);
1907       } catch (Exception ex)
1908       {
1909       }
1910     }
1911   }
1912
1913   /**
1914    * DOCUMENT ME!
1915    * 
1916    * @param e
1917    *          DOCUMENT ME!
1918    */
1919   protected void deleteGroups_actionPerformed(ActionEvent e)
1920   {
1921     viewport.alignment.deleteAllGroups();
1922     viewport.sequenceColours = null;
1923     viewport.setSelectionGroup(null);
1924     PaintRefresher.Refresh(this, viewport.getSequenceSetId());
1925     alignPanel.updateAnnotation();
1926     alignPanel.paintAlignment(true);
1927   }
1928
1929   /**
1930    * DOCUMENT ME!
1931    * 
1932    * @param e
1933    *          DOCUMENT ME!
1934    */
1935   public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)
1936   {
1937     SequenceGroup sg = new SequenceGroup();
1938
1939     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
1940     {
1941       sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
1942     }
1943
1944     sg.setEndRes(viewport.alignment.getWidth() - 1);
1945     viewport.setSelectionGroup(sg);
1946     viewport.sendSelection();
1947     alignPanel.paintAlignment(true);
1948     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
1949   }
1950
1951   /**
1952    * DOCUMENT ME!
1953    * 
1954    * @param e
1955    *          DOCUMENT ME!
1956    */
1957   public void deselectAllSequenceMenuItem_actionPerformed(ActionEvent e)
1958   {
1959     if (viewport.cursorMode)
1960     {
1961       alignPanel.seqPanel.keyboardNo1 = null;
1962       alignPanel.seqPanel.keyboardNo2 = null;
1963     }
1964     viewport.setSelectionGroup(null);
1965     viewport.getColumnSelection().clear();
1966     viewport.setSelectionGroup(null);
1967     alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);
1968     alignPanel.idPanel.idCanvas.searchResults = null;
1969     alignPanel.paintAlignment(true);
1970     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
1971   }
1972
1973   /**
1974    * DOCUMENT ME!
1975    * 
1976    * @param e
1977    *          DOCUMENT ME!
1978    */
1979   public void invertSequenceMenuItem_actionPerformed(ActionEvent e)
1980   {
1981     SequenceGroup sg = viewport.getSelectionGroup();
1982
1983     if (sg == null)
1984     {
1985       selectAllSequenceMenuItem_actionPerformed(null);
1986
1987       return;
1988     }
1989
1990     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
1991     {
1992       sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
1993     }
1994
1995     alignPanel.paintAlignment(true);
1996     viewport.sendSelection();
1997     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
1998   }
1999
2000   public void invertColSel_actionPerformed(ActionEvent e)
2001   {
2002     viewport.invertColumnSelection();
2003     alignPanel.paintAlignment(true);
2004   }
2005
2006   /**
2007    * DOCUMENT ME!
2008    * 
2009    * @param e
2010    *          DOCUMENT ME!
2011    */
2012   public void remove2LeftMenuItem_actionPerformed(ActionEvent e)
2013   {
2014     trimAlignment(true);
2015   }
2016
2017   /**
2018    * DOCUMENT ME!
2019    * 
2020    * @param e
2021    *          DOCUMENT ME!
2022    */
2023   public void remove2RightMenuItem_actionPerformed(ActionEvent e)
2024   {
2025     trimAlignment(false);
2026   }
2027
2028   void trimAlignment(boolean trimLeft)
2029   {
2030     ColumnSelection colSel = viewport.getColumnSelection();
2031     int column;
2032
2033     if (colSel.size() > 0)
2034     {
2035       if (trimLeft)
2036       {
2037         column = colSel.getMin();
2038       }
2039       else
2040       {
2041         column = colSel.getMax();
2042       }
2043
2044       SequenceI[] seqs;
2045       if (viewport.getSelectionGroup() != null)
2046       {
2047         seqs = viewport.getSelectionGroup().getSequencesAsArray(
2048                 viewport.hiddenRepSequences);
2049       }
2050       else
2051       {
2052         seqs = viewport.alignment.getSequencesArray();
2053       }
2054
2055       TrimRegionCommand trimRegion;
2056       if (trimLeft)
2057       {
2058         trimRegion = new TrimRegionCommand("Remove Left",
2059                 TrimRegionCommand.TRIM_LEFT, seqs, column,
2060                 viewport.alignment, viewport.colSel,
2061                 viewport.selectionGroup);
2062         viewport.setStartRes(0);
2063       }
2064       else
2065       {
2066         trimRegion = new TrimRegionCommand("Remove Right",
2067                 TrimRegionCommand.TRIM_RIGHT, seqs, column,
2068                 viewport.alignment, viewport.colSel,
2069                 viewport.selectionGroup);
2070       }
2071
2072       statusBar.setText("Removed " + trimRegion.getSize() + " columns.");
2073
2074       addHistoryItem(trimRegion);
2075
2076       Vector groups = viewport.alignment.getGroups();
2077
2078       for (int i = 0; i < groups.size(); i++)
2079       {
2080         SequenceGroup sg = (SequenceGroup) groups.get(i);
2081
2082         if ((trimLeft && !sg.adjustForRemoveLeft(column))
2083                 || (!trimLeft && !sg.adjustForRemoveRight(column)))
2084         {
2085           viewport.alignment.deleteGroup(sg);
2086         }
2087       }
2088
2089       viewport.firePropertyChange("alignment", null, viewport
2090               .getAlignment().getSequences());
2091     }
2092   }
2093
2094   /**
2095    * DOCUMENT ME!
2096    * 
2097    * @param e
2098    *          DOCUMENT ME!
2099    */
2100   public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e)
2101   {
2102     int start = 0, end = viewport.alignment.getWidth() - 1;
2103
2104     SequenceI[] seqs;
2105     if (viewport.getSelectionGroup() != null)
2106     {
2107       seqs = viewport.getSelectionGroup().getSequencesAsArray(
2108               viewport.hiddenRepSequences);
2109       start = viewport.getSelectionGroup().getStartRes();
2110       end = viewport.getSelectionGroup().getEndRes();
2111     }
2112     else
2113     {
2114       seqs = viewport.alignment.getSequencesArray();
2115     }
2116
2117     RemoveGapColCommand removeGapCols = new RemoveGapColCommand(
2118             "Remove Gapped Columns", seqs, start, end, viewport.alignment);
2119
2120     addHistoryItem(removeGapCols);
2121
2122     statusBar.setText("Removed " + removeGapCols.getSize()
2123             + " empty columns.");
2124
2125     // This is to maintain viewport position on first residue
2126     // of first sequence
2127     SequenceI seq = viewport.alignment.getSequenceAt(0);
2128     int startRes = seq.findPosition(viewport.startRes);
2129     // ShiftList shifts;
2130     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
2131     // edit.alColumnChanges=shifts.getInverse();
2132     // if (viewport.hasHiddenColumns)
2133     // viewport.getColumnSelection().compensateForEdits(shifts);
2134     viewport.setStartRes(seq.findIndex(startRes) - 1);
2135     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2136             .getSequences());
2137
2138   }
2139
2140   /**
2141    * DOCUMENT ME!
2142    * 
2143    * @param e
2144    *          DOCUMENT ME!
2145    */
2146   public void removeAllGapsMenuItem_actionPerformed(ActionEvent e)
2147   {
2148     int start = 0, end = viewport.alignment.getWidth() - 1;
2149
2150     SequenceI[] seqs;
2151     if (viewport.getSelectionGroup() != null)
2152     {
2153       seqs = viewport.getSelectionGroup().getSequencesAsArray(
2154               viewport.hiddenRepSequences);
2155       start = viewport.getSelectionGroup().getStartRes();
2156       end = viewport.getSelectionGroup().getEndRes();
2157     }
2158     else
2159     {
2160       seqs = viewport.alignment.getSequencesArray();
2161     }
2162
2163     // This is to maintain viewport position on first residue
2164     // of first sequence
2165     SequenceI seq = viewport.alignment.getSequenceAt(0);
2166     int startRes = seq.findPosition(viewport.startRes);
2167
2168     addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
2169             viewport.alignment));
2170
2171     viewport.setStartRes(seq.findIndex(startRes) - 1);
2172
2173     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2174             .getSequences());
2175
2176   }
2177
2178   /**
2179    * DOCUMENT ME!
2180    * 
2181    * @param e
2182    *          DOCUMENT ME!
2183    */
2184   public void padGapsMenuitem_actionPerformed(ActionEvent e)
2185   {
2186     viewport.padGaps = padGapsMenuitem.isSelected();
2187     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2188             .getSequences());
2189   }
2190
2191   // else
2192   {
2193     // if (justifySeqs>0)
2194     {
2195       // alignment.justify(justifySeqs!=RIGHT_JUSTIFY);
2196     }
2197   }
2198
2199   // }
2200
2201   /**
2202    * DOCUMENT ME!
2203    * 
2204    * @param e
2205    *          DOCUMENT ME!
2206    */
2207   public void findMenuItem_actionPerformed(ActionEvent e)
2208   {
2209     new Finder();
2210   }
2211
2212   public void newView_actionPerformed(ActionEvent e)
2213   {
2214     AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel,
2215             true);
2216
2217     newap.av.gatherViewsHere = false;
2218
2219     if (viewport.viewName == null)
2220     {
2221       viewport.viewName = "Original";
2222     }
2223
2224     newap.av.historyList = viewport.historyList;
2225     newap.av.redoList = viewport.redoList;
2226
2227     int index = Desktop.getViewCount(viewport.getSequenceSetId());
2228     String newViewName = "View " + index;
2229
2230     Vector comps = (Vector) PaintRefresher.components.get(viewport
2231             .getSequenceSetId());
2232     Vector existingNames = new Vector();
2233     for (int i = 0; i < comps.size(); i++)
2234     {
2235       if (comps.elementAt(i) instanceof AlignmentPanel)
2236       {
2237         AlignmentPanel ap = (AlignmentPanel) comps.elementAt(i);
2238         if (!existingNames.contains(ap.av.viewName))
2239         {
2240           existingNames.addElement(ap.av.viewName);
2241         }
2242       }
2243     }
2244
2245     while (existingNames.contains(newViewName))
2246     {
2247       newViewName = "View " + (++index);
2248     }
2249
2250     newap.av.viewName = newViewName;
2251
2252     addAlignmentPanel(newap, true);
2253
2254     if (alignPanels.size() == 2)
2255     {
2256       viewport.gatherViewsHere = true;
2257     }
2258     tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
2259   }
2260
2261   public void expandViews_actionPerformed(ActionEvent e)
2262   {
2263     Desktop.instance.explodeViews(this);
2264   }
2265
2266   public void gatherViews_actionPerformed(ActionEvent e)
2267   {
2268     Desktop.instance.gatherViews(this);
2269   }
2270
2271   /**
2272    * DOCUMENT ME!
2273    * 
2274    * @param e
2275    *          DOCUMENT ME!
2276    */
2277   public void font_actionPerformed(ActionEvent e)
2278   {
2279     new FontChooser(alignPanel);
2280   }
2281
2282   /**
2283    * DOCUMENT ME!
2284    * 
2285    * @param e
2286    *          DOCUMENT ME!
2287    */
2288   protected void seqLimit_actionPerformed(ActionEvent e)
2289   {
2290     viewport.setShowJVSuffix(seqLimits.isSelected());
2291
2292     alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel
2293             .calculateIdWidth());
2294     alignPanel.paintAlignment(true);
2295   }
2296
2297   public void idRightAlign_actionPerformed(ActionEvent e)
2298   {
2299     viewport.rightAlignIds = idRightAlign.isSelected();
2300     alignPanel.paintAlignment(true);
2301   }
2302
2303   public void centreColumnLabels_actionPerformed(ActionEvent e)
2304   {
2305     viewport.centreColumnLabels = centreColumnLabelsMenuItem.getState();
2306     alignPanel.paintAlignment(true);
2307   }
2308
2309   /*
2310    * (non-Javadoc)
2311    * 
2312    * @see jalview.jbgui.GAlignFrame#followHighlight_actionPerformed()
2313    */
2314   protected void followHighlight_actionPerformed()
2315   {
2316     if (viewport.followHighlight = this.followHighlightMenuItem.getState())
2317     {
2318       alignPanel.scrollToPosition(
2319               alignPanel.seqPanel.seqCanvas.searchResults, false);
2320     }
2321   }
2322
2323   /**
2324    * DOCUMENT ME!
2325    * 
2326    * @param e
2327    *          DOCUMENT ME!
2328    */
2329   protected void colourTextMenuItem_actionPerformed(ActionEvent e)
2330   {
2331     viewport.setColourText(colourTextMenuItem.isSelected());
2332     alignPanel.paintAlignment(true);
2333   }
2334
2335   /**
2336    * DOCUMENT ME!
2337    * 
2338    * @param e
2339    *          DOCUMENT ME!
2340    */
2341   public void wrapMenuItem_actionPerformed(ActionEvent e)
2342   {
2343     scaleAbove.setVisible(wrapMenuItem.isSelected());
2344     scaleLeft.setVisible(wrapMenuItem.isSelected());
2345     scaleRight.setVisible(wrapMenuItem.isSelected());
2346     viewport.setWrapAlignment(wrapMenuItem.isSelected());
2347     alignPanel.setWrapAlignment(wrapMenuItem.isSelected());
2348   }
2349
2350   public void showAllSeqs_actionPerformed(ActionEvent e)
2351   {
2352     viewport.showAllHiddenSeqs();
2353   }
2354
2355   public void showAllColumns_actionPerformed(ActionEvent e)
2356   {
2357     viewport.showAllHiddenColumns();
2358     repaint();
2359   }
2360
2361   public void hideSelSequences_actionPerformed(ActionEvent e)
2362   {
2363     viewport.hideAllSelectedSeqs();
2364     alignPanel.paintAlignment(true);
2365   }
2366
2367   /**
2368    * called by key handler and the hide all/show all menu items
2369    * 
2370    * @param toggleSeqs
2371    * @param toggleCols
2372    */
2373   private void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
2374   {
2375
2376     boolean hide = false;
2377     SequenceGroup sg = viewport.getSelectionGroup();
2378     if (!toggleSeqs && !toggleCols)
2379     {
2380       // Hide everything by the current selection - this is a hack - we do the
2381       // invert and then hide
2382       // first check that there will be visible columns after the invert.
2383       if ((viewport.colSel != null && viewport.colSel.getSelected() != null && viewport.colSel
2384               .getSelected().size() > 0)
2385               || (sg != null && sg.getSize() > 0 && sg.getStartRes() <= sg
2386                       .getEndRes()))
2387       {
2388         // now invert the sequence set, if required - empty selection implies
2389         // that no hiding is required.
2390         if (sg != null)
2391         {
2392           invertSequenceMenuItem_actionPerformed(null);
2393           sg = viewport.getSelectionGroup();
2394           toggleSeqs = true;
2395
2396         }
2397         viewport.expandColSelection(sg, true);
2398         // finally invert the column selection and get the new sequence
2399         // selection.
2400         invertColSel_actionPerformed(null);
2401         toggleCols = true;
2402       }
2403     }
2404
2405     if (toggleSeqs)
2406     {
2407       if (sg != null && sg.getSize() != viewport.alignment.getHeight())
2408       {
2409         hideSelSequences_actionPerformed(null);
2410         hide = true;
2411       }
2412       else if (!(toggleCols && viewport.colSel.getSelected().size() > 0))
2413       {
2414         showAllSeqs_actionPerformed(null);
2415       }
2416     }
2417
2418     if (toggleCols)
2419     {
2420       if (viewport.colSel.getSelected().size() > 0)
2421       {
2422         hideSelColumns_actionPerformed(null);
2423         if (!toggleSeqs)
2424         {
2425           viewport.selectionGroup = sg;
2426         }
2427       }
2428       else if (!hide)
2429       {
2430         showAllColumns_actionPerformed(null);
2431       }
2432     }
2433   }
2434
2435   /*
2436    * (non-Javadoc)
2437    * 
2438    * @see
2439    * jalview.jbgui.GAlignFrame#hideAllButSelection_actionPerformed(java.awt.
2440    * event.ActionEvent)
2441    */
2442   public void hideAllButSelection_actionPerformed(ActionEvent e)
2443   {
2444     toggleHiddenRegions(false, false);
2445   }
2446
2447   /*
2448    * (non-Javadoc)
2449    * 
2450    * @see
2451    * jalview.jbgui.GAlignFrame#hideAllSelection_actionPerformed(java.awt.event
2452    * .ActionEvent)
2453    */
2454   public void hideAllSelection_actionPerformed(ActionEvent e)
2455   {
2456     SequenceGroup sg = viewport.getSelectionGroup();
2457     viewport.expandColSelection(sg, false);
2458     viewport.hideAllSelectedSeqs();
2459     viewport.hideSelectedColumns();
2460     alignPanel.paintAlignment(true);
2461   }
2462
2463   /*
2464    * (non-Javadoc)
2465    * 
2466    * @see
2467    * jalview.jbgui.GAlignFrame#showAllhidden_actionPerformed(java.awt.event.
2468    * ActionEvent)
2469    */
2470   public void showAllhidden_actionPerformed(ActionEvent e)
2471   {
2472     viewport.showAllHiddenColumns();
2473     viewport.showAllHiddenSeqs();
2474     alignPanel.paintAlignment(true);
2475   }
2476
2477   public void hideSelColumns_actionPerformed(ActionEvent e)
2478   {
2479     viewport.hideSelectedColumns();
2480     alignPanel.paintAlignment(true);
2481   }
2482
2483   public void hiddenMarkers_actionPerformed(ActionEvent e)
2484   {
2485     viewport.setShowHiddenMarkers(hiddenMarkers.isSelected());
2486     repaint();
2487   }
2488
2489   /**
2490    * DOCUMENT ME!
2491    * 
2492    * @param e
2493    *          DOCUMENT ME!
2494    */
2495   protected void scaleAbove_actionPerformed(ActionEvent e)
2496   {
2497     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
2498     alignPanel.paintAlignment(true);
2499   }
2500
2501   /**
2502    * DOCUMENT ME!
2503    * 
2504    * @param e
2505    *          DOCUMENT ME!
2506    */
2507   protected void scaleLeft_actionPerformed(ActionEvent e)
2508   {
2509     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
2510     alignPanel.paintAlignment(true);
2511   }
2512
2513   /**
2514    * DOCUMENT ME!
2515    * 
2516    * @param e
2517    *          DOCUMENT ME!
2518    */
2519   protected void scaleRight_actionPerformed(ActionEvent e)
2520   {
2521     viewport.setScaleRightWrapped(scaleRight.isSelected());
2522     alignPanel.paintAlignment(true);
2523   }
2524
2525   /**
2526    * DOCUMENT ME!
2527    * 
2528    * @param e
2529    *          DOCUMENT ME!
2530    */
2531   public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
2532   {
2533     viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
2534     alignPanel.paintAlignment(true);
2535   }
2536
2537   /**
2538    * DOCUMENT ME!
2539    * 
2540    * @param e
2541    *          DOCUMENT ME!
2542    */
2543   public void viewTextMenuItem_actionPerformed(ActionEvent e)
2544   {
2545     viewport.setShowText(viewTextMenuItem.isSelected());
2546     alignPanel.paintAlignment(true);
2547   }
2548
2549   /**
2550    * DOCUMENT ME!
2551    * 
2552    * @param e
2553    *          DOCUMENT ME!
2554    */
2555   protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
2556   {
2557     viewport.setRenderGaps(renderGapsMenuItem.isSelected());
2558     alignPanel.paintAlignment(true);
2559   }
2560
2561   public FeatureSettings featureSettings;
2562
2563   public void featureSettings_actionPerformed(ActionEvent e)
2564   {
2565     if (featureSettings != null)
2566     {
2567       featureSettings.close();
2568       featureSettings = null;
2569     }
2570     if (!showSeqFeatures.isSelected())
2571     {
2572       // make sure features are actually displayed
2573       showSeqFeatures.setSelected(true);
2574       showSeqFeatures_actionPerformed(null);
2575     }
2576     featureSettings = new FeatureSettings(this);
2577   }
2578
2579   /**
2580    * Set or clear 'Show Sequence Features'
2581    * 
2582    * @param evt
2583    *          DOCUMENT ME!
2584    */
2585   public void showSeqFeatures_actionPerformed(ActionEvent evt)
2586   {
2587     viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
2588     alignPanel.paintAlignment(true);
2589     if (alignPanel.getOverviewPanel() != null)
2590     {
2591       alignPanel.getOverviewPanel().updateOverviewImage();
2592     }
2593   }
2594
2595   /**
2596    * Set or clear 'Show Sequence Features'
2597    * 
2598    * @param evt
2599    *          DOCUMENT ME!
2600    */
2601   public void showSeqFeaturesHeight_actionPerformed(ActionEvent evt)
2602   {
2603     viewport.setShowSequenceFeaturesHeight(showSeqFeaturesHeight
2604             .isSelected());
2605     if (viewport.getShowSequenceFeaturesHeight())
2606     {
2607       // ensure we're actually displaying features
2608       viewport.setShowSequenceFeatures(true);
2609       showSeqFeatures.setSelected(true);
2610     }
2611     alignPanel.paintAlignment(true);
2612     if (alignPanel.getOverviewPanel() != null)
2613     {
2614       alignPanel.getOverviewPanel().updateOverviewImage();
2615     }
2616   }
2617
2618   /**
2619    * DOCUMENT ME!
2620    * 
2621    * @param e
2622    *          DOCUMENT ME!
2623    */
2624   public void annotationPanelMenuItem_actionPerformed(ActionEvent e)
2625   {
2626     viewport.setShowAnnotation(annotationPanelMenuItem.isSelected());
2627     alignPanel.setAnnotationVisible(annotationPanelMenuItem.isSelected());
2628   }
2629
2630   public void alignmentProperties()
2631   {
2632     JEditorPane editPane = new JEditorPane("text/html", "");
2633     editPane.setEditable(false);
2634     StringBuffer contents = new StringBuffer("<html>");
2635
2636     float avg = 0;
2637     int min = Integer.MAX_VALUE, max = 0;
2638     for (int i = 0; i < viewport.alignment.getHeight(); i++)
2639     {
2640       int size = viewport.alignment.getSequenceAt(i).getEnd()
2641               - viewport.alignment.getSequenceAt(i).getStart();
2642       avg += size;
2643       if (size > max)
2644         max = size;
2645       if (size < min)
2646         min = size;
2647     }
2648     avg = avg / (float) viewport.alignment.getHeight();
2649
2650     contents.append("<br>Sequences: " + viewport.alignment.getHeight());
2651     contents.append("<br>Minimum Sequence Length: " + min);
2652     contents.append("<br>Maximum Sequence Length: " + max);
2653     contents.append("<br>Average Length: " + (int) avg);
2654
2655     if (((Alignment) viewport.alignment).getProperties() != null)
2656     {
2657       Hashtable props = ((Alignment) viewport.alignment).getProperties();
2658       Enumeration en = props.keys();
2659       contents.append("<br><br><table border=\"1\">");
2660       while (en.hasMoreElements())
2661       {
2662         String key = en.nextElement().toString();
2663         StringBuffer val = new StringBuffer();
2664         String vals = props.get(key).toString();
2665         int pos = 0, npos;
2666         do
2667         {
2668           npos = vals.indexOf("\n", pos);
2669           if (npos == -1)
2670           {
2671             val.append(vals.substring(pos));
2672           }
2673           else
2674           {
2675             val.append(vals.substring(pos, npos));
2676             val.append("<br>");
2677           }
2678           pos = npos + 1;
2679         } while (npos != -1);
2680         contents
2681                 .append("<tr><td>" + key + "</td><td>" + val + "</td></tr>");
2682       }
2683       contents.append("</table>");
2684     }
2685     editPane.setText(contents.toString() + "</html>");
2686     JInternalFrame frame = new JInternalFrame();
2687     frame.getContentPane().add(new JScrollPane(editPane));
2688
2689     Desktop.instance.addInternalFrame(frame, "Alignment Properties: "
2690             + getTitle(), 500, 400);
2691   }
2692
2693   /**
2694    * DOCUMENT ME!
2695    * 
2696    * @param e
2697    *          DOCUMENT ME!
2698    */
2699   public void overviewMenuItem_actionPerformed(ActionEvent e)
2700   {
2701     if (alignPanel.overviewPanel != null)
2702     {
2703       return;
2704     }
2705
2706     JInternalFrame frame = new JInternalFrame();
2707     OverviewPanel overview = new OverviewPanel(alignPanel);
2708     frame.setContentPane(overview);
2709     Desktop.addInternalFrame(frame, "Overview " + this.getTitle(), frame
2710             .getWidth(), frame.getHeight());
2711     frame.pack();
2712     frame.setLayer(JLayeredPane.PALETTE_LAYER);
2713     frame
2714             .addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
2715             {
2716               public void internalFrameClosed(
2717                       javax.swing.event.InternalFrameEvent evt)
2718               {
2719                 alignPanel.setOverviewPanel(null);
2720               };
2721             });
2722
2723     alignPanel.setOverviewPanel(overview);
2724   }
2725
2726   public void textColour_actionPerformed(ActionEvent e)
2727   {
2728     new TextColourChooser().chooseColour(alignPanel, null);
2729   }
2730
2731   /**
2732    * DOCUMENT ME!
2733    * 
2734    * @param e
2735    *          DOCUMENT ME!
2736    */
2737   protected void noColourmenuItem_actionPerformed(ActionEvent e)
2738   {
2739     changeColour(null);
2740   }
2741
2742   /**
2743    * DOCUMENT ME!
2744    * 
2745    * @param e
2746    *          DOCUMENT ME!
2747    */
2748   public void clustalColour_actionPerformed(ActionEvent e)
2749   {
2750     changeColour(new ClustalxColourScheme(
2751             viewport.alignment.getSequences(), viewport.alignment
2752                     .getWidth()));
2753   }
2754
2755   /**
2756    * DOCUMENT ME!
2757    * 
2758    * @param e
2759    *          DOCUMENT ME!
2760    */
2761   public void zappoColour_actionPerformed(ActionEvent e)
2762   {
2763     changeColour(new ZappoColourScheme());
2764   }
2765
2766   /**
2767    * DOCUMENT ME!
2768    * 
2769    * @param e
2770    *          DOCUMENT ME!
2771    */
2772   public void taylorColour_actionPerformed(ActionEvent e)
2773   {
2774     changeColour(new TaylorColourScheme());
2775   }
2776
2777   /**
2778    * DOCUMENT ME!
2779    * 
2780    * @param e
2781    *          DOCUMENT ME!
2782    */
2783   public void hydrophobicityColour_actionPerformed(ActionEvent e)
2784   {
2785     changeColour(new HydrophobicColourScheme());
2786   }
2787
2788   /**
2789    * DOCUMENT ME!
2790    * 
2791    * @param e
2792    *          DOCUMENT ME!
2793    */
2794   public void helixColour_actionPerformed(ActionEvent e)
2795   {
2796     changeColour(new HelixColourScheme());
2797   }
2798
2799   /**
2800    * DOCUMENT ME!
2801    * 
2802    * @param e
2803    *          DOCUMENT ME!
2804    */
2805   public void strandColour_actionPerformed(ActionEvent e)
2806   {
2807     changeColour(new StrandColourScheme());
2808   }
2809
2810   /**
2811    * DOCUMENT ME!
2812    * 
2813    * @param e
2814    *          DOCUMENT ME!
2815    */
2816   public void turnColour_actionPerformed(ActionEvent e)
2817   {
2818     changeColour(new TurnColourScheme());
2819   }
2820
2821   /**
2822    * DOCUMENT ME!
2823    * 
2824    * @param e
2825    *          DOCUMENT ME!
2826    */
2827   public void buriedColour_actionPerformed(ActionEvent e)
2828   {
2829     changeColour(new BuriedColourScheme());
2830   }
2831
2832   /**
2833    * DOCUMENT ME!
2834    * 
2835    * @param e
2836    *          DOCUMENT ME!
2837    */
2838   public void nucleotideColour_actionPerformed(ActionEvent e)
2839   {
2840     changeColour(new NucleotideColourScheme());
2841   }
2842
2843   public void annotationColour_actionPerformed(ActionEvent e)
2844   {
2845     new AnnotationColourChooser(viewport, alignPanel);
2846   }
2847
2848   /**
2849    * DOCUMENT ME!
2850    * 
2851    * @param e
2852    *          DOCUMENT ME!
2853    */
2854   protected void applyToAllGroups_actionPerformed(ActionEvent e)
2855   {
2856     viewport.setColourAppliesToAllGroups(applyToAllGroups.isSelected());
2857   }
2858
2859   /**
2860    * DOCUMENT ME!
2861    * 
2862    * @param cs
2863    *          DOCUMENT ME!
2864    */
2865   public void changeColour(ColourSchemeI cs)
2866   {
2867     int threshold = 0;
2868
2869     if (cs != null)
2870     {
2871       if (viewport.getAbovePIDThreshold())
2872       {
2873         threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
2874                 "Background");
2875
2876         cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
2877
2878         viewport.setGlobalColourScheme(cs);
2879       }
2880       else
2881       {
2882         cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
2883       }
2884
2885       if (viewport.getConservationSelected())
2886       {
2887
2888         Alignment al = (Alignment) viewport.alignment;
2889         Conservation c = new Conservation("All",
2890                 ResidueProperties.propHash, 3, al.getSequences(), 0, al
2891                         .getWidth() - 1);
2892
2893         c.calculate();
2894         c.verdict(false, viewport.ConsPercGaps);
2895
2896         cs.setConservation(c);
2897
2898         cs.setConservationInc(SliderPanel.setConservationSlider(alignPanel,
2899                 cs, "Background"));
2900       }
2901       else
2902       {
2903         cs.setConservation(null);
2904       }
2905
2906       cs.setConsensus(viewport.hconsensus);
2907     }
2908
2909     viewport.setGlobalColourScheme(cs);
2910
2911     if (viewport.getColourAppliesToAllGroups())
2912     {
2913       Vector groups = viewport.alignment.getGroups();
2914
2915       for (int i = 0; i < groups.size(); i++)
2916       {
2917         SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
2918
2919         if (cs == null)
2920         {
2921           sg.cs = null;
2922           continue;
2923         }
2924
2925         if (cs instanceof ClustalxColourScheme)
2926         {
2927           sg.cs = new ClustalxColourScheme(sg
2928                   .getSequences(viewport.hiddenRepSequences), sg.getWidth());
2929         }
2930         else if (cs instanceof UserColourScheme)
2931         {
2932           sg.cs = new UserColourScheme(((UserColourScheme) cs).getColours());
2933         }
2934         else
2935         {
2936           try
2937           {
2938             sg.cs = (ColourSchemeI) cs.getClass().newInstance();
2939           } catch (Exception ex)
2940           {
2941           }
2942         }
2943
2944         if (viewport.getAbovePIDThreshold()
2945                 || cs instanceof PIDColourScheme
2946                 || cs instanceof Blosum62ColourScheme)
2947         {
2948           sg.cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
2949
2950           sg.cs.setConsensus(AAFrequency.calculate(sg
2951                   .getSequences(viewport.hiddenRepSequences), sg
2952                   .getStartRes(), sg.getEndRes() + 1));
2953         }
2954         else
2955         {
2956           sg.cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
2957         }
2958
2959         if (viewport.getConservationSelected())
2960         {
2961           Conservation c = new Conservation("Group",
2962                   ResidueProperties.propHash, 3, sg
2963                           .getSequences(viewport.hiddenRepSequences), sg
2964                           .getStartRes(), sg.getEndRes() + 1);
2965           c.calculate();
2966           c.verdict(false, viewport.ConsPercGaps);
2967           sg.cs.setConservation(c);
2968         }
2969         else
2970         {
2971           sg.cs.setConservation(null);
2972         }
2973       }
2974     }
2975
2976     if (alignPanel.getOverviewPanel() != null)
2977     {
2978       alignPanel.getOverviewPanel().updateOverviewImage();
2979     }
2980
2981     alignPanel.paintAlignment(true);
2982   }
2983
2984   /**
2985    * DOCUMENT ME!
2986    * 
2987    * @param e
2988    *          DOCUMENT ME!
2989    */
2990   protected void modifyPID_actionPerformed(ActionEvent e)
2991   {
2992     if (viewport.getAbovePIDThreshold()
2993             && viewport.globalColourScheme != null)
2994     {
2995       SliderPanel.setPIDSliderSource(alignPanel, viewport
2996               .getGlobalColourScheme(), "Background");
2997       SliderPanel.showPIDSlider();
2998     }
2999   }
3000
3001   /**
3002    * DOCUMENT ME!
3003    * 
3004    * @param e
3005    *          DOCUMENT ME!
3006    */
3007   protected void modifyConservation_actionPerformed(ActionEvent e)
3008   {
3009     if (viewport.getConservationSelected()
3010             && viewport.globalColourScheme != null)
3011     {
3012       SliderPanel.setConservationSlider(alignPanel,
3013               viewport.globalColourScheme, "Background");
3014       SliderPanel.showConservationSlider();
3015     }
3016   }
3017
3018   /**
3019    * DOCUMENT ME!
3020    * 
3021    * @param e
3022    *          DOCUMENT ME!
3023    */
3024   protected void conservationMenuItem_actionPerformed(ActionEvent e)
3025   {
3026     viewport.setConservationSelected(conservationMenuItem.isSelected());
3027
3028     viewport.setAbovePIDThreshold(false);
3029     abovePIDThreshold.setSelected(false);
3030
3031     changeColour(viewport.getGlobalColourScheme());
3032
3033     modifyConservation_actionPerformed(null);
3034   }
3035
3036   /**
3037    * DOCUMENT ME!
3038    * 
3039    * @param e
3040    *          DOCUMENT ME!
3041    */
3042   public void abovePIDThreshold_actionPerformed(ActionEvent e)
3043   {
3044     viewport.setAbovePIDThreshold(abovePIDThreshold.isSelected());
3045
3046     conservationMenuItem.setSelected(false);
3047     viewport.setConservationSelected(false);
3048
3049     changeColour(viewport.getGlobalColourScheme());
3050
3051     modifyPID_actionPerformed(null);
3052   }
3053
3054   /**
3055    * DOCUMENT ME!
3056    * 
3057    * @param e
3058    *          DOCUMENT ME!
3059    */
3060   public void userDefinedColour_actionPerformed(ActionEvent e)
3061   {
3062     if (e.getActionCommand().equals("User Defined..."))
3063     {
3064       new UserDefinedColours(alignPanel, null);
3065     }
3066     else
3067     {
3068       UserColourScheme udc = (UserColourScheme) UserDefinedColours
3069               .getUserColourSchemes().get(e.getActionCommand());
3070
3071       changeColour(udc);
3072     }
3073   }
3074
3075   public void updateUserColourMenu()
3076   {
3077
3078     Component[] menuItems = colourMenu.getMenuComponents();
3079     int i, iSize = menuItems.length;
3080     for (i = 0; i < iSize; i++)
3081     {
3082       if (menuItems[i].getName() != null
3083               && menuItems[i].getName().equals("USER_DEFINED"))
3084       {
3085         colourMenu.remove(menuItems[i]);
3086         iSize--;
3087       }
3088     }
3089     if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)
3090     {
3091       java.util.Enumeration userColours = jalview.gui.UserDefinedColours
3092               .getUserColourSchemes().keys();
3093
3094       while (userColours.hasMoreElements())
3095       {
3096         final JRadioButtonMenuItem radioItem = new JRadioButtonMenuItem(
3097                 userColours.nextElement().toString());
3098         radioItem.setName("USER_DEFINED");
3099         radioItem.addMouseListener(new MouseAdapter()
3100         {
3101           public void mousePressed(MouseEvent evt)
3102           {
3103             if (evt.isControlDown()
3104                     || SwingUtilities.isRightMouseButton(evt))
3105             {
3106               radioItem
3107                       .removeActionListener(radioItem.getActionListeners()[0]);
3108
3109               int option = JOptionPane.showInternalConfirmDialog(
3110                       jalview.gui.Desktop.desktop,
3111                       "Remove from default list?",
3112                       "Remove user defined colour",
3113                       JOptionPane.YES_NO_OPTION);
3114               if (option == JOptionPane.YES_OPTION)
3115               {
3116                 jalview.gui.UserDefinedColours
3117                         .removeColourFromDefaults(radioItem.getText());
3118                 colourMenu.remove(radioItem);
3119               }
3120               else
3121               {
3122                 radioItem.addActionListener(new ActionListener()
3123                 {
3124                   public void actionPerformed(ActionEvent evt)
3125                   {
3126                     userDefinedColour_actionPerformed(evt);
3127                   }
3128                 });
3129               }
3130             }
3131           }
3132         });
3133         radioItem.addActionListener(new ActionListener()
3134         {
3135           public void actionPerformed(ActionEvent evt)
3136           {
3137             userDefinedColour_actionPerformed(evt);
3138           }
3139         });
3140
3141         colourMenu.insert(radioItem, 15);
3142         colours.add(radioItem);
3143       }
3144     }
3145   }
3146
3147   /**
3148    * DOCUMENT ME!
3149    * 
3150    * @param e
3151    *          DOCUMENT ME!
3152    */
3153   public void PIDColour_actionPerformed(ActionEvent e)
3154   {
3155     changeColour(new PIDColourScheme());
3156   }
3157
3158   /**
3159    * DOCUMENT ME!
3160    * 
3161    * @param e
3162    *          DOCUMENT ME!
3163    */
3164   public void BLOSUM62Colour_actionPerformed(ActionEvent e)
3165   {
3166     changeColour(new Blosum62ColourScheme());
3167   }
3168
3169   /**
3170    * DOCUMENT ME!
3171    * 
3172    * @param e
3173    *          DOCUMENT ME!
3174    */
3175   public void sortPairwiseMenuItem_actionPerformed(ActionEvent e)
3176   {
3177     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3178     AlignmentSorter.sortByPID(viewport.getAlignment(), viewport
3179             .getAlignment().getSequenceAt(0), null);
3180     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
3181             viewport.alignment));
3182     alignPanel.paintAlignment(true);
3183   }
3184
3185   /**
3186    * DOCUMENT ME!
3187    * 
3188    * @param e
3189    *          DOCUMENT ME!
3190    */
3191   public void sortIDMenuItem_actionPerformed(ActionEvent e)
3192   {
3193     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3194     AlignmentSorter.sortByID(viewport.getAlignment());
3195     addHistoryItem(new OrderCommand("ID Sort", oldOrder, viewport.alignment));
3196     alignPanel.paintAlignment(true);
3197   }
3198
3199   /**
3200    * DOCUMENT ME!
3201    * 
3202    * @param e
3203    *          DOCUMENT ME!
3204    */
3205   public void sortLengthMenuItem_actionPerformed(ActionEvent e)
3206   {
3207     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3208     AlignmentSorter.sortByLength(viewport.getAlignment());
3209     addHistoryItem(new OrderCommand("Length Sort", oldOrder,
3210             viewport.alignment));
3211     alignPanel.paintAlignment(true);
3212   }
3213
3214   /**
3215    * DOCUMENT ME!
3216    * 
3217    * @param e
3218    *          DOCUMENT ME!
3219    */
3220   public void sortGroupMenuItem_actionPerformed(ActionEvent e)
3221   {
3222     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3223     AlignmentSorter.sortByGroup(viewport.getAlignment());
3224     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
3225             viewport.alignment));
3226
3227     alignPanel.paintAlignment(true);
3228   }
3229
3230   /**
3231    * DOCUMENT ME!
3232    * 
3233    * @param e
3234    *          DOCUMENT ME!
3235    */
3236   public void removeRedundancyMenuItem_actionPerformed(ActionEvent e)
3237   {
3238     new RedundancyPanel(alignPanel, this);
3239   }
3240
3241   /**
3242    * DOCUMENT ME!
3243    * 
3244    * @param e
3245    *          DOCUMENT ME!
3246    */
3247   public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e)
3248   {
3249     if ((viewport.getSelectionGroup() == null)
3250             || (viewport.getSelectionGroup().getSize() < 2))
3251     {
3252       JOptionPane.showInternalMessageDialog(this,
3253               "You must select at least 2 sequences.", "Invalid Selection",
3254               JOptionPane.WARNING_MESSAGE);
3255     }
3256     else
3257     {
3258       JInternalFrame frame = new JInternalFrame();
3259       frame.setContentPane(new PairwiseAlignPanel(viewport));
3260       Desktop.addInternalFrame(frame, "Pairwise Alignment", 600, 500);
3261     }
3262   }
3263
3264   /**
3265    * DOCUMENT ME!
3266    * 
3267    * @param e
3268    *          DOCUMENT ME!
3269    */
3270   public void PCAMenuItem_actionPerformed(ActionEvent e)
3271   {
3272     if (((viewport.getSelectionGroup() != null)
3273             && (viewport.getSelectionGroup().getSize() < 4) && (viewport
3274             .getSelectionGroup().getSize() > 0))
3275             || (viewport.getAlignment().getHeight() < 4))
3276     {
3277       JOptionPane.showInternalMessageDialog(this,
3278               "Principal component analysis must take\n"
3279                       + "at least 4 input sequences.",
3280               "Sequence selection insufficient",
3281               JOptionPane.WARNING_MESSAGE);
3282
3283       return;
3284     }
3285
3286     new PCAPanel(alignPanel);
3287   }
3288
3289   public void autoCalculate_actionPerformed(ActionEvent e)
3290   {
3291     viewport.autoCalculateConsensus = autoCalculate.isSelected();
3292     if (viewport.autoCalculateConsensus)
3293     {
3294       viewport.firePropertyChange("alignment", null, viewport
3295               .getAlignment().getSequences());
3296     }
3297   }
3298
3299   /**
3300    * DOCUMENT ME!
3301    * 
3302    * @param e
3303    *          DOCUMENT ME!
3304    */
3305   public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)
3306   {
3307     NewTreePanel("AV", "PID", "Average distance tree using PID");
3308   }
3309
3310   /**
3311    * DOCUMENT ME!
3312    * 
3313    * @param e
3314    *          DOCUMENT ME!
3315    */
3316   public void neighbourTreeMenuItem_actionPerformed(ActionEvent e)
3317   {
3318     NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
3319   }
3320
3321   /**
3322    * DOCUMENT ME!
3323    * 
3324    * @param e
3325    *          DOCUMENT ME!
3326    */
3327   protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)
3328   {
3329     NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
3330   }
3331
3332   /**
3333    * DOCUMENT ME!
3334    * 
3335    * @param e
3336    *          DOCUMENT ME!
3337    */
3338   protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e)
3339   {
3340     NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
3341   }
3342
3343   /**
3344    * DOCUMENT ME!
3345    * 
3346    * @param type
3347    *          DOCUMENT ME!
3348    * @param pwType
3349    *          DOCUMENT ME!
3350    * @param title
3351    *          DOCUMENT ME!
3352    */
3353   void NewTreePanel(String type, String pwType, String title)
3354   {
3355     TreePanel tp;
3356
3357     if (viewport.getSelectionGroup() != null)
3358     {
3359       if (viewport.getSelectionGroup().getSize() < 3)
3360       {
3361         JOptionPane
3362                 .showMessageDialog(
3363                         Desktop.desktop,
3364                         "You need to have more than two sequences selected to build a tree!",
3365                         "Not enough sequences", JOptionPane.WARNING_MESSAGE);
3366         return;
3367       }
3368
3369       int s = 0;
3370       SequenceGroup sg = viewport.getSelectionGroup();
3371
3372       /* Decide if the selection is a column region */
3373       while (s < sg.getSize())
3374       {
3375         if (((SequenceI) sg.getSequences(null).elementAt(s++)).getLength() < sg
3376                 .getEndRes())
3377         {
3378           JOptionPane
3379                   .showMessageDialog(
3380                           Desktop.desktop,
3381                           "The selected region to create a tree may\nonly contain residues or gaps.\n"
3382                                   + "Try using the Pad function in the edit menu,\n"
3383                                   + "or one of the multiple sequence alignment web services.",
3384                           "Sequences in selection are not aligned",
3385                           JOptionPane.WARNING_MESSAGE);
3386
3387           return;
3388         }
3389       }
3390
3391       title = title + " on region";
3392       tp = new TreePanel(alignPanel, type, pwType);
3393     }
3394     else
3395     {
3396       // are the visible sequences aligned?
3397       if (!viewport.alignment.isAligned(false))
3398       {
3399         JOptionPane
3400                 .showMessageDialog(
3401                         Desktop.desktop,
3402                         "The sequences must be aligned before creating a tree.\n"
3403                                 + "Try using the Pad function in the edit menu,\n"
3404                                 + "or one of the multiple sequence alignment web services.",
3405                         "Sequences not aligned",
3406                         JOptionPane.WARNING_MESSAGE);
3407
3408         return;
3409       }
3410
3411       if (viewport.alignment.getHeight() < 2)
3412       {
3413         return;
3414       }
3415
3416       tp = new TreePanel(alignPanel, type, pwType);
3417     }
3418
3419     title += " from ";
3420
3421     if (viewport.viewName != null)
3422     {
3423       title += viewport.viewName + " of ";
3424     }
3425
3426     title += this.title;
3427
3428     Desktop.addInternalFrame(tp, title, 600, 500);
3429   }
3430
3431   /**
3432    * DOCUMENT ME!
3433    * 
3434    * @param title
3435    *          DOCUMENT ME!
3436    * @param order
3437    *          DOCUMENT ME!
3438    */
3439   public void addSortByOrderMenuItem(String title,
3440           final AlignmentOrder order)
3441   {
3442     final JMenuItem item = new JMenuItem("by " + title);
3443     sort.add(item);
3444     item.addActionListener(new java.awt.event.ActionListener()
3445     {
3446       public void actionPerformed(ActionEvent e)
3447       {
3448         SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3449
3450         // TODO: JBPNote - have to map order entries to curent SequenceI
3451         // pointers
3452         AlignmentSorter.sortBy(viewport.getAlignment(), order);
3453
3454         addHistoryItem(new OrderCommand(order.getName(), oldOrder,
3455                 viewport.alignment));
3456
3457         alignPanel.paintAlignment(true);
3458       }
3459     });
3460   }
3461
3462   /**
3463    * Add a new sort by annotation score menu item
3464    * 
3465    * @param sort
3466    *          the menu to add the option to
3467    * @param scoreLabel
3468    *          the label used to retrieve scores for each sequence on the
3469    *          alignment
3470    */
3471   public void addSortByAnnotScoreMenuItem(JMenu sort,
3472           final String scoreLabel)
3473   {
3474     final JMenuItem item = new JMenuItem(scoreLabel);
3475     sort.add(item);
3476     item.addActionListener(new java.awt.event.ActionListener()
3477     {
3478       public void actionPerformed(ActionEvent e)
3479       {
3480         SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3481         AlignmentSorter.sortByAnnotationScore(scoreLabel, viewport
3482                 .getAlignment());// ,viewport.getSelectionGroup());
3483         addHistoryItem(new OrderCommand("Sort by " + scoreLabel, oldOrder,
3484                 viewport.alignment));
3485         alignPanel.paintAlignment(true);
3486       }
3487     });
3488   }
3489
3490   /**
3491    * last hash for alignment's annotation array - used to minimise cost of
3492    * rebuild.
3493    */
3494   protected int _annotationScoreVectorHash;
3495
3496   /**
3497    * search the alignment and rebuild the sort by annotation score submenu the
3498    * last alignment annotation vector hash is stored to minimize cost of
3499    * rebuilding in subsequence calls.
3500    * 
3501    */
3502   public void buildSortByAnnotationScoresMenu()
3503   {
3504     if (viewport.alignment.getAlignmentAnnotation() == null)
3505     {
3506       return;
3507     }
3508
3509     if (viewport.alignment.getAlignmentAnnotation().hashCode() != _annotationScoreVectorHash)
3510     {
3511       sortByAnnotScore.removeAll();
3512       // almost certainly a quicker way to do this - but we keep it simple
3513       Hashtable scoreSorts = new Hashtable();
3514       AlignmentAnnotation aann[];
3515       Enumeration sq = viewport.alignment.getSequences().elements();
3516       while (sq.hasMoreElements())
3517       {
3518         aann = ((SequenceI) sq.nextElement()).getAnnotation();
3519         for (int i = 0; aann != null && i < aann.length; i++)
3520         {
3521           if (aann[i].hasScore() && aann[i].sequenceRef != null)
3522           {
3523             scoreSorts.put(aann[i].label, aann[i].label);
3524           }
3525         }
3526       }
3527       Enumeration labels = scoreSorts.keys();
3528       while (labels.hasMoreElements())
3529       {
3530         addSortByAnnotScoreMenuItem(sortByAnnotScore, (String) labels
3531                 .nextElement());
3532       }
3533       sortByAnnotScore.setVisible(scoreSorts.size() > 0);
3534       scoreSorts.clear();
3535
3536       _annotationScoreVectorHash = viewport.alignment
3537               .getAlignmentAnnotation().hashCode();
3538     }
3539   }
3540
3541   /**
3542    * Maintain the Order by->Displayed Tree menu. Creates a new menu item for a
3543    * TreePanel with an appropriate <code>jalview.analysis.AlignmentSorter</code>
3544    * call. Listeners are added to remove the menu item when the treePanel is
3545    * closed, and adjust the tree leaf to sequence mapping when the alignment is
3546    * modified.
3547    * 
3548    * @param treePanel
3549    *          Displayed tree window.
3550    * @param title
3551    *          SortBy menu item title.
3552    */
3553   public void buildTreeMenu()
3554   {
3555     sortByTreeMenu.removeAll();
3556
3557     Vector comps = (Vector) PaintRefresher.components.get(viewport
3558             .getSequenceSetId());
3559     Vector treePanels = new Vector();
3560     int i, iSize = comps.size();
3561     for (i = 0; i < iSize; i++)
3562     {
3563       if (comps.elementAt(i) instanceof TreePanel)
3564       {
3565         treePanels.add(comps.elementAt(i));
3566       }
3567     }
3568
3569     iSize = treePanels.size();
3570
3571     if (iSize < 1)
3572     {
3573       sortByTreeMenu.setVisible(false);
3574       return;
3575     }
3576
3577     sortByTreeMenu.setVisible(true);
3578
3579     for (i = 0; i < treePanels.size(); i++)
3580     {
3581       TreePanel tp = (TreePanel) treePanels.elementAt(i);
3582       final JMenuItem item = new JMenuItem(tp.getTitle());
3583       final NJTree tree = ((TreePanel) treePanels.elementAt(i)).getTree();
3584       item.addActionListener(new java.awt.event.ActionListener()
3585       {
3586         public void actionPerformed(ActionEvent e)
3587         {
3588           SequenceI[] oldOrder = viewport.getAlignment()
3589                   .getSequencesArray();
3590           AlignmentSorter.sortByTree(viewport.getAlignment(), tree);
3591
3592           addHistoryItem(new OrderCommand("Tree Sort", oldOrder,
3593                   viewport.alignment));
3594
3595           alignPanel.paintAlignment(true);
3596         }
3597       });
3598
3599       sortByTreeMenu.add(item);
3600     }
3601   }
3602
3603   /**
3604    * Work out whether the whole set of sequences or just the selected set will
3605    * be submitted for multiple alignment.
3606    * 
3607    */
3608   public jalview.datamodel.AlignmentView gatherSequencesForAlignment()
3609   {
3610     // Now, check we have enough sequences
3611     AlignmentView msa = null;
3612
3613     if ((viewport.getSelectionGroup() != null)
3614             && (viewport.getSelectionGroup().getSize() > 1))
3615     {
3616       // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to
3617       // some common interface!
3618       /*
3619        * SequenceGroup seqs = viewport.getSelectionGroup(); int sz; msa = new
3620        * SequenceI[sz = seqs.getSize(false)];
3621        * 
3622        * for (int i = 0; i < sz; i++) { msa[i] = (SequenceI)
3623        * seqs.getSequenceAt(i); }
3624        */
3625       msa = viewport.getAlignmentView(true);
3626     }
3627     else
3628     {
3629       /*
3630        * Vector seqs = viewport.getAlignment().getSequences();
3631        * 
3632        * if (seqs.size() > 1) { msa = new SequenceI[seqs.size()];
3633        * 
3634        * for (int i = 0; i < seqs.size(); i++) { msa[i] = (SequenceI)
3635        * seqs.elementAt(i); } }
3636        */
3637       msa = viewport.getAlignmentView(false);
3638     }
3639     return msa;
3640   }
3641
3642   /**
3643    * Decides what is submitted to a secondary structure prediction service: the
3644    * first sequence in the alignment, or in the current selection, or, if the
3645    * alignment is 'aligned' (ie padded with gaps), then the currently selected
3646    * region or the whole alignment. (where the first sequence in the set is the
3647    * one that the prediction will be for).
3648    */
3649   public AlignmentView gatherSeqOrMsaForSecStrPrediction()
3650   {
3651     AlignmentView seqs = null;
3652
3653     if ((viewport.getSelectionGroup() != null)
3654             && (viewport.getSelectionGroup().getSize() > 0))
3655     {
3656       seqs = viewport.getAlignmentView(true);
3657     }
3658     else
3659     {
3660       seqs = viewport.getAlignmentView(false);
3661     }
3662     // limit sequences - JBPNote in future - could spawn multiple prediction
3663     // jobs
3664     // TODO: viewport.alignment.isAligned is a global state - the local
3665     // selection may well be aligned - we preserve 2.0.8 behaviour for moment.
3666     if (!viewport.alignment.isAligned(false))
3667     {
3668       seqs.setSequences(new SeqCigar[]
3669       { seqs.getSequences()[0] });
3670       // TODO: if seqs.getSequences().length>1 then should really have warned
3671       // user!
3672
3673     }
3674     return seqs;
3675   }
3676
3677   /**
3678    * DOCUMENT ME!
3679    * 
3680    * @param e
3681    *          DOCUMENT ME!
3682    */
3683   protected void LoadtreeMenuItem_actionPerformed(ActionEvent e)
3684   {
3685     // Pick the tree file
3686     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
3687             .getProperty("LAST_DIRECTORY"));
3688     chooser.setFileView(new JalviewFileView());
3689     chooser.setDialogTitle("Select a newick-like tree file");
3690     chooser.setToolTipText("Load a tree file");
3691
3692     int value = chooser.showOpenDialog(null);
3693
3694     if (value == JalviewFileChooser.APPROVE_OPTION)
3695     {
3696       String choice = chooser.getSelectedFile().getPath();
3697       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
3698       jalview.io.NewickFile fin = null;
3699       try
3700       {
3701         fin = new jalview.io.NewickFile(choice, "File");
3702         viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
3703       } catch (Exception ex)
3704       {
3705         JOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(),
3706                 "Problem reading tree file", JOptionPane.WARNING_MESSAGE);
3707         ex.printStackTrace();
3708       }
3709       if (fin != null && fin.hasWarningMessage())
3710       {
3711         JOptionPane.showMessageDialog(Desktop.desktop, fin
3712                 .getWarningMessage(), "Possible problem with tree file",
3713                 JOptionPane.WARNING_MESSAGE);
3714       }
3715     }
3716   }
3717
3718   public TreePanel ShowNewickTree(NewickFile nf, String title)
3719   {
3720     return ShowNewickTree(nf, title, 600, 500, 4, 5);
3721   }
3722
3723   public TreePanel ShowNewickTree(NewickFile nf, String title,
3724           AlignmentView input)
3725   {
3726     return ShowNewickTree(nf, title, input, 600, 500, 4, 5);
3727   }
3728
3729   public TreePanel ShowNewickTree(NewickFile nf, String title, int w,
3730           int h, int x, int y)
3731   {
3732     return ShowNewickTree(nf, title, null, w, h, x, y);
3733   }
3734
3735   /**
3736    * Add a treeviewer for the tree extracted from a newick file object to the
3737    * current alignment view
3738    * 
3739    * @param nf
3740    *          the tree
3741    * @param title
3742    *          tree viewer title
3743    * @param input
3744    *          Associated alignment input data (or null)
3745    * @param w
3746    *          width
3747    * @param h
3748    *          height
3749    * @param x
3750    *          position
3751    * @param y
3752    *          position
3753    * @return TreePanel handle
3754    */
3755   public TreePanel ShowNewickTree(NewickFile nf, String title,
3756           AlignmentView input, int w, int h, int x, int y)
3757   {
3758     TreePanel tp = null;
3759
3760     try
3761     {
3762       nf.parse();
3763
3764       if (nf.getTree() != null)
3765       {
3766         tp = new TreePanel(alignPanel, "FromFile", title, nf, input);
3767
3768         tp.setSize(w, h);
3769
3770         if (x > 0 && y > 0)
3771         {
3772           tp.setLocation(x, y);
3773         }
3774
3775         Desktop.addInternalFrame(tp, title, w, h);
3776       }
3777     } catch (Exception ex)
3778     {
3779       ex.printStackTrace();
3780     }
3781
3782     return tp;
3783   }
3784
3785   /**
3786    * Generates menu items and listener event actions for web service clients
3787    * 
3788    */
3789   public void BuildWebServiceMenu()
3790   {
3791     // TODO: add support for context dependent disabling of services based on
3792     // alignment and current selection
3793     // TODO: add additional serviceHandle parameter to specify abstract handler
3794     // class independently of AbstractName
3795     // TODO: add in rediscovery GUI function to restart discoverer
3796     // TODO: group services by location as well as function and/or introduce
3797     // object broker mechanism.
3798     if ((Discoverer.services != null) && (Discoverer.services.size() > 0))
3799     {
3800       // TODO: refactor to allow list of AbstractName/Handler bindings to be
3801       // stored or retrieved from elsewhere
3802       Vector msaws = (Vector) Discoverer.services.get("MsaWS");
3803       Vector secstrpr = (Vector) Discoverer.services.get("SecStrPred");
3804       Vector seqsrch = (Vector) Discoverer.services.get("SeqSearch");
3805       // TODO: move GUI generation code onto service implementation - so a
3806       // client instance attaches itself to the GUI with method call like
3807       // jalview.ws.MsaWSClient.bind(servicehandle, Desktop.instance,
3808       // alignframe)
3809       Vector wsmenu = new Vector();
3810       final IProgressIndicator af = this;
3811       if (msaws != null)
3812       {
3813         // Add any Multiple Sequence Alignment Services
3814         final JMenu msawsmenu = new JMenu("Alignment");
3815         for (int i = 0, j = msaws.size(); i < j; i++)
3816         {
3817           final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) msaws
3818                   .get(i);
3819           jalview.ws.WSClient impl = jalview.ws.Discoverer
3820                   .getServiceClient(sh);
3821           impl.attachWSMenuEntry(msawsmenu, this);
3822
3823         }
3824         wsmenu.add(msawsmenu);
3825       }
3826       if (secstrpr != null)
3827       {
3828         // Add any secondary structure prediction services
3829         final JMenu secstrmenu = new JMenu("Secondary Structure Prediction");
3830         for (int i = 0, j = secstrpr.size(); i < j; i++)
3831         {
3832           final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr
3833                   .get(i);
3834           jalview.ws.WSClient impl = jalview.ws.Discoverer
3835                   .getServiceClient(sh);
3836           impl.attachWSMenuEntry(secstrmenu, this);
3837         }
3838         wsmenu.add(secstrmenu);
3839       }
3840       if (seqsrch != null)
3841       {
3842         // Add any sequence search services
3843         final JMenu seqsrchmenu = new JMenu("Sequence Database Search");
3844         for (int i = 0, j = seqsrch.size(); i < j; i++)
3845         {
3846           final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) seqsrch
3847                   .elementAt(i);
3848           jalview.ws.WSClient impl = jalview.ws.Discoverer
3849                   .getServiceClient(sh);
3850           impl.attachWSMenuEntry(seqsrchmenu, this);
3851         }
3852         wsmenu.add(seqsrchmenu);
3853       }
3854       // finally, add the whole shebang onto the webservices menu
3855       resetWebServiceMenu();
3856       for (int i = 0, j = wsmenu.size(); i < j; i++)
3857       {
3858         webService.add((JMenu) wsmenu.get(i));
3859       }
3860     }
3861     else
3862     {
3863       resetWebServiceMenu();
3864       this.webService.add(this.webServiceNoServices);
3865     }
3866   }
3867
3868   /**
3869    * empty the web service menu and add any ad-hoc functions not dynamically
3870    * discovered.
3871    * 
3872    */
3873   private void resetWebServiceMenu()
3874   {
3875     webService.removeAll();
3876     build_fetchdbmenu(webService);
3877     build_urlServiceMenu(webService);
3878   }
3879
3880   /**
3881    * construct any groupURL type service menu entries.
3882    * 
3883    * @param webService
3884    */
3885   private void build_urlServiceMenu(JMenu webService)
3886   {
3887     jalview.ws.EnfinEnvision2OneWay.getInstance().attachWSMenuEntry(
3888             webService, this);
3889   }
3890
3891   /*
3892    * public void vamsasStore_actionPerformed(ActionEvent e) { JalviewFileChooser
3893    * chooser = new JalviewFileChooser(jalview.bin.Cache.
3894    * getProperty("LAST_DIRECTORY"));
3895    * 
3896    * chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle("Export
3897    * to Vamsas file"); chooser.setToolTipText("Export");
3898    * 
3899    * int value = chooser.showSaveDialog(this);
3900    * 
3901    * if (value == JalviewFileChooser.APPROVE_OPTION) {
3902    * jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport);
3903    * //vs.store(chooser.getSelectedFile().getAbsolutePath() ); vs.storeJalview(
3904    * chooser.getSelectedFile().getAbsolutePath(), this); } }
3905    */
3906   /**
3907    * prototype of an automatically enabled/disabled analysis function
3908    * 
3909    */
3910   protected void setShowProductsEnabled()
3911   {
3912     SequenceI[] selection = viewport.getSequenceSelection();
3913     if (canShowProducts(selection, viewport.getSelectionGroup() != null,
3914             viewport.getAlignment().getDataset()))
3915     {
3916       showProducts.setEnabled(true);
3917
3918     }
3919     else
3920     {
3921       showProducts.setEnabled(false);
3922     }
3923   }
3924
3925   /**
3926    * search selection for sequence xRef products and build the show products
3927    * menu.
3928    * 
3929    * @param selection
3930    * @param dataset
3931    * @return true if showProducts menu should be enabled.
3932    */
3933   public boolean canShowProducts(SequenceI[] selection,
3934           boolean isRegionSelection, Alignment dataset)
3935   {
3936     boolean showp = false;
3937     try
3938     {
3939       showProducts.removeAll();
3940       final boolean dna = viewport.getAlignment().isNucleotide();
3941       final Alignment ds = dataset;
3942       String[] ptypes = (selection == null || selection.length == 0) ? null
3943               : CrossRef.findSequenceXrefTypes(dna, selection, dataset);
3944       // Object[] prods =
3945       // CrossRef.buildXProductsList(viewport.getAlignment().isNucleotide(),
3946       // selection, dataset, true);
3947       final SequenceI[] sel = selection;
3948       for (int t = 0; ptypes != null && t < ptypes.length; t++)
3949       {
3950         showp = true;
3951         final boolean isRegSel = isRegionSelection;
3952         final AlignFrame af = this;
3953         final String source = ptypes[t];
3954         JMenuItem xtype = new JMenuItem(ptypes[t]);
3955         xtype.addActionListener(new ActionListener()
3956         {
3957
3958           public void actionPerformed(ActionEvent e)
3959           {
3960             // TODO: new thread for this call with vis-delay
3961             af.showProductsFor(af.viewport.getSequenceSelection(), ds,
3962                     isRegSel, dna, source);
3963           }
3964
3965         });
3966         showProducts.add(xtype);
3967       }
3968       showProducts.setVisible(showp);
3969       showProducts.setEnabled(showp);
3970     } catch (Exception e)
3971     {
3972       jalview.bin.Cache.log
3973               .warn(
3974                       "canTranslate threw an exception - please report to help@jalview.org",
3975                       e);
3976       return false;
3977     }
3978     return showp;
3979   }
3980
3981   protected void showProductsFor(SequenceI[] sel, Alignment ds,
3982           boolean isRegSel, boolean dna, String source)
3983   {
3984     final boolean fisRegSel = isRegSel;
3985     final boolean fdna = dna;
3986     final String fsrc = source;
3987     final AlignFrame ths = this;
3988     final SequenceI[] fsel = sel;
3989     Runnable foo = new Runnable()
3990     {
3991
3992       public void run()
3993       {
3994         final long sttime = System.currentTimeMillis();
3995         ths.setProgressBar("Searching for sequences from " + fsrc, sttime);
3996         try
3997         {
3998           Alignment ds = ths.getViewport().alignment.getDataset(); // update
3999           // our local
4000           // dataset
4001           // reference
4002           Alignment prods = CrossRef
4003                   .findXrefSequences(fsel, fdna, fsrc, ds);
4004           if (prods != null)
4005           {
4006             SequenceI[] sprods = new SequenceI[prods.getHeight()];
4007             for (int s = 0; s < sprods.length; s++)
4008             {
4009               sprods[s] = (prods.getSequenceAt(s)).deriveSequence();
4010               if (ds.getSequences() == null
4011                       || !ds.getSequences().contains(
4012                               sprods[s].getDatasetSequence()))
4013                 ds.addSequence(sprods[s].getDatasetSequence());
4014               sprods[s].updatePDBIds();
4015             }
4016             Alignment al = new Alignment(sprods);
4017             AlignedCodonFrame[] cf = prods.getCodonFrames();
4018             al.setDataset(ds);
4019             for (int s = 0; cf != null && s < cf.length; s++)
4020             {
4021               al.addCodonFrame(cf[s]);
4022               cf[s] = null;
4023             }
4024             AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH,
4025                     DEFAULT_HEIGHT);
4026             String newtitle = "" + ((fdna) ? "Proteins " : "Nucleotides ")
4027                     + " for " + ((fisRegSel) ? "selected region of " : "")
4028                     + getTitle();
4029             Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,
4030                     DEFAULT_HEIGHT);
4031           }
4032           else
4033           {
4034             System.err.println("No Sequences generated for xRef type "
4035                     + fsrc);
4036           }
4037         } catch (Exception e)
4038         {
4039           jalview.bin.Cache.log.error(
4040                   "Exception when finding crossreferences", e);
4041         } catch (OutOfMemoryError e)
4042         {
4043           new OOMWarning("whilst fetching crossreferences", e);
4044         } catch (Error e)
4045         {
4046           jalview.bin.Cache.log.error("Error when finding crossreferences",
4047                   e);
4048         }
4049         ths.setProgressBar("Finished searching for sequences from " + fsrc,
4050                 sttime);
4051       }
4052
4053     };
4054     Thread frunner = new Thread(foo);
4055     frunner.start();
4056   }
4057
4058   public boolean canShowTranslationProducts(SequenceI[] selection,
4059           AlignmentI alignment)
4060   {
4061     // old way
4062     try
4063     {
4064       return (jalview.analysis.Dna.canTranslate(selection, viewport
4065               .getViewAsVisibleContigs(true)));
4066     } catch (Exception e)
4067     {
4068       jalview.bin.Cache.log
4069               .warn(
4070                       "canTranslate threw an exception - please report to help@jalview.org",
4071                       e);
4072       return false;
4073     }
4074   }
4075
4076   public void showProducts_actionPerformed(ActionEvent e)
4077   {
4078     // /////////////////////////////
4079     // Collect Data to be translated/transferred
4080
4081     SequenceI[] selection = viewport.getSequenceSelection();
4082     AlignmentI al = null;
4083     try
4084     {
4085       al = jalview.analysis.Dna.CdnaTranslate(selection, viewport
4086               .getViewAsVisibleContigs(true), viewport.getGapCharacter(),
4087               viewport.getAlignment().getDataset());
4088     } catch (Exception ex)
4089     {
4090       al = null;
4091       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4092     }
4093     if (al == null)
4094     {
4095       JOptionPane
4096               .showMessageDialog(
4097                       Desktop.desktop,
4098                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4099                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4100     }
4101     else
4102     {
4103       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4104       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4105               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4106     }
4107   }
4108
4109   public void showTranslation_actionPerformed(ActionEvent e)
4110   {
4111     // /////////////////////////////
4112     // Collect Data to be translated/transferred
4113
4114     SequenceI[] selection = viewport.getSequenceSelection();
4115     String[] seqstring = viewport.getViewAsString(true);
4116     AlignmentI al = null;
4117     try
4118     {
4119       al = jalview.analysis.Dna.CdnaTranslate(selection, seqstring,
4120               viewport.getViewAsVisibleContigs(true), viewport
4121                       .getGapCharacter(), viewport.alignment
4122                       .getAlignmentAnnotation(), viewport.alignment
4123                       .getWidth(), viewport.getAlignment().getDataset());
4124     } catch (Exception ex)
4125     {
4126       al = null;
4127       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4128     }
4129     if (al == null)
4130     {
4131       JOptionPane
4132               .showMessageDialog(
4133                       Desktop.desktop,
4134                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4135                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4136     }
4137     else
4138     {
4139       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4140       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4141               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4142     }
4143   }
4144
4145   /**
4146    * Try to load a features file onto the alignment.
4147    * 
4148    * @param file
4149    *          contents or path to retrieve file
4150    * @param type
4151    *          access mode of file (see jalview.io.AlignFile)
4152    * @return true if features file was parsed corectly.
4153    */
4154   public boolean parseFeaturesFile(String file, String type)
4155   {
4156     boolean featuresFile = false;
4157     try
4158     {
4159       featuresFile = new FeaturesFile(file, type).parse(viewport.alignment
4160               .getDataset(), alignPanel.seqPanel.seqCanvas
4161               .getFeatureRenderer().featureColours, false);
4162     } catch (Exception ex)
4163     {
4164       ex.printStackTrace();
4165     }
4166
4167     if (featuresFile)
4168     {
4169       viewport.showSequenceFeatures = true;
4170       showSeqFeatures.setSelected(true);
4171       if (alignPanel.seqPanel.seqCanvas.fr != null)
4172       {
4173         // update the min/max ranges where necessary
4174         alignPanel.seqPanel.seqCanvas.fr.findAllFeatures(true);
4175       }
4176       if (featureSettings != null)
4177       {
4178         featureSettings.setTableData();
4179       }
4180       alignPanel.paintAlignment(true);
4181     }
4182
4183     return featuresFile;
4184   }
4185
4186   public void dragEnter(DropTargetDragEvent evt)
4187   {
4188   }
4189
4190   public void dragExit(DropTargetEvent evt)
4191   {
4192   }
4193
4194   public void dragOver(DropTargetDragEvent evt)
4195   {
4196   }
4197
4198   public void dropActionChanged(DropTargetDragEvent evt)
4199   {
4200   }
4201
4202   public void drop(DropTargetDropEvent evt)
4203   {
4204     Transferable t = evt.getTransferable();
4205     java.util.List files = null;
4206
4207     try
4208     {
4209       DataFlavor uriListFlavor = new DataFlavor(
4210               "text/uri-list;class=java.lang.String");
4211       if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
4212       {
4213         // Works on Windows and MacOSX
4214         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4215         files = (java.util.List) t
4216                 .getTransferData(DataFlavor.javaFileListFlavor);
4217       }
4218       else if (t.isDataFlavorSupported(uriListFlavor))
4219       {
4220         // This is used by Unix drag system
4221         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4222         String data = (String) t.getTransferData(uriListFlavor);
4223         files = new java.util.ArrayList(1);
4224         for (java.util.StringTokenizer st = new java.util.StringTokenizer(
4225                 data, "\r\n"); st.hasMoreTokens();)
4226         {
4227           String s = st.nextToken();
4228           if (s.startsWith("#"))
4229           {
4230             // the line is a comment (as per the RFC 2483)
4231             continue;
4232           }
4233
4234           java.net.URI uri = new java.net.URI(s);
4235           // check to see if we can handle this kind of URI
4236           if (uri.getScheme().toLowerCase().startsWith("http"))
4237           {
4238             files.add(uri.toString());
4239           }
4240           else
4241           {
4242             // otherwise preserve old behaviour: catch all for file objects
4243             java.io.File file = new java.io.File(uri);
4244             files.add(file.toString());
4245           }
4246         }
4247       }
4248     } catch (Exception e)
4249     {
4250       e.printStackTrace();
4251     }
4252     if (files != null)
4253     {
4254       try
4255       {
4256
4257         for (int i = 0; i < files.size(); i++)
4258         {
4259           loadJalviewDataFile(files.get(i).toString());
4260         }
4261       } catch (Exception ex)
4262       {
4263         ex.printStackTrace();
4264       }
4265     }
4266   }
4267
4268   /**
4269    * Attempt to load a "dropped" file or URL string: First by testing whether
4270    * it's and Annotation file, then a JNet file, and finally a features file. If
4271    * all are false then the user may have dropped an alignment file onto this
4272    * AlignFrame.
4273    * 
4274    * @param file
4275    *          either a filename or a URL string.
4276    */
4277   public void loadJalviewDataFile(String file)
4278   {
4279     try
4280     {
4281       String protocol = jalview.io.FormatAdapter.FILE;
4282       String f = file.toLowerCase();
4283       if (f.indexOf("http:") == 0 || f.indexOf("https:") == 0
4284               || f.indexOf("file:") == 0)
4285       {
4286         protocol = jalview.io.FormatAdapter.URL;
4287       }
4288
4289       boolean isAnnotation = new AnnotationFile().readAnnotationFile(
4290               viewport.alignment, file, protocol);
4291
4292       if (!isAnnotation)
4293       {
4294         // try to see if its a JNet 'concise' style annotation file *before* we
4295         // try to parse it as a features file
4296         String format = new IdentifyFile().Identify(file, protocol);
4297         if (format.equalsIgnoreCase("JnetFile"))
4298         {
4299           jalview.io.JPredFile predictions = new jalview.io.JPredFile(file,
4300                   protocol);
4301           new JnetAnnotationMaker().add_annotation(predictions, viewport
4302                   .getAlignment(), 0, false);
4303           isAnnotation = true;
4304         }
4305         else
4306         {
4307           // try to parse it as a features file
4308           boolean isGroupsFile = parseFeaturesFile(file, protocol);
4309           // if it wasn't a features file then we just treat it as a general
4310           // alignment file to load into the current view.
4311           if (!isGroupsFile)
4312           {
4313             new FileLoader().LoadFile(viewport, file, protocol, format);
4314           }
4315           else
4316           {
4317             alignPanel.paintAlignment(true);
4318           }
4319         }
4320       }
4321       if (isAnnotation)
4322       {
4323
4324         alignPanel.adjustAnnotationHeight();
4325         viewport.updateSequenceIdColours();
4326         buildSortByAnnotationScoresMenu();
4327         alignPanel.paintAlignment(true);
4328       }
4329     } catch (Exception ex)
4330     {
4331       ex.printStackTrace();
4332     }
4333   }
4334
4335   public void tabSelectionChanged(int index)
4336   {
4337     if (index > -1)
4338     {
4339       alignPanel = (AlignmentPanel) alignPanels.elementAt(index);
4340       viewport = alignPanel.av;
4341       setMenusFromViewport(viewport);
4342     }
4343   }
4344
4345   public void tabbedPane_mousePressed(MouseEvent e)
4346   {
4347     if (SwingUtilities.isRightMouseButton(e))
4348     {
4349       String reply = JOptionPane.showInternalInputDialog(this,
4350               "Enter View Name", "Edit View Name",
4351               JOptionPane.QUESTION_MESSAGE);
4352
4353       if (reply != null)
4354       {
4355         viewport.viewName = reply;
4356         tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
4357       }
4358     }
4359   }
4360
4361   public AlignViewport getCurrentView()
4362   {
4363     return viewport;
4364   }
4365
4366   /**
4367    * Open the dialog for regex description parsing.
4368    */
4369   protected void extractScores_actionPerformed(ActionEvent e)
4370   {
4371     ParseProperties pp = new jalview.analysis.ParseProperties(
4372             viewport.alignment);
4373     // TODO: verify regex and introduce GUI dialog for version 2.5
4374     // if (pp.getScoresFromDescription("col", "score column ",
4375     // "\\W*([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)",
4376     // true)>0)
4377     if (pp.getScoresFromDescription("description column",
4378             "score in description column ", "\\W*([-+eE0-9.]+)", true) > 0)
4379     {
4380       buildSortByAnnotationScoresMenu();
4381     }
4382   }
4383
4384   /*
4385    * (non-Javadoc)
4386    * 
4387    * @see
4388    * jalview.jbgui.GAlignFrame#showDbRefs_actionPerformed(java.awt.event.ActionEvent
4389    * )
4390    */
4391   protected void showDbRefs_actionPerformed(ActionEvent e)
4392   {
4393     viewport.setShowDbRefs(showDbRefsMenuitem.isSelected());
4394   }
4395
4396   /*
4397    * (non-Javadoc)
4398    * 
4399    * @seejalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event.
4400    * ActionEvent)
4401    */
4402   protected void showNpFeats_actionPerformed(ActionEvent e)
4403   {
4404     viewport.setShowNpFeats(showNpFeatsMenuitem.isSelected());
4405   }
4406
4407   /**
4408    * find the viewport amongst the tabs in this alignment frame and close that
4409    * tab
4410    * 
4411    * @param av
4412    */
4413   public boolean closeView(AlignViewport av)
4414   {
4415     if (viewport == av)
4416     {
4417       this.closeMenuItem_actionPerformed(false);
4418       return true;
4419     }
4420     Component[] comp = tabbedPane.getComponents();
4421     for (int i = 0; comp != null && i < comp.length; i++)
4422     {
4423       if (comp[i] instanceof AlignmentPanel)
4424       {
4425         if (((AlignmentPanel) comp[i]).av == av)
4426         {
4427           // close the view.
4428           closeView((AlignmentPanel) comp[i]);
4429           return true;
4430         }
4431       }
4432     }
4433     return false;
4434   }
4435
4436   protected void build_fetchdbmenu(JMenu webService)
4437   {
4438     // Temporary hack - DBRef Fetcher always top level ws entry.
4439     // TODO We probably want to store a sequence database checklist in
4440     // preferences and have checkboxes.. rather than individual sources selected
4441     // here
4442     JMenu rfetch = new JMenu("Fetch DB References");
4443     rfetch
4444             .setToolTipText("Retrieve and parse sequence database records for the alignment or the currently selected sequences");
4445     webService.add(rfetch);
4446
4447     JMenuItem fetchr = new JMenuItem("Standard Databases");
4448     fetchr
4449             .setToolTipText("Fetch from EMBL/EMBLCDS or Uniprot/PDB and any selected DAS sources");
4450     fetchr.addActionListener(new ActionListener()
4451     {
4452
4453       public void actionPerformed(ActionEvent e)
4454       {
4455         new Thread(new Runnable()
4456         {
4457
4458           public void run()
4459           {
4460             new jalview.ws.DBRefFetcher(alignPanel.av
4461                     .getSequenceSelection(), alignPanel.alignFrame)
4462                     .fetchDBRefs(false);
4463           }
4464         }).start();
4465
4466       }
4467
4468     });
4469     rfetch.add(fetchr);
4470     JMenu dfetch = new JMenu();
4471     rfetch.add(dfetch);
4472     jalview.ws.SequenceFetcher sf = SequenceFetcher
4473             .getSequenceFetcherSingleton(this);
4474     String[] otherdb = sf.getOrderedSupportedSources();
4475     // sf.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);
4476     // jalview.util.QuickSort.sort(otherdb, otherdb);
4477     int comp = 0, mcomp = 15;
4478     String mname = null;
4479     if (otherdb != null && otherdb.length > 0)
4480     {
4481       for (int i = 0; i < otherdb.length; i++)
4482       {
4483         String dbname = sf.getSourceProxy(otherdb[i]).getDbName();
4484         if (mname == null)
4485         {
4486           mname = "from '" + dbname + "'";
4487         }
4488         fetchr = new JMenuItem(otherdb[i]);
4489         final String[] dassource = new String[]
4490         { otherdb[i] };
4491         fetchr.addActionListener(new ActionListener()
4492         {
4493
4494           public void actionPerformed(ActionEvent e)
4495           {
4496             new Thread(new Runnable()
4497             {
4498
4499               public void run()
4500               {
4501                 new jalview.ws.DBRefFetcher(alignPanel.av
4502                         .getSequenceSelection(), alignPanel.alignFrame,
4503                         dassource).fetchDBRefs(false);
4504               }
4505             }).start();
4506           }
4507
4508         });
4509         fetchr.setToolTipText("Retrieve from " + dbname);
4510         dfetch.add(fetchr);
4511         if (comp++ == mcomp || i == (otherdb.length - 1))
4512         {
4513           dfetch.setText(mname + " to '" + dbname + "'");
4514           rfetch.add(dfetch);
4515           dfetch = new JMenu();
4516           mname = null;
4517           comp = 0;
4518         }
4519       }
4520     }
4521   }
4522
4523   /**
4524    * Left justify the whole alignment.
4525    */
4526   protected void justifyLeftMenuItem_actionPerformed(ActionEvent e)
4527   {
4528     AlignmentI al = viewport.getAlignment();
4529     al.justify(false);
4530     viewport.firePropertyChange("alignment", null, al);
4531   }
4532
4533   /**
4534    * Right justify the whole alignment.
4535    */
4536   protected void justifyRightMenuItem_actionPerformed(ActionEvent e)
4537   {
4538     AlignmentI al = viewport.getAlignment();
4539     al.justify(true);
4540     viewport.firePropertyChange("alignment", null, al);
4541   }
4542
4543   public void setShowSeqFeatures(boolean b)
4544   {
4545     showSeqFeatures.setSelected(true);
4546     viewport.setShowSequenceFeatures(true);
4547   }
4548
4549   /*
4550    * (non-Javadoc)
4551    * 
4552    * @see
4553    * jalview.jbgui.GAlignFrame#showUnconservedMenuItem_actionPerformed(java.
4554    * awt.event.ActionEvent)
4555    */
4556   protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)
4557   {
4558     viewport.setShowUnconserved(showUnconservedMenuItem.getState());
4559     alignPanel.paintAlignment(true);
4560   }
4561
4562   /*
4563    * (non-Javadoc)
4564    * 
4565    * @see
4566    * jalview.jbgui.GAlignFrame#showGroupConsensus_actionPerformed(java.awt.event
4567    * .ActionEvent)
4568    */
4569   protected void showGroupConsensus_actionPerformed(ActionEvent e)
4570   {
4571     viewport.setShowGroupConsensus(showGroupConsensus.getState());
4572     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4573
4574   }
4575
4576   /*
4577    * (non-Javadoc)
4578    * 
4579    * @see
4580    * jalview.jbgui.GAlignFrame#showGroupConservation_actionPerformed(java.awt
4581    * .event.ActionEvent)
4582    */
4583   protected void showGroupConservation_actionPerformed(ActionEvent e)
4584   {
4585     viewport.setShowGroupConservation(showGroupConservation.getState());
4586     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4587   }
4588
4589   /*
4590    * (non-Javadoc)
4591    * 
4592    * @see
4593    * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt
4594    * .event.ActionEvent)
4595    */
4596   protected void showConsensusHistogram_actionPerformed(ActionEvent e)
4597   {
4598     viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
4599     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4600   }
4601
4602   /*
4603    * (non-Javadoc)
4604    * 
4605    * @see
4606    * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt
4607    * .event.ActionEvent)
4608    */
4609   protected void showSequenceLogo_actionPerformed(ActionEvent e)
4610   {
4611     viewport.setShowSequenceLogo(showSequenceLogo.getState());
4612     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4613   }
4614
4615   protected void applyAutoAnnotationSettings_actionPerformed(ActionEvent e)
4616   {
4617     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4618   }
4619
4620   /*
4621    * (non-Javadoc)
4622    * 
4623    * @see
4624    * jalview.jbgui.GAlignFrame#makeGrpsFromSelection_actionPerformed(java.awt
4625    * .event.ActionEvent)
4626    */
4627   protected void makeGrpsFromSelection_actionPerformed(ActionEvent e)
4628   {
4629     if (viewport.getSelectionGroup() != null)
4630     {
4631       SequenceGroup[] gps = jalview.analysis.Grouping.makeGroupsFrom(
4632               viewport.getSequenceSelection(), viewport.getAlignmentView(
4633                       true).getSequenceStrings(viewport.getGapCharacter()),
4634               viewport.alignment.getGroups());
4635       viewport.alignment.deleteAllGroups();
4636       viewport.sequenceColours = null;
4637       viewport.setSelectionGroup(null);
4638       // set view properties for each group
4639       for (int g = 0; g < gps.length; g++)
4640       {
4641         gps[g].setShowunconserved(viewport.getShowUnconserved());
4642         gps[g].setIncludeAllConsSymbols(viewport
4643                 .isIncludeAllConsensusSymbols());
4644         viewport.alignment.addGroup(gps[g]);
4645         Color col = new Color((int) (Math.random() * 255), (int) (Math
4646                 .random() * 255), (int) (Math.random() * 255));
4647         col = col.brighter();
4648         for (Enumeration sq = gps[g].getSequences(null).elements(); sq
4649                 .hasMoreElements(); viewport.setSequenceColour(
4650                 (SequenceI) sq.nextElement(), col))
4651           ;
4652       }
4653       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
4654       alignPanel.updateAnnotation();
4655       alignPanel.paintAlignment(true);
4656     }
4657   }
4658 }
4659
4660 class PrintThread extends Thread
4661 {
4662   AlignmentPanel ap;
4663
4664   public PrintThread(AlignmentPanel ap)
4665   {
4666     this.ap = ap;
4667   }
4668
4669   static PageFormat pf;
4670
4671   public void run()
4672   {
4673     PrinterJob printJob = PrinterJob.getPrinterJob();
4674
4675     if (pf != null)
4676     {
4677       printJob.setPrintable(ap, pf);
4678     }
4679     else
4680     {
4681       printJob.setPrintable(ap);
4682     }
4683
4684     if (printJob.printDialog())
4685     {
4686       try
4687       {
4688         printJob.print();
4689       } catch (Exception PrintException)
4690       {
4691         PrintException.printStackTrace();
4692       }
4693     }
4694   }
4695 }