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