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