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