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