JAL-1114 - refactor methods handling Vectors and Hashtables to Lists and Maps, and...
[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.colourAppliesToAllGroups);
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       Enumeration sq = viewport.getAlignment().getSequences().elements();
3711       while (sq.hasMoreElements())
3712       {
3713         aann = ((SequenceI) sq.nextElement()).getAnnotation();
3714         for (int i = 0; aann != null && i < aann.length; i++)
3715         {
3716           if (aann[i].hasScore() && aann[i].sequenceRef != null)
3717           {
3718             scoreSorts.put(aann[i].label, aann[i].label);
3719           }
3720         }
3721       }
3722       Enumeration labels = scoreSorts.keys();
3723       while (labels.hasMoreElements())
3724       {
3725         addSortByAnnotScoreMenuItem(sortByAnnotScore,
3726                 (String) labels.nextElement());
3727       }
3728       sortByAnnotScore.setVisible(scoreSorts.size() > 0);
3729       scoreSorts.clear();
3730
3731       _annotationScoreVectorHash = viewport.getAlignment()
3732               .getAlignmentAnnotation().hashCode();
3733     }
3734   }
3735
3736   /**
3737    * Maintain the Order by->Displayed Tree menu. Creates a new menu item for a
3738    * TreePanel with an appropriate <code>jalview.analysis.AlignmentSorter</code>
3739    * call. Listeners are added to remove the menu item when the treePanel is
3740    * closed, and adjust the tree leaf to sequence mapping when the alignment is
3741    * modified.
3742    * 
3743    * @param treePanel
3744    *          Displayed tree window.
3745    * @param title
3746    *          SortBy menu item title.
3747    */
3748   public void buildTreeMenu()
3749   {
3750     sortByTreeMenu.removeAll();
3751
3752     Vector comps = (Vector) PaintRefresher.components.get(viewport
3753             .getSequenceSetId());
3754     Vector treePanels = new Vector();
3755     int i, iSize = comps.size();
3756     for (i = 0; i < iSize; i++)
3757     {
3758       if (comps.elementAt(i) instanceof TreePanel)
3759       {
3760         treePanels.add(comps.elementAt(i));
3761       }
3762     }
3763
3764     iSize = treePanels.size();
3765
3766     if (iSize < 1)
3767     {
3768       sortByTreeMenu.setVisible(false);
3769       return;
3770     }
3771
3772     sortByTreeMenu.setVisible(true);
3773
3774     for (i = 0; i < treePanels.size(); i++)
3775     {
3776       final TreePanel tp = (TreePanel) treePanels.elementAt(i);
3777       final JMenuItem item = new JMenuItem(tp.getTitle());
3778       final NJTree tree = ((TreePanel) treePanels.elementAt(i)).getTree();
3779       item.addActionListener(new java.awt.event.ActionListener()
3780       {
3781         public void actionPerformed(ActionEvent e)
3782         {
3783           tp.sortByTree_actionPerformed(null);
3784           addHistoryItem(tp.sortAlignmentIn(alignPanel));
3785
3786         }
3787       });
3788
3789       sortByTreeMenu.add(item);
3790     }
3791   }
3792
3793   public boolean sortBy(AlignmentOrder alorder, String undoname)
3794   {
3795     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3796     AlignmentSorter.sortBy(viewport.getAlignment(), alorder);
3797     if (undoname != null)
3798     {
3799       addHistoryItem(new OrderCommand(undoname, oldOrder,
3800               viewport.getAlignment()));
3801     }
3802     alignPanel.paintAlignment(true);
3803     return true;
3804   }
3805
3806   /**
3807    * Work out whether the whole set of sequences or just the selected set will
3808    * be submitted for multiple alignment.
3809    * 
3810    */
3811   public jalview.datamodel.AlignmentView gatherSequencesForAlignment()
3812   {
3813     // Now, check we have enough sequences
3814     AlignmentView msa = null;
3815
3816     if ((viewport.getSelectionGroup() != null)
3817             && (viewport.getSelectionGroup().getSize() > 1))
3818     {
3819       // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to
3820       // some common interface!
3821       /*
3822        * SequenceGroup seqs = viewport.getSelectionGroup(); int sz; msa = new
3823        * SequenceI[sz = seqs.getSize(false)];
3824        * 
3825        * for (int i = 0; i < sz; i++) { msa[i] = (SequenceI)
3826        * seqs.getSequenceAt(i); }
3827        */
3828       msa = viewport.getAlignmentView(true);
3829     }
3830     else
3831     {
3832       /*
3833        * Vector seqs = viewport.getAlignment().getSequences();
3834        * 
3835        * if (seqs.size() > 1) { msa = new SequenceI[seqs.size()];
3836        * 
3837        * for (int i = 0; i < seqs.size(); i++) { msa[i] = (SequenceI)
3838        * seqs.elementAt(i); } }
3839        */
3840       msa = viewport.getAlignmentView(false);
3841     }
3842     return msa;
3843   }
3844
3845   /**
3846    * Decides what is submitted to a secondary structure prediction service: the
3847    * first sequence in the alignment, or in the current selection, or, if the
3848    * alignment is 'aligned' (ie padded with gaps), then the currently selected
3849    * region or the whole alignment. (where the first sequence in the set is the
3850    * one that the prediction will be for).
3851    */
3852   public AlignmentView gatherSeqOrMsaForSecStrPrediction()
3853   {
3854     AlignmentView seqs = null;
3855
3856     if ((viewport.getSelectionGroup() != null)
3857             && (viewport.getSelectionGroup().getSize() > 0))
3858     {
3859       seqs = viewport.getAlignmentView(true);
3860     }
3861     else
3862     {
3863       seqs = viewport.getAlignmentView(false);
3864     }
3865     // limit sequences - JBPNote in future - could spawn multiple prediction
3866     // jobs
3867     // TODO: viewport.getAlignment().isAligned is a global state - the local
3868     // selection may well be aligned - we preserve 2.0.8 behaviour for moment.
3869     if (!viewport.getAlignment().isAligned(false))
3870     {
3871       seqs.setSequences(new SeqCigar[]
3872       { seqs.getSequences()[0] });
3873       // TODO: if seqs.getSequences().length>1 then should really have warned
3874       // user!
3875
3876     }
3877     return seqs;
3878   }
3879
3880   /**
3881    * DOCUMENT ME!
3882    * 
3883    * @param e
3884    *          DOCUMENT ME!
3885    */
3886   protected void LoadtreeMenuItem_actionPerformed(ActionEvent e)
3887   {
3888     // Pick the tree file
3889     JalviewFileChooser chooser = new JalviewFileChooser(
3890             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
3891     chooser.setFileView(new JalviewFileView());
3892     chooser.setDialogTitle("Select a newick-like tree file");
3893     chooser.setToolTipText("Load a tree file");
3894
3895     int value = chooser.showOpenDialog(null);
3896
3897     if (value == JalviewFileChooser.APPROVE_OPTION)
3898     {
3899       String choice = chooser.getSelectedFile().getPath();
3900       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
3901       jalview.io.NewickFile fin = null;
3902       try
3903       {
3904         fin = new jalview.io.NewickFile(choice, "File");
3905         viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
3906       } catch (Exception ex)
3907       {
3908         JOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(),
3909                 "Problem reading tree file", JOptionPane.WARNING_MESSAGE);
3910         ex.printStackTrace();
3911       }
3912       if (fin != null && fin.hasWarningMessage())
3913       {
3914         JOptionPane.showMessageDialog(Desktop.desktop,
3915                 fin.getWarningMessage(), "Possible problem with tree file",
3916                 JOptionPane.WARNING_MESSAGE);
3917       }
3918     }
3919   }
3920
3921   @Override
3922   protected void tcoffeeColorScheme_actionPerformed(ActionEvent e)
3923   {
3924     changeColour(new TCoffeeColourScheme(alignPanel.getAlignment()));
3925   }
3926
3927   public TreePanel ShowNewickTree(NewickFile nf, String title)
3928   {
3929     return ShowNewickTree(nf, title, 600, 500, 4, 5);
3930   }
3931
3932   public TreePanel ShowNewickTree(NewickFile nf, String title,
3933           AlignmentView input)
3934   {
3935     return ShowNewickTree(nf, title, input, 600, 500, 4, 5);
3936   }
3937
3938   public TreePanel ShowNewickTree(NewickFile nf, String title, int w,
3939           int h, int x, int y)
3940   {
3941     return ShowNewickTree(nf, title, null, w, h, x, y);
3942   }
3943
3944   /**
3945    * Add a treeviewer for the tree extracted from a newick file object to the
3946    * current alignment view
3947    * 
3948    * @param nf
3949    *          the tree
3950    * @param title
3951    *          tree viewer title
3952    * @param input
3953    *          Associated alignment input data (or null)
3954    * @param w
3955    *          width
3956    * @param h
3957    *          height
3958    * @param x
3959    *          position
3960    * @param y
3961    *          position
3962    * @return TreePanel handle
3963    */
3964   public TreePanel ShowNewickTree(NewickFile nf, String title,
3965           AlignmentView input, int w, int h, int x, int y)
3966   {
3967     TreePanel tp = null;
3968
3969     try
3970     {
3971       nf.parse();
3972
3973       if (nf.getTree() != null)
3974       {
3975         tp = new TreePanel(alignPanel, "FromFile", title, nf, input);
3976
3977         tp.setSize(w, h);
3978
3979         if (x > 0 && y > 0)
3980         {
3981           tp.setLocation(x, y);
3982         }
3983
3984         Desktop.addInternalFrame(tp, title, w, h);
3985       }
3986     } catch (Exception ex)
3987     {
3988       ex.printStackTrace();
3989     }
3990
3991     return tp;
3992   }
3993
3994   private boolean buildingMenu = false;
3995
3996   /**
3997    * Generates menu items and listener event actions for web service clients
3998    * 
3999    */
4000   public void BuildWebServiceMenu()
4001   {
4002     while (buildingMenu)
4003     {
4004       try
4005       {
4006         System.err.println("Waiting for building menu to finish.");
4007         Thread.sleep(10);
4008       } catch (Exception e)
4009       {
4010       }
4011       ;
4012     }
4013     final AlignFrame me = this;
4014     buildingMenu = true;
4015     new Thread(new Runnable()
4016     {
4017       public void run()
4018       {
4019         try
4020         {
4021           System.err.println("Building ws menu again "
4022                   + Thread.currentThread());
4023           // TODO: add support for context dependent disabling of services based
4024           // on
4025           // alignment and current selection
4026           // TODO: add additional serviceHandle parameter to specify abstract
4027           // handler
4028           // class independently of AbstractName
4029           // TODO: add in rediscovery GUI function to restart discoverer
4030           // TODO: group services by location as well as function and/or
4031           // introduce
4032           // object broker mechanism.
4033           final Vector<JMenu> wsmenu = new Vector<JMenu>();
4034           final IProgressIndicator af = me;
4035           final JMenu msawsmenu = new JMenu("Alignment");
4036           final JMenu secstrmenu = new JMenu(
4037                   "Secondary Structure Prediction");
4038           final JMenu seqsrchmenu = new JMenu("Sequence Database Search");
4039           final JMenu analymenu = new JMenu("Analysis");
4040           final JMenu dismenu = new JMenu("Disorder");
4041           // JAL-940 - only show secondary structure prediction services from
4042           // the legacy server
4043           if (// Cache.getDefault("SHOW_JWS1_SERVICES", true)
4044               // &&
4045           Discoverer.services != null && (Discoverer.services.size() > 0))
4046           {
4047             // TODO: refactor to allow list of AbstractName/Handler bindings to
4048             // be
4049             // stored or retrieved from elsewhere
4050             Vector msaws = null; // (Vector) Discoverer.services.get("MsaWS");
4051             Vector secstrpr = (Vector) Discoverer.services
4052                     .get("SecStrPred");
4053             Vector seqsrch = null; // (Vector)
4054                                    // Discoverer.services.get("SeqSearch");
4055             // TODO: move GUI generation code onto service implementation - so a
4056             // client instance attaches itself to the GUI with method call like
4057             // jalview.ws.MsaWSClient.bind(servicehandle, Desktop.instance,
4058             // alignframe)
4059             if (msaws != null)
4060             {
4061               // Add any Multiple Sequence Alignment Services
4062               for (int i = 0, j = msaws.size(); i < j; i++)
4063               {
4064                 final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) msaws
4065                         .get(i);
4066                 jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
4067                         .getServiceClient(sh);
4068                 impl.attachWSMenuEntry(msawsmenu, me);
4069
4070               }
4071             }
4072             if (secstrpr != null)
4073             {
4074               // Add any secondary structure prediction services
4075               for (int i = 0, j = secstrpr.size(); i < j; i++)
4076               {
4077                 final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr
4078                         .get(i);
4079                 jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
4080                         .getServiceClient(sh);
4081                 impl.attachWSMenuEntry(secstrmenu, me);
4082               }
4083             }
4084             if (seqsrch != null)
4085             {
4086               // Add any sequence search services
4087               for (int i = 0, j = seqsrch.size(); i < j; i++)
4088               {
4089                 final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) seqsrch
4090                         .elementAt(i);
4091                 jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
4092                         .getServiceClient(sh);
4093                 impl.attachWSMenuEntry(seqsrchmenu, me);
4094               }
4095             }
4096           }
4097
4098           // Add all submenus in the order they should appear on the web
4099           // services menu
4100           wsmenu.add(msawsmenu);
4101           wsmenu.add(secstrmenu);
4102           wsmenu.add(dismenu);
4103           wsmenu.add(analymenu);
4104           // final ArrayList<JMenu> submens=new ArrayList<JMenu>();
4105           // submens.add(msawsmenu);
4106           // submens.add(secstrmenu);
4107           // submens.add(dismenu);
4108           // submens.add(analymenu);
4109
4110           // No search services yet
4111           // wsmenu.add(seqsrchmenu);
4112
4113           javax.swing.SwingUtilities.invokeLater(new Runnable()
4114           {
4115             public void run()
4116             {
4117               try
4118               {
4119                 webService.removeAll();
4120                 // first, add discovered services onto the webservices menu
4121                 if (wsmenu.size() > 0)
4122                 {
4123                   for (int i = 0, j = wsmenu.size(); i < j; i++)
4124                   {
4125                     webService.add((JMenu) wsmenu.get(i));
4126                   }
4127                 }
4128                 else
4129                 {
4130                   webService.add(me.webServiceNoServices);
4131                 }
4132                 // TODO: move into separate menu builder class.
4133                 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
4134                 {
4135                   Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer();
4136                   if (jws2servs != null)
4137                   {
4138                     if (jws2servs.hasServices())
4139                     {
4140                       jws2servs.attachWSMenuEntry(webService, me);
4141                     }
4142                     if (jws2servs.isRunning())
4143                     {
4144                       JMenuItem tm = new JMenuItem(
4145                               "Still discovering JABA Services");
4146                       tm.setEnabled(false);
4147                       webService.add(tm);
4148                     }
4149                   }
4150                 }
4151
4152                 build_urlServiceMenu(me.webService);
4153                 build_fetchdbmenu(webService);
4154                 for (JMenu item : wsmenu)
4155                 {
4156                   if (item.getItemCount() == 0)
4157                   {
4158                     item.setEnabled(false);
4159                   }
4160                   else
4161                   {
4162                     item.setEnabled(true);
4163                   }
4164                 }
4165               } catch (Exception e)
4166               {
4167               }
4168               ;
4169             }
4170           });
4171         } catch (Exception e)
4172         {
4173         }
4174         ;
4175
4176         buildingMenu = false;
4177       }
4178     }).start();
4179
4180   }
4181
4182   /**
4183    * construct any groupURL type service menu entries.
4184    * 
4185    * @param webService
4186    */
4187   private void build_urlServiceMenu(JMenu webService)
4188   {
4189     // TODO: remove this code when 2.7 is released
4190     // DEBUG - alignmentView
4191     /*
4192      * JMenuItem testAlView = new JMenuItem("Test AlignmentView"); final
4193      * AlignFrame af = this; testAlView.addActionListener(new ActionListener() {
4194      * 
4195      * @Override public void actionPerformed(ActionEvent e) {
4196      * jalview.datamodel.AlignmentView
4197      * .testSelectionViews(af.viewport.getAlignment(),
4198      * af.viewport.getColumnSelection(), af.viewport.selectionGroup); }
4199      * 
4200      * }); webService.add(testAlView);
4201      */
4202     // TODO: refactor to RestClient discoverer and merge menu entries for
4203     // rest-style services with other types of analysis/calculation service
4204     // SHmmr test client - still being implemented.
4205     // DEBUG - alignmentView
4206
4207     for (jalview.ws.rest.RestClient client : jalview.ws.rest.RestClient
4208             .getRestClients())
4209     {
4210       client.attachWSMenuEntry(
4211               JvSwingUtils.findOrCreateMenu(webService, client.getAction()),
4212               this);
4213     }
4214
4215     if (Cache.getDefault("SHOW_ENFIN_SERVICES", true))
4216     {
4217       jalview.ws.EnfinEnvision2OneWay.getInstance().attachWSMenuEntry(
4218               webService, this);
4219     }
4220   }
4221
4222   /*
4223    * public void vamsasStore_actionPerformed(ActionEvent e) { JalviewFileChooser
4224    * chooser = new JalviewFileChooser(jalview.bin.Cache.
4225    * getProperty("LAST_DIRECTORY"));
4226    * 
4227    * chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle("Export
4228    * to Vamsas file"); chooser.setToolTipText("Export");
4229    * 
4230    * int value = chooser.showSaveDialog(this);
4231    * 
4232    * if (value == JalviewFileChooser.APPROVE_OPTION) {
4233    * jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport);
4234    * //vs.store(chooser.getSelectedFile().getAbsolutePath() ); vs.storeJalview(
4235    * chooser.getSelectedFile().getAbsolutePath(), this); } }
4236    */
4237   /**
4238    * prototype of an automatically enabled/disabled analysis function
4239    * 
4240    */
4241   protected void setShowProductsEnabled()
4242   {
4243     SequenceI[] selection = viewport.getSequenceSelection();
4244     if (canShowProducts(selection, viewport.getSelectionGroup() != null,
4245             viewport.getAlignment().getDataset()))
4246     {
4247       showProducts.setEnabled(true);
4248
4249     }
4250     else
4251     {
4252       showProducts.setEnabled(false);
4253     }
4254   }
4255
4256   /**
4257    * search selection for sequence xRef products and build the show products
4258    * menu.
4259    * 
4260    * @param selection
4261    * @param dataset
4262    * @return true if showProducts menu should be enabled.
4263    */
4264   public boolean canShowProducts(SequenceI[] selection,
4265           boolean isRegionSelection, Alignment dataset)
4266   {
4267     boolean showp = false;
4268     try
4269     {
4270       showProducts.removeAll();
4271       final boolean dna = viewport.getAlignment().isNucleotide();
4272       final Alignment ds = dataset;
4273       String[] ptypes = (selection == null || selection.length == 0) ? null
4274               : CrossRef.findSequenceXrefTypes(dna, selection, dataset);
4275       // Object[] prods =
4276       // CrossRef.buildXProductsList(viewport.getAlignment().isNucleotide(),
4277       // selection, dataset, true);
4278       final SequenceI[] sel = selection;
4279       for (int t = 0; ptypes != null && t < ptypes.length; t++)
4280       {
4281         showp = true;
4282         final boolean isRegSel = isRegionSelection;
4283         final AlignFrame af = this;
4284         final String source = ptypes[t];
4285         JMenuItem xtype = new JMenuItem(ptypes[t]);
4286         xtype.addActionListener(new ActionListener()
4287         {
4288
4289           public void actionPerformed(ActionEvent e)
4290           {
4291             // TODO: new thread for this call with vis-delay
4292             af.showProductsFor(af.viewport.getSequenceSelection(), ds,
4293                     isRegSel, dna, source);
4294           }
4295
4296         });
4297         showProducts.add(xtype);
4298       }
4299       showProducts.setVisible(showp);
4300       showProducts.setEnabled(showp);
4301     } catch (Exception e)
4302     {
4303       jalview.bin.Cache.log
4304               .warn("canTranslate threw an exception - please report to help@jalview.org",
4305                       e);
4306       return false;
4307     }
4308     return showp;
4309   }
4310
4311   protected void showProductsFor(SequenceI[] sel, Alignment ds,
4312           boolean isRegSel, boolean dna, String source)
4313   {
4314     final boolean fisRegSel = isRegSel;
4315     final boolean fdna = dna;
4316     final String fsrc = source;
4317     final AlignFrame ths = this;
4318     final SequenceI[] fsel = sel;
4319     Runnable foo = new Runnable()
4320     {
4321
4322       public void run()
4323       {
4324         final long sttime = System.currentTimeMillis();
4325         ths.setProgressBar("Searching for sequences from " + fsrc, sttime);
4326         try
4327         {
4328           Alignment ds = ths.getViewport().getAlignment().getDataset(); // update
4329           // our local
4330           // dataset
4331           // reference
4332           Alignment prods = CrossRef
4333                   .findXrefSequences(fsel, fdna, fsrc, ds);
4334           if (prods != null)
4335           {
4336             SequenceI[] sprods = new SequenceI[prods.getHeight()];
4337             for (int s = 0; s < sprods.length; s++)
4338             {
4339               sprods[s] = (prods.getSequenceAt(s)).deriveSequence();
4340               if (ds.getSequences() == null
4341                       || !ds.getSequences().contains(
4342                               sprods[s].getDatasetSequence()))
4343                 ds.addSequence(sprods[s].getDatasetSequence());
4344               sprods[s].updatePDBIds();
4345             }
4346             Alignment al = new Alignment(sprods);
4347             AlignedCodonFrame[] cf = prods.getCodonFrames();
4348             al.setDataset(ds);
4349             for (int s = 0; cf != null && s < cf.length; s++)
4350             {
4351               al.addCodonFrame(cf[s]);
4352               cf[s] = null;
4353             }
4354             AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH,
4355                     DEFAULT_HEIGHT);
4356             String newtitle = "" + ((fdna) ? "Proteins " : "Nucleotides ")
4357                     + " for " + ((fisRegSel) ? "selected region of " : "")
4358                     + getTitle();
4359             Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,
4360                     DEFAULT_HEIGHT);
4361           }
4362           else
4363           {
4364             System.err.println("No Sequences generated for xRef type "
4365                     + fsrc);
4366           }
4367         } catch (Exception e)
4368         {
4369           jalview.bin.Cache.log.error(
4370                   "Exception when finding crossreferences", e);
4371         } catch (OutOfMemoryError e)
4372         {
4373           new OOMWarning("whilst fetching crossreferences", e);
4374         } catch (Error e)
4375         {
4376           jalview.bin.Cache.log.error("Error when finding crossreferences",
4377                   e);
4378         }
4379         ths.setProgressBar("Finished searching for sequences from " + fsrc,
4380                 sttime);
4381       }
4382
4383     };
4384     Thread frunner = new Thread(foo);
4385     frunner.start();
4386   }
4387
4388   public boolean canShowTranslationProducts(SequenceI[] selection,
4389           AlignmentI alignment)
4390   {
4391     // old way
4392     try
4393     {
4394       return (jalview.analysis.Dna.canTranslate(selection,
4395               viewport.getViewAsVisibleContigs(true)));
4396     } catch (Exception e)
4397     {
4398       jalview.bin.Cache.log
4399               .warn("canTranslate threw an exception - please report to help@jalview.org",
4400                       e);
4401       return false;
4402     }
4403   }
4404
4405   public void showProducts_actionPerformed(ActionEvent e)
4406   {
4407     // /////////////////////////////
4408     // Collect Data to be translated/transferred
4409
4410     SequenceI[] selection = viewport.getSequenceSelection();
4411     AlignmentI al = null;
4412     try
4413     {
4414       al = jalview.analysis.Dna.CdnaTranslate(selection, viewport
4415               .getViewAsVisibleContigs(true), viewport.getGapCharacter(),
4416               viewport.getAlignment().getDataset());
4417     } catch (Exception ex)
4418     {
4419       al = null;
4420       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4421     }
4422     if (al == null)
4423     {
4424       JOptionPane
4425               .showMessageDialog(
4426                       Desktop.desktop,
4427                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4428                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4429     }
4430     else
4431     {
4432       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4433       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4434               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4435     }
4436   }
4437
4438   public void showTranslation_actionPerformed(ActionEvent e)
4439   {
4440     // /////////////////////////////
4441     // Collect Data to be translated/transferred
4442
4443     SequenceI[] selection = viewport.getSequenceSelection();
4444     String[] seqstring = viewport.getViewAsString(true);
4445     AlignmentI al = null;
4446     try
4447     {
4448       al = jalview.analysis.Dna.CdnaTranslate(selection, seqstring,
4449               viewport.getViewAsVisibleContigs(true), viewport
4450                       .getGapCharacter(), viewport.getAlignment()
4451                       .getAlignmentAnnotation(), viewport.getAlignment()
4452                       .getWidth(), viewport.getAlignment().getDataset());
4453     } catch (Exception ex)
4454     {
4455       al = null;
4456       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4457     }
4458     if (al == null)
4459     {
4460       JOptionPane
4461               .showMessageDialog(
4462                       Desktop.desktop,
4463                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4464                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4465     }
4466     else
4467     {
4468       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4469       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4470               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4471     }
4472   }
4473
4474   /**
4475    * Try to load a features file onto the alignment.
4476    * 
4477    * @param file
4478    *          contents or path to retrieve file
4479    * @param type
4480    *          access mode of file (see jalview.io.AlignFile)
4481    * @return true if features file was parsed corectly.
4482    */
4483   public boolean parseFeaturesFile(String file, String type)
4484   {
4485     boolean featuresFile = false;
4486     try
4487     {
4488       featuresFile = new FeaturesFile(file, type).parse(viewport
4489               .getAlignment().getDataset(), alignPanel.seqPanel.seqCanvas
4490               .getFeatureRenderer().featureColours, false,
4491               jalview.bin.Cache.getDefault("RELAXEDSEQIDMATCHING", false));
4492     } catch (Exception ex)
4493     {
4494       ex.printStackTrace();
4495     }
4496
4497     if (featuresFile)
4498     {
4499       viewport.showSequenceFeatures = true;
4500       showSeqFeatures.setSelected(true);
4501       if (alignPanel.seqPanel.seqCanvas.fr != null)
4502       {
4503         // update the min/max ranges where necessary
4504         alignPanel.seqPanel.seqCanvas.fr.findAllFeatures(true);
4505       }
4506       if (featureSettings != null)
4507       {
4508         featureSettings.setTableData();
4509       }
4510       alignPanel.paintAlignment(true);
4511     }
4512
4513     return featuresFile;
4514   }
4515
4516   public void dragEnter(DropTargetDragEvent evt)
4517   {
4518   }
4519
4520   public void dragExit(DropTargetEvent evt)
4521   {
4522   }
4523
4524   public void dragOver(DropTargetDragEvent evt)
4525   {
4526   }
4527
4528   public void dropActionChanged(DropTargetDragEvent evt)
4529   {
4530   }
4531
4532   public void drop(DropTargetDropEvent evt)
4533   {
4534     Transferable t = evt.getTransferable();
4535     java.util.List files = null;
4536
4537     try
4538     {
4539       DataFlavor uriListFlavor = new DataFlavor(
4540               "text/uri-list;class=java.lang.String");
4541       if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
4542       {
4543         // Works on Windows and MacOSX
4544         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4545         files = (java.util.List) t
4546                 .getTransferData(DataFlavor.javaFileListFlavor);
4547       }
4548       else if (t.isDataFlavorSupported(uriListFlavor))
4549       {
4550         // This is used by Unix drag system
4551         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4552         String data = (String) t.getTransferData(uriListFlavor);
4553         files = new java.util.ArrayList(1);
4554         for (java.util.StringTokenizer st = new java.util.StringTokenizer(
4555                 data, "\r\n"); st.hasMoreTokens();)
4556         {
4557           String s = st.nextToken();
4558           if (s.startsWith("#"))
4559           {
4560             // the line is a comment (as per the RFC 2483)
4561             continue;
4562           }
4563
4564           java.net.URI uri = new java.net.URI(s);
4565           // check to see if we can handle this kind of URI
4566           if (uri.getScheme().toLowerCase().startsWith("http"))
4567           {
4568             files.add(uri.toString());
4569           }
4570           else
4571           {
4572             // otherwise preserve old behaviour: catch all for file objects
4573             java.io.File file = new java.io.File(uri);
4574             files.add(file.toString());
4575           }
4576         }
4577       }
4578     } catch (Exception e)
4579     {
4580       e.printStackTrace();
4581     }
4582     if (files != null)
4583     {
4584       try
4585       {
4586         // check to see if any of these files have names matching sequences in
4587         // the alignment
4588         SequenceIdMatcher idm = new SequenceIdMatcher(viewport
4589                 .getAlignment().getSequencesArray());
4590         /**
4591          * Object[] { String,SequenceI}
4592          */
4593         ArrayList<Object[]> filesmatched = new ArrayList<Object[]>();
4594         ArrayList<String> filesnotmatched = new ArrayList<String>();
4595         for (int i = 0; i < files.size(); i++)
4596         {
4597           String file = files.get(i).toString();
4598           String pdbfn = "";
4599           String protocol = FormatAdapter.checkProtocol(file);
4600           if (protocol == jalview.io.FormatAdapter.FILE)
4601           {
4602             File fl = new File(file);
4603             pdbfn = fl.getName();
4604           }
4605           else if (protocol == jalview.io.FormatAdapter.URL)
4606           {
4607             URL url = new URL(file);
4608             pdbfn = url.getFile();
4609           }
4610           if (pdbfn.length() > 0)
4611           {
4612             // attempt to find a match in the alignment
4613             SequenceI[] mtch = idm.findAllIdMatches(pdbfn);
4614             int l = 0, c = pdbfn.indexOf(".");
4615             while (mtch == null && c != -1)
4616             {
4617               do
4618               {
4619                 l = c;
4620               } while ((c = pdbfn.indexOf(".", l)) > l);
4621               if (l > -1)
4622               {
4623                 pdbfn = pdbfn.substring(0, l);
4624               }
4625               mtch = idm.findAllIdMatches(pdbfn);
4626             }
4627             if (mtch != null)
4628             {
4629               String type = null;
4630               try
4631               {
4632                 type = new IdentifyFile().Identify(file, protocol);
4633               } catch (Exception ex)
4634               {
4635                 type = null;
4636               }
4637               if (type != null)
4638               {
4639                 if (type.equalsIgnoreCase("PDB"))
4640                 {
4641                   filesmatched.add(new Object[]
4642                   { file, protocol, mtch });
4643                   continue;
4644                 }
4645               }
4646             }
4647             // File wasn't named like one of the sequences or wasn't a PDB file.
4648             filesnotmatched.add(file);
4649           }
4650         }
4651         int assocfiles = 0;
4652         if (filesmatched.size() > 0)
4653         {
4654           if (Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false)
4655                   || JOptionPane
4656                           .showConfirmDialog(
4657                                   this,
4658                                   "Do you want to automatically associate the "
4659                                           + filesmatched.size()
4660                                           + " PDB files with sequences in the alignment that have the same name ?",
4661                                   "Automatically Associate PDB files by name",
4662                                   JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
4663
4664           {
4665             for (Object[] fm : filesmatched)
4666             {
4667               // try and associate
4668               // TODO: may want to set a standard ID naming formalism for
4669               // associating PDB files which have no IDs.
4670               for (SequenceI toassoc : (SequenceI[]) fm[2])
4671               {
4672                 PDBEntry pe = new AssociatePdbFileWithSeq()
4673                         .associatePdbWithSeq((String) fm[0],
4674                                 (String) fm[1], toassoc, false);
4675                 if (pe != null)
4676                 {
4677                   System.err.println("Associated file : "
4678                           + ((String) fm[0]) + " with "
4679                           + toassoc.getDisplayId(true));
4680                   assocfiles++;
4681                 }
4682               }
4683               alignPanel.paintAlignment(true);
4684             }
4685           }
4686         }
4687         if (filesnotmatched.size() > 0)
4688         {
4689           if (assocfiles > 0
4690                   && (Cache.getDefault(
4691                           "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false) || JOptionPane
4692                           .showConfirmDialog(
4693                                   this,
4694                                   "<html>Do you want to <em>ignore</em> the "
4695                                           + filesnotmatched.size()
4696                                           + " files whose names did not match any sequence IDs ?</html>",
4697                                   "Ignore unmatched dropped files ?",
4698                                   JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))
4699           {
4700             return;
4701           }
4702           for (String fn : filesnotmatched)
4703           {
4704             loadJalviewDataFile(fn, null, null, null);
4705           }
4706
4707         }
4708       } catch (Exception ex)
4709       {
4710         ex.printStackTrace();
4711       }
4712     }
4713   }
4714
4715   /**
4716    * Attempt to load a "dropped" file or URL string: First by testing whether
4717    * it's and Annotation file, then a JNet file, and finally a features file. If
4718    * all are false then the user may have dropped an alignment file onto this
4719    * AlignFrame.
4720    * 
4721    * @param file
4722    *          either a filename or a URL string.
4723    */
4724   public void loadJalviewDataFile(String file, String protocol,
4725           String format, SequenceI assocSeq)
4726   {
4727     try
4728     {
4729       if (protocol == null)
4730       {
4731         protocol = jalview.io.FormatAdapter.checkProtocol(file);
4732       }
4733       // if the file isn't identified, or not positively identified as some
4734       // other filetype (PFAM is default unidentified alignment file type) then
4735       // try to parse as annotation.
4736       boolean isAnnotation = (format == null || format
4737               .equalsIgnoreCase("PFAM")) ? new AnnotationFile()
4738               .readAnnotationFile(viewport.getAlignment(), file, protocol)
4739               : false;
4740
4741       if (!isAnnotation)
4742       {
4743         // first see if its a T-COFFEE score file
4744         TCoffeeScoreFile tcf = null;
4745         try
4746         {
4747           tcf = new TCoffeeScoreFile(file, protocol);
4748           if (tcf.isValid())
4749           {
4750             if (tcf.annotateAlignment(viewport.getAlignment(), true))
4751             {
4752               tcoffeeColour.setEnabled(true);
4753               tcoffeeColour.setSelected(true);
4754               changeColour(new TCoffeeColourScheme(viewport.getAlignment()));
4755               isAnnotation = true;
4756               statusBar
4757                       .setText("Successfully pasted T-Coffee scores to alignment.");
4758             }
4759             else
4760             {
4761               // some problem - if no warning its probable that the ID matching process didn't work
4762               JOptionPane.showMessageDialog(Desktop.desktop,
4763                       tcf.getWarningMessage()==null ? "Check that the file matches sequence IDs in the alignment." : tcf.getWarningMessage(),
4764                       "Problem reading T-COFFEE score file",
4765                       JOptionPane.WARNING_MESSAGE);
4766             }
4767           }
4768           else
4769           {
4770             tcf = null;
4771           }
4772         } catch (Exception x)
4773         {
4774           Cache.log.debug("Exception when processing data source as T-COFFEE score file",x);
4775           tcf = null;
4776         }
4777         if (tcf == null)
4778         {
4779           // try to see if its a JNet 'concise' style annotation file *before*
4780           // we
4781           // try to parse it as a features file
4782           if (format == null)
4783           {
4784             format = new IdentifyFile().Identify(file, protocol);
4785           }
4786           if (format.equalsIgnoreCase("JnetFile"))
4787           {
4788             jalview.io.JPredFile predictions = new jalview.io.JPredFile(
4789                     file, protocol);
4790             new JnetAnnotationMaker().add_annotation(predictions,
4791                     viewport.getAlignment(), 0, false);
4792             isAnnotation = true;
4793           }
4794           else
4795           {
4796             /*
4797              * if (format.equalsIgnoreCase("PDB")) {
4798              * 
4799              * String pdbfn = ""; // try to match up filename with sequence id
4800              * try { if (protocol == jalview.io.FormatAdapter.FILE) { File fl =
4801              * new File(file); pdbfn = fl.getName(); } else if (protocol ==
4802              * jalview.io.FormatAdapter.URL) { URL url = new URL(file); pdbfn =
4803              * url.getFile(); } } catch (Exception e) { } ; if (assocSeq ==
4804              * null) { SequenceIdMatcher idm = new SequenceIdMatcher(viewport
4805              * .getAlignment().getSequencesArray()); if (pdbfn.length() > 0) {
4806              * // attempt to find a match in the alignment SequenceI mtch =
4807              * idm.findIdMatch(pdbfn); int l = 0, c = pdbfn.indexOf("."); while
4808              * (mtch == null && c != -1) { while ((c = pdbfn.indexOf(".", l)) >
4809              * l) { l = c; } if (l > -1) { pdbfn = pdbfn.substring(0, l); } mtch
4810              * = idm.findIdMatch(pdbfn); } if (mtch != null) { // try and
4811              * associate // prompt ? PDBEntry pe = new AssociatePdbFileWithSeq()
4812              * .associatePdbWithSeq(file, protocol, mtch, true); if (pe != null)
4813              * { System.err.println("Associated file : " + file + " with " +
4814              * mtch.getDisplayId(true)); alignPanel.paintAlignment(true); } } //
4815              * TODO: maybe need to load as normal otherwise return; } }
4816              */
4817             // try to parse it as a features file
4818             boolean isGroupsFile = parseFeaturesFile(file, protocol);
4819             // if it wasn't a features file then we just treat it as a general
4820             // alignment file to load into the current view.
4821             if (!isGroupsFile)
4822             {
4823               new FileLoader().LoadFile(viewport, file, protocol, format);
4824             }
4825             else
4826             {
4827               alignPanel.paintAlignment(true);
4828             }
4829           }
4830         }
4831       }
4832       if (isAnnotation)
4833       {
4834
4835         alignPanel.adjustAnnotationHeight();
4836         viewport.updateSequenceIdColours();
4837         buildSortByAnnotationScoresMenu();
4838         alignPanel.paintAlignment(true);
4839       }
4840     } catch (Exception ex)
4841     {
4842       ex.printStackTrace();
4843     }
4844   }
4845
4846   public void tabSelectionChanged(int index)
4847   {
4848     if (index > -1)
4849     {
4850       alignPanel = (AlignmentPanel) alignPanels.elementAt(index);
4851       viewport = alignPanel.av;
4852       setMenusFromViewport(viewport);
4853     }
4854   }
4855
4856   public void tabbedPane_mousePressed(MouseEvent e)
4857   {
4858     if (SwingUtilities.isRightMouseButton(e))
4859     {
4860       String reply = JOptionPane.showInternalInputDialog(this,
4861               "Enter View Name", "Edit View Name",
4862               JOptionPane.QUESTION_MESSAGE);
4863
4864       if (reply != null)
4865       {
4866         viewport.viewName = reply;
4867         tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
4868       }
4869     }
4870   }
4871
4872   public AlignViewport getCurrentView()
4873   {
4874     return viewport;
4875   }
4876
4877   /**
4878    * Open the dialog for regex description parsing.
4879    */
4880   protected void extractScores_actionPerformed(ActionEvent e)
4881   {
4882     ParseProperties pp = new jalview.analysis.ParseProperties(
4883             viewport.getAlignment());
4884     // TODO: verify regex and introduce GUI dialog for version 2.5
4885     // if (pp.getScoresFromDescription("col", "score column ",
4886     // "\\W*([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)",
4887     // true)>0)
4888     if (pp.getScoresFromDescription("description column",
4889             "score in description column ", "\\W*([-+eE0-9.]+)", true) > 0)
4890     {
4891       buildSortByAnnotationScoresMenu();
4892     }
4893   }
4894
4895   /*
4896    * (non-Javadoc)
4897    * 
4898    * @see
4899    * jalview.jbgui.GAlignFrame#showDbRefs_actionPerformed(java.awt.event.ActionEvent
4900    * )
4901    */
4902   protected void showDbRefs_actionPerformed(ActionEvent e)
4903   {
4904     viewport.setShowDbRefs(showDbRefsMenuitem.isSelected());
4905   }
4906
4907   /*
4908    * (non-Javadoc)
4909    * 
4910    * @seejalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event.
4911    * ActionEvent)
4912    */
4913   protected void showNpFeats_actionPerformed(ActionEvent e)
4914   {
4915     viewport.setShowNpFeats(showNpFeatsMenuitem.isSelected());
4916   }
4917
4918   /**
4919    * find the viewport amongst the tabs in this alignment frame and close that
4920    * tab
4921    * 
4922    * @param av
4923    */
4924   public boolean closeView(AlignViewport av)
4925   {
4926     if (viewport == av)
4927     {
4928       this.closeMenuItem_actionPerformed(false);
4929       return true;
4930     }
4931     Component[] comp = tabbedPane.getComponents();
4932     for (int i = 0; comp != null && i < comp.length; i++)
4933     {
4934       if (comp[i] instanceof AlignmentPanel)
4935       {
4936         if (((AlignmentPanel) comp[i]).av == av)
4937         {
4938           // close the view.
4939           closeView((AlignmentPanel) comp[i]);
4940           return true;
4941         }
4942       }
4943     }
4944     return false;
4945   }
4946
4947   protected void build_fetchdbmenu(JMenu webService)
4948   {
4949     // Temporary hack - DBRef Fetcher always top level ws entry.
4950     // TODO We probably want to store a sequence database checklist in
4951     // preferences and have checkboxes.. rather than individual sources selected
4952     // here
4953     final JMenu rfetch = new JMenu("Fetch DB References");
4954     rfetch.setToolTipText("Retrieve and parse sequence database records for the alignment or the currently selected sequences");
4955     webService.add(rfetch);
4956
4957     JMenuItem fetchr = new JMenuItem("Standard Databases");
4958     fetchr.setToolTipText("Fetch from EMBL/EMBLCDS or Uniprot/PDB and any selected DAS sources");
4959     fetchr.addActionListener(new ActionListener()
4960     {
4961
4962       public void actionPerformed(ActionEvent e)
4963       {
4964         new Thread(new Runnable()
4965         {
4966
4967           public void run()
4968           {
4969             new jalview.ws.DBRefFetcher(alignPanel.av
4970                     .getSequenceSelection(), alignPanel.alignFrame)
4971                     .fetchDBRefs(false);
4972           }
4973         }).start();
4974
4975       }
4976
4977     });
4978     rfetch.add(fetchr);
4979     final AlignFrame me = this;
4980     new Thread(new Runnable()
4981     {
4982       public void run()
4983       {
4984         final jalview.ws.SequenceFetcher sf = SequenceFetcher
4985                 .getSequenceFetcherSingleton(me);
4986         javax.swing.SwingUtilities.invokeLater(new Runnable()
4987         {
4988           public void run()
4989           {
4990             String[] dbclasses = sf.getOrderedSupportedSources();
4991             // sf.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);
4992             // jalview.util.QuickSort.sort(otherdb, otherdb);
4993             List<DbSourceProxy> otherdb;
4994             JMenu dfetch = new JMenu();
4995             JMenu ifetch = new JMenu();
4996             JMenuItem fetchr = null;
4997             int comp = 0, icomp = 0, mcomp = 15;
4998             String mname = null;
4999             int dbi = 0;
5000             for (String dbclass : dbclasses)
5001             {
5002               otherdb = sf.getSourceProxy(dbclass);
5003               // add a single entry for this class, or submenu allowing 'fetch
5004               // all' or pick one
5005               if (otherdb == null || otherdb.size() < 1)
5006               {
5007                 continue;
5008               }
5009               // List<DbSourceProxy> dbs=otherdb;
5010               // otherdb=new ArrayList<DbSourceProxy>();
5011               // for (DbSourceProxy db:dbs)
5012               // {
5013               // if (!db.isA(DBRefSource.ALIGNMENTDB)
5014               // }
5015               if (mname == null)
5016               {
5017                 mname = "From " + dbclass;
5018               }
5019               if (otherdb.size() == 1)
5020               {
5021                 final DbSourceProxy[] dassource = otherdb
5022                         .toArray(new DbSourceProxy[0]);
5023                 DbSourceProxy src = otherdb.get(0);
5024                 fetchr = new JMenuItem(src.getDbSource());
5025                 fetchr.addActionListener(new ActionListener()
5026                 {
5027
5028                   public void actionPerformed(ActionEvent e)
5029                   {
5030                     new Thread(new Runnable()
5031                     {
5032
5033                       public void run()
5034                       {
5035                         new jalview.ws.DBRefFetcher(alignPanel.av
5036                                 .getSequenceSelection(),
5037                                 alignPanel.alignFrame, dassource)
5038                                 .fetchDBRefs(false);
5039                       }
5040                     }).start();
5041                   }
5042
5043                 });
5044                 fetchr.setToolTipText("<html>"
5045                         + JvSwingUtils.wrapTooltip("Retrieve from "
5046                                 + src.getDbName()) + "<html>");
5047                 dfetch.add(fetchr);
5048                 comp++;
5049               }
5050               else
5051               {
5052                 final DbSourceProxy[] dassource = otherdb
5053                         .toArray(new DbSourceProxy[0]);
5054                 // fetch all entry
5055                 DbSourceProxy src = otherdb.get(0);
5056                 fetchr = new JMenuItem("Fetch All '" + src.getDbSource()
5057                         + "'");
5058                 fetchr.addActionListener(new ActionListener()
5059                 {
5060                   public void actionPerformed(ActionEvent e)
5061                   {
5062                     new Thread(new Runnable()
5063                     {
5064
5065                       public void run()
5066                       {
5067                         new jalview.ws.DBRefFetcher(alignPanel.av
5068                                 .getSequenceSelection(),
5069                                 alignPanel.alignFrame, dassource)
5070                                 .fetchDBRefs(false);
5071                       }
5072                     }).start();
5073                   }
5074                 });
5075
5076                 fetchr.setToolTipText("<html>"
5077                         + JvSwingUtils.wrapTooltip("Retrieve from all "
5078                                 + otherdb.size() + " sources in "
5079                                 + src.getDbSource() + "<br>First is :"
5080                                 + src.getDbName()) + "<html>");
5081                 dfetch.add(fetchr);
5082                 comp++;
5083                 // and then build the rest of the individual menus
5084                 ifetch = new JMenu("Sources from " + src.getDbSource());
5085                 icomp = 0;
5086                 String imname = null;
5087                 int i = 0;
5088                 for (DbSourceProxy sproxy : otherdb)
5089                 {
5090                   String dbname = sproxy.getDbName();
5091                   String sname = dbname.length() > 5 ? dbname.substring(0,
5092                           5) + "..." : dbname;
5093                   String msname = dbname.length() > 10 ? dbname.substring(
5094                           0, 10) + "..." : dbname;
5095                   if (imname == null)
5096                   {
5097                     imname = "from '" + sname + "'";
5098                   }
5099                   fetchr = new JMenuItem(msname);
5100                   final DbSourceProxy[] dassrc =
5101                   { sproxy };
5102                   fetchr.addActionListener(new ActionListener()
5103                   {
5104
5105                     public void actionPerformed(ActionEvent e)
5106                     {
5107                       new Thread(new Runnable()
5108                       {
5109
5110                         public void run()
5111                         {
5112                           new jalview.ws.DBRefFetcher(alignPanel.av
5113                                   .getSequenceSelection(),
5114                                   alignPanel.alignFrame, dassrc)
5115                                   .fetchDBRefs(false);
5116                         }
5117                       }).start();
5118                     }
5119
5120                   });
5121                   fetchr.setToolTipText("<html>"
5122                           + JvSwingUtils.wrapTooltip("Retrieve from "
5123                                   + dbname) + "</html>");
5124                   ifetch.add(fetchr);
5125                   ++i;
5126                   if (++icomp >= mcomp || i == (otherdb.size()))
5127                   {
5128                     ifetch.setText(imname + " to '" + sname + "'");
5129                     dfetch.add(ifetch);
5130                     ifetch = new JMenu();
5131                     imname = null;
5132                     icomp = 0;
5133                     comp++;
5134                   }
5135                 }
5136               }
5137               ++dbi;
5138               if (comp >= mcomp || dbi >= (dbclasses.length))
5139               {
5140                 dfetch.setText(mname + " to '" + dbclass + "'");
5141                 rfetch.add(dfetch);
5142                 dfetch = new JMenu();
5143                 mname = null;
5144                 comp = 0;
5145               }
5146             }
5147           }
5148         });
5149       }
5150     }).start();
5151
5152   }
5153
5154   /**
5155    * Left justify the whole alignment.
5156    */
5157   protected void justifyLeftMenuItem_actionPerformed(ActionEvent e)
5158   {
5159     AlignmentI al = viewport.getAlignment();
5160     al.justify(false);
5161     viewport.firePropertyChange("alignment", null, al);
5162   }
5163
5164   /**
5165    * Right justify the whole alignment.
5166    */
5167   protected void justifyRightMenuItem_actionPerformed(ActionEvent e)
5168   {
5169     AlignmentI al = viewport.getAlignment();
5170     al.justify(true);
5171     viewport.firePropertyChange("alignment", null, al);
5172   }
5173
5174   public void setShowSeqFeatures(boolean b)
5175   {
5176     showSeqFeatures.setSelected(true);
5177     viewport.setShowSequenceFeatures(true);
5178   }
5179
5180   /*
5181    * (non-Javadoc)
5182    * 
5183    * @see
5184    * jalview.jbgui.GAlignFrame#showUnconservedMenuItem_actionPerformed(java.
5185    * awt.event.ActionEvent)
5186    */
5187   protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)
5188   {
5189     viewport.setShowUnconserved(showNonconservedMenuItem.getState());
5190     alignPanel.paintAlignment(true);
5191   }
5192
5193   /*
5194    * (non-Javadoc)
5195    * 
5196    * @see
5197    * jalview.jbgui.GAlignFrame#showGroupConsensus_actionPerformed(java.awt.event
5198    * .ActionEvent)
5199    */
5200   protected void showGroupConsensus_actionPerformed(ActionEvent e)
5201   {
5202     viewport.setShowGroupConsensus(showGroupConsensus.getState());
5203     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5204
5205   }
5206
5207   /*
5208    * (non-Javadoc)
5209    * 
5210    * @see
5211    * jalview.jbgui.GAlignFrame#showGroupConservation_actionPerformed(java.awt
5212    * .event.ActionEvent)
5213    */
5214   protected void showGroupConservation_actionPerformed(ActionEvent e)
5215   {
5216     viewport.setShowGroupConservation(showGroupConservation.getState());
5217     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5218   }
5219
5220   /*
5221    * (non-Javadoc)
5222    * 
5223    * @see
5224    * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt
5225    * .event.ActionEvent)
5226    */
5227   protected void showConsensusHistogram_actionPerformed(ActionEvent e)
5228   {
5229     viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
5230     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5231   }
5232
5233   /*
5234    * (non-Javadoc)
5235    * 
5236    * @see
5237    * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt
5238    * .event.ActionEvent)
5239    */
5240   protected void showSequenceLogo_actionPerformed(ActionEvent e)
5241   {
5242     viewport.setShowSequenceLogo(showSequenceLogo.getState());
5243     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5244   }
5245
5246   protected void normaliseSequenceLogo_actionPerformed(ActionEvent e)
5247   {
5248     viewport.setNormaliseSequenceLogo(normaliseSequenceLogo.getState());
5249     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5250   }
5251
5252   protected void applyAutoAnnotationSettings_actionPerformed(ActionEvent e)
5253   {
5254     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5255   }
5256
5257   /*
5258    * (non-Javadoc)
5259    * 
5260    * @see
5261    * jalview.jbgui.GAlignFrame#makeGrpsFromSelection_actionPerformed(java.awt
5262    * .event.ActionEvent)
5263    */
5264   protected void makeGrpsFromSelection_actionPerformed(ActionEvent e)
5265   {
5266     if (viewport.getSelectionGroup() != null)
5267     {
5268       SequenceGroup[] gps = jalview.analysis.Grouping.makeGroupsFrom(
5269               viewport.getSequenceSelection(),
5270               viewport.getAlignmentView(true).getSequenceStrings(
5271                       viewport.getGapCharacter()), viewport.getAlignment()
5272                       .getGroups());
5273       viewport.getAlignment().deleteAllGroups();
5274       viewport.sequenceColours = null;
5275       viewport.setSelectionGroup(null);
5276       // set view properties for each group
5277       for (int g = 0; g < gps.length; g++)
5278       {
5279         gps[g].setShowNonconserved(viewport.getShowUnconserved());
5280         gps[g].setshowSequenceLogo(viewport.isShowSequenceLogo());
5281         viewport.getAlignment().addGroup(gps[g]);
5282         Color col = new Color((int) (Math.random() * 255),
5283                 (int) (Math.random() * 255), (int) (Math.random() * 255));
5284         col = col.brighter();
5285         for (SequenceI s:gps[g].getSequences())
5286           viewport.setSequenceColour(
5287                 s, col)
5288           ;
5289       }
5290       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
5291       alignPanel.updateAnnotation();
5292       alignPanel.paintAlignment(true);
5293     }
5294   }
5295
5296   /**
5297    * make the given alignmentPanel the currently selected tab
5298    * 
5299    * @param alignmentPanel
5300    */
5301   public void setDisplayedView(AlignmentPanel alignmentPanel)
5302   {
5303     if (!viewport.getSequenceSetId().equals(
5304             alignmentPanel.av.getSequenceSetId()))
5305     {
5306       throw new Error(
5307               "Implementation error: cannot show a view from another alignment in an AlignFrame.");
5308     }
5309     if (tabbedPane != null
5310             & alignPanels.indexOf(alignmentPanel) != tabbedPane
5311                     .getSelectedIndex())
5312     {
5313       tabbedPane.setSelectedIndex(alignPanels.indexOf(alignmentPanel));
5314     }
5315   }
5316 }
5317
5318 class PrintThread extends Thread
5319 {
5320   AlignmentPanel ap;
5321
5322   public PrintThread(AlignmentPanel ap)
5323   {
5324     this.ap = ap;
5325   }
5326
5327   static PageFormat pf;
5328
5329   public void run()
5330   {
5331     PrinterJob printJob = PrinterJob.getPrinterJob();
5332
5333     if (pf != null)
5334     {
5335       printJob.setPrintable(ap, pf);
5336     }
5337     else
5338     {
5339       printJob.setPrintable(ap);
5340     }
5341
5342     if (printJob.printDialog())
5343     {
5344       try
5345       {
5346         printJob.print();
5347       } catch (Exception PrintException)
5348       {
5349         PrintException.printStackTrace();
5350       }
5351     }
5352   }
5353 }