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