da34013b5b89a0c4a9195ce6462180e2dcbf3598
[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.AlignmentUtils;
24 import jalview.analysis.Conservation;
25 import jalview.analysis.CrossRef;
26 import jalview.analysis.NJTree;
27 import jalview.analysis.ParseProperties;
28 import jalview.analysis.SequenceIdMatcher;
29 import jalview.api.AlignViewControllerGuiI;
30 import jalview.api.AlignViewControllerI;
31 import jalview.api.analysis.ScoreModelI;
32 import jalview.bin.Cache;
33 import jalview.commands.CommandI;
34 import jalview.commands.EditCommand;
35 import jalview.commands.OrderCommand;
36 import jalview.commands.RemoveGapColCommand;
37 import jalview.commands.RemoveGapsCommand;
38 import jalview.commands.SlideSequencesCommand;
39 import jalview.commands.TrimRegionCommand;
40 import jalview.datamodel.AlignedCodonFrame;
41 import jalview.datamodel.Alignment;
42 import jalview.datamodel.AlignmentAnnotation;
43 import jalview.datamodel.AlignmentI;
44 import jalview.datamodel.AlignmentOrder;
45 import jalview.datamodel.AlignmentView;
46 import jalview.datamodel.ColumnSelection;
47 import jalview.datamodel.PDBEntry;
48 import jalview.datamodel.SeqCigar;
49 import jalview.datamodel.Sequence;
50 import jalview.datamodel.SequenceGroup;
51 import jalview.datamodel.SequenceI;
52 import jalview.io.AlignmentProperties;
53 import jalview.io.AnnotationFile;
54 import jalview.io.FeaturesFile;
55 import jalview.io.FileLoader;
56 import jalview.io.FormatAdapter;
57 import jalview.io.HTMLOutput;
58 import jalview.io.IdentifyFile;
59 import jalview.io.JalviewFileChooser;
60 import jalview.io.JalviewFileView;
61 import jalview.io.JnetAnnotationMaker;
62 import jalview.io.NewickFile;
63 import jalview.io.TCoffeeScoreFile;
64 import jalview.jbgui.GAlignFrame;
65 import jalview.schemes.Blosum62ColourScheme;
66 import jalview.schemes.BuriedColourScheme;
67 import jalview.schemes.ClustalxColourScheme;
68 import jalview.schemes.ColourSchemeI;
69 import jalview.schemes.ColourSchemeProperty;
70 import jalview.schemes.HelixColourScheme;
71 import jalview.schemes.HydrophobicColourScheme;
72 import jalview.schemes.NucleotideColourScheme;
73 import jalview.schemes.PIDColourScheme;
74 import jalview.schemes.PurinePyrimidineColourScheme;
75 import jalview.schemes.RNAHelicesColourChooser;
76 import jalview.schemes.ResidueProperties;
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.Component;
91 import java.awt.GridLayout;
92 import java.awt.Rectangle;
93 import java.awt.Toolkit;
94 import java.awt.datatransfer.Clipboard;
95 import java.awt.datatransfer.DataFlavor;
96 import java.awt.datatransfer.StringSelection;
97 import java.awt.datatransfer.Transferable;
98 import java.awt.dnd.DnDConstants;
99 import java.awt.dnd.DropTargetDragEvent;
100 import java.awt.dnd.DropTargetDropEvent;
101 import java.awt.dnd.DropTargetEvent;
102 import java.awt.dnd.DropTargetListener;
103 import java.awt.event.ActionEvent;
104 import java.awt.event.ActionListener;
105 import java.awt.event.KeyAdapter;
106 import java.awt.event.KeyEvent;
107 import java.awt.event.MouseAdapter;
108 import java.awt.event.MouseEvent;
109 import java.awt.print.PageFormat;
110 import java.awt.print.PrinterJob;
111 import java.beans.PropertyChangeEvent;
112 import java.io.File;
113 import java.net.URL;
114 import java.util.ArrayList;
115 import java.util.Enumeration;
116 import java.util.Hashtable;
117 import java.util.List;
118 import java.util.Vector;
119
120 import javax.swing.JButton;
121 import javax.swing.JCheckBoxMenuItem;
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   @Override
2067   protected void expand_newalign(ActionEvent e)
2068   {
2069     try {
2070     AlignmentI alignment = AlignmentUtils.expandContext(getViewport().getAlignment(), -1);
2071     AlignFrame af = new AlignFrame(alignment, DEFAULT_WIDTH,
2072             DEFAULT_HEIGHT);
2073     String newtitle = new String("Flanking alignment");
2074
2075     if (Desktop.jalviewClipboard != null
2076             && Desktop.jalviewClipboard[2] != null)
2077     {
2078       Vector hc = (Vector) Desktop.jalviewClipboard[2];
2079       for (int i = 0; i < hc.size(); i++)
2080       {
2081         int[] region = (int[]) hc.elementAt(i);
2082         af.viewport.hideColumns(region[0], region[1]);
2083       }
2084     }
2085
2086     // >>>This is a fix for the moment, until a better solution is
2087     // found!!<<<
2088     af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer()
2089             .transferSettings(
2090                     alignPanel.seqPanel.seqCanvas.getFeatureRenderer());
2091
2092     // TODO: maintain provenance of an alignment, rather than just make the
2093     // title a concatenation of operations.
2094     {
2095       if (title.startsWith("Copied sequences"))
2096       {
2097         newtitle = title;
2098       }
2099       else
2100       {
2101         newtitle = newtitle.concat("- from " + title);
2102       }
2103     }
2104
2105     Desktop.addInternalFrame(af, newtitle, DEFAULT_WIDTH,
2106             DEFAULT_HEIGHT);
2107
2108     } catch (Exception ex)
2109     {
2110       ex.printStackTrace();
2111       System.out.println("Exception whilst pasting: " + ex);
2112       // could be anything being pasted in here
2113     }
2114     catch (OutOfMemoryError oom)
2115     {
2116       new OOMWarning("Viewing flanking region of alignment", oom);
2117     }
2118   }
2119   /**
2120    * DOCUMENT ME!
2121    * 
2122    * @param e
2123    *          DOCUMENT ME!
2124    */
2125   @Override
2126   protected void cut_actionPerformed(ActionEvent e)
2127   {
2128     copy_actionPerformed(null);
2129     delete_actionPerformed(null);
2130   }
2131
2132   /**
2133    * DOCUMENT ME!
2134    * 
2135    * @param e
2136    *          DOCUMENT ME!
2137    */
2138   @Override
2139   protected void delete_actionPerformed(ActionEvent evt)
2140   {
2141
2142     SequenceGroup sg = viewport.getSelectionGroup();
2143     if (sg == null)
2144     {
2145       return;
2146     }
2147
2148     Vector seqs = new Vector();
2149     SequenceI seq;
2150     for (int i = 0; i < sg.getSize(); i++)
2151     {
2152       seq = sg.getSequenceAt(i);
2153       seqs.addElement(seq);
2154     }
2155
2156     // If the cut affects all sequences, remove highlighted columns
2157     if (sg.getSize() == viewport.getAlignment().getHeight())
2158     {
2159       viewport.getColumnSelection().removeElements(sg.getStartRes(),
2160               sg.getEndRes() + 1);
2161     }
2162
2163     SequenceI[] cut = new SequenceI[seqs.size()];
2164     for (int i = 0; i < seqs.size(); i++)
2165     {
2166       cut[i] = (SequenceI) seqs.elementAt(i);
2167     }
2168
2169     /*
2170      * //ADD HISTORY ITEM
2171      */
2172     addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT, cut,
2173             sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
2174             viewport.getAlignment()));
2175
2176     viewport.setSelectionGroup(null);
2177     viewport.sendSelection();
2178     viewport.getAlignment().deleteGroup(sg);
2179
2180     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2181             .getSequences());
2182     if (viewport.getAlignment().getHeight() < 1)
2183     {
2184       try
2185       {
2186         this.setClosed(true);
2187       } catch (Exception ex)
2188       {
2189       }
2190     }
2191   }
2192
2193   /**
2194    * DOCUMENT ME!
2195    * 
2196    * @param e
2197    *          DOCUMENT ME!
2198    */
2199   @Override
2200   protected void deleteGroups_actionPerformed(ActionEvent e)
2201   {
2202     if (avc.deleteGroups()) {
2203       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
2204       alignPanel.updateAnnotation();
2205       alignPanel.paintAlignment(true);
2206     }
2207   }
2208
2209   /**
2210    * DOCUMENT ME!
2211    * 
2212    * @param e
2213    *          DOCUMENT ME!
2214    */
2215   @Override
2216   public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)
2217   {
2218     SequenceGroup sg = new SequenceGroup();
2219
2220     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2221     {
2222       sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
2223     }
2224
2225     sg.setEndRes(viewport.getAlignment().getWidth() - 1);
2226     viewport.setSelectionGroup(sg);
2227     viewport.sendSelection();
2228     alignPanel.paintAlignment(true);
2229     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2230   }
2231
2232   /**
2233    * DOCUMENT ME!
2234    * 
2235    * @param e
2236    *          DOCUMENT ME!
2237    */
2238   @Override
2239   public void deselectAllSequenceMenuItem_actionPerformed(ActionEvent e)
2240   {
2241     if (viewport.cursorMode)
2242     {
2243       alignPanel.seqPanel.keyboardNo1 = null;
2244       alignPanel.seqPanel.keyboardNo2 = null;
2245     }
2246     viewport.setSelectionGroup(null);
2247     viewport.getColumnSelection().clear();
2248     viewport.setSelectionGroup(null);
2249     alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);
2250     alignPanel.idPanel.idCanvas.searchResults = null;
2251     alignPanel.paintAlignment(true);
2252     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2253     viewport.sendSelection();
2254   }
2255
2256   /**
2257    * DOCUMENT ME!
2258    * 
2259    * @param e
2260    *          DOCUMENT ME!
2261    */
2262   @Override
2263   public void invertSequenceMenuItem_actionPerformed(ActionEvent e)
2264   {
2265     SequenceGroup sg = viewport.getSelectionGroup();
2266
2267     if (sg == null)
2268     {
2269       selectAllSequenceMenuItem_actionPerformed(null);
2270
2271       return;
2272     }
2273
2274     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2275     {
2276       sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
2277     }
2278
2279     alignPanel.paintAlignment(true);
2280     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2281     viewport.sendSelection();
2282   }
2283
2284   @Override
2285   public void invertColSel_actionPerformed(ActionEvent e)
2286   {
2287     viewport.invertColumnSelection();
2288     alignPanel.paintAlignment(true);
2289     viewport.sendSelection();
2290   }
2291
2292   /**
2293    * DOCUMENT ME!
2294    * 
2295    * @param e
2296    *          DOCUMENT ME!
2297    */
2298   @Override
2299   public void remove2LeftMenuItem_actionPerformed(ActionEvent e)
2300   {
2301     trimAlignment(true);
2302   }
2303
2304   /**
2305    * DOCUMENT ME!
2306    * 
2307    * @param e
2308    *          DOCUMENT ME!
2309    */
2310   @Override
2311   public void remove2RightMenuItem_actionPerformed(ActionEvent e)
2312   {
2313     trimAlignment(false);
2314   }
2315
2316   void trimAlignment(boolean trimLeft)
2317   {
2318     ColumnSelection colSel = viewport.getColumnSelection();
2319     int column;
2320
2321     if (colSel.size() > 0)
2322     {
2323       if (trimLeft)
2324       {
2325         column = colSel.getMin();
2326       }
2327       else
2328       {
2329         column = colSel.getMax();
2330       }
2331
2332       SequenceI[] seqs;
2333       if (viewport.getSelectionGroup() != null)
2334       {
2335         seqs = viewport.getSelectionGroup().getSequencesAsArray(
2336                 viewport.getHiddenRepSequences());
2337       }
2338       else
2339       {
2340         seqs = viewport.getAlignment().getSequencesArray();
2341       }
2342
2343       TrimRegionCommand trimRegion;
2344       if (trimLeft)
2345       {
2346         trimRegion = new TrimRegionCommand("Remove Left",
2347                 TrimRegionCommand.TRIM_LEFT, seqs, column,
2348                 viewport.getAlignment(), viewport.getColumnSelection(),
2349                 viewport.getSelectionGroup());
2350         viewport.setStartRes(0);
2351       }
2352       else
2353       {
2354         trimRegion = new TrimRegionCommand("Remove Right",
2355                 TrimRegionCommand.TRIM_RIGHT, seqs, column,
2356                 viewport.getAlignment(), viewport.getColumnSelection(),
2357                 viewport.getSelectionGroup());
2358       }
2359
2360       statusBar.setText(MessageManager.formatMessage("label.removed_columns", new String[]{Integer.valueOf(trimRegion.getSize()).toString()}));
2361
2362       addHistoryItem(trimRegion);
2363
2364       for (SequenceGroup sg : viewport.getAlignment().getGroups())
2365       {
2366         if ((trimLeft && !sg.adjustForRemoveLeft(column))
2367                 || (!trimLeft && !sg.adjustForRemoveRight(column)))
2368         {
2369           viewport.getAlignment().deleteGroup(sg);
2370         }
2371       }
2372
2373       viewport.firePropertyChange("alignment", null, viewport
2374               .getAlignment().getSequences());
2375     }
2376   }
2377
2378   /**
2379    * DOCUMENT ME!
2380    * 
2381    * @param e
2382    *          DOCUMENT ME!
2383    */
2384   @Override
2385   public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e)
2386   {
2387     int start = 0, end = viewport.getAlignment().getWidth() - 1;
2388
2389     SequenceI[] seqs;
2390     if (viewport.getSelectionGroup() != null)
2391     {
2392       seqs = viewport.getSelectionGroup().getSequencesAsArray(
2393               viewport.getHiddenRepSequences());
2394       start = viewport.getSelectionGroup().getStartRes();
2395       end = viewport.getSelectionGroup().getEndRes();
2396     }
2397     else
2398     {
2399       seqs = viewport.getAlignment().getSequencesArray();
2400     }
2401
2402     RemoveGapColCommand removeGapCols = new RemoveGapColCommand(
2403             "Remove Gapped Columns", seqs, start, end,
2404             viewport.getAlignment());
2405
2406     addHistoryItem(removeGapCols);
2407
2408     statusBar.setText(MessageManager.formatMessage("label.removed_empty_columns", new String[]{Integer.valueOf(removeGapCols.getSize()).toString()}));
2409
2410     // This is to maintain viewport position on first residue
2411     // of first sequence
2412     SequenceI seq = viewport.getAlignment().getSequenceAt(0);
2413     int startRes = seq.findPosition(viewport.startRes);
2414     // ShiftList shifts;
2415     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
2416     // edit.alColumnChanges=shifts.getInverse();
2417     // if (viewport.hasHiddenColumns)
2418     // viewport.getColumnSelection().compensateForEdits(shifts);
2419     viewport.setStartRes(seq.findIndex(startRes) - 1);
2420     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2421             .getSequences());
2422
2423   }
2424
2425   /**
2426    * DOCUMENT ME!
2427    * 
2428    * @param e
2429    *          DOCUMENT ME!
2430    */
2431   @Override
2432   public void removeAllGapsMenuItem_actionPerformed(ActionEvent e)
2433   {
2434     int start = 0, end = viewport.getAlignment().getWidth() - 1;
2435
2436     SequenceI[] seqs;
2437     if (viewport.getSelectionGroup() != null)
2438     {
2439       seqs = viewport.getSelectionGroup().getSequencesAsArray(
2440               viewport.getHiddenRepSequences());
2441       start = viewport.getSelectionGroup().getStartRes();
2442       end = viewport.getSelectionGroup().getEndRes();
2443     }
2444     else
2445     {
2446       seqs = viewport.getAlignment().getSequencesArray();
2447     }
2448
2449     // This is to maintain viewport position on first residue
2450     // of first sequence
2451     SequenceI seq = viewport.getAlignment().getSequenceAt(0);
2452     int startRes = seq.findPosition(viewport.startRes);
2453
2454     addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
2455             viewport.getAlignment()));
2456
2457     viewport.setStartRes(seq.findIndex(startRes) - 1);
2458
2459     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2460             .getSequences());
2461
2462   }
2463
2464   /**
2465    * DOCUMENT ME!
2466    * 
2467    * @param e
2468    *          DOCUMENT ME!
2469    */
2470   @Override
2471   public void padGapsMenuitem_actionPerformed(ActionEvent e)
2472   {
2473     viewport.setPadGaps(padGapsMenuitem.isSelected());
2474     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2475             .getSequences());
2476   }
2477
2478   // else
2479   {
2480     // if (justifySeqs>0)
2481     {
2482       // alignment.justify(justifySeqs!=RIGHT_JUSTIFY);
2483     }
2484   }
2485
2486   // }
2487
2488   /**
2489    * DOCUMENT ME!
2490    * 
2491    * @param e
2492    *          DOCUMENT ME!
2493    */
2494   @Override
2495   public void findMenuItem_actionPerformed(ActionEvent e)
2496   {
2497     new Finder();
2498   }
2499
2500   @Override
2501   public void newView_actionPerformed(ActionEvent e)
2502   {
2503     newView(true);
2504   }
2505
2506   /**
2507    * 
2508    * @param copyAnnotation
2509    *          if true then duplicate all annnotation, groups and settings
2510    * @return new alignment panel, already displayed.
2511    */
2512   public AlignmentPanel newView(boolean copyAnnotation)
2513   {
2514     return newView(null, copyAnnotation);
2515   }
2516
2517   /**
2518    * 
2519    * @param viewTitle
2520    *          title of newly created view
2521    * @return new alignment panel, already displayed.
2522    */
2523   public AlignmentPanel newView(String viewTitle)
2524   {
2525     return newView(viewTitle, true);
2526   }
2527
2528   /**
2529    * 
2530    * @param viewTitle
2531    *          title of newly created view
2532    * @param copyAnnotation
2533    *          if true then duplicate all annnotation, groups and settings
2534    * @return new alignment panel, already displayed.
2535    */
2536   public AlignmentPanel newView(String viewTitle, boolean copyAnnotation)
2537   {
2538     AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel,
2539             true);
2540     if (!copyAnnotation)
2541     {
2542       // just remove all the current annotation except for the automatic stuff
2543       newap.av.getAlignment().deleteAllGroups();
2544       for (AlignmentAnnotation alan : newap.av.getAlignment()
2545               .getAlignmentAnnotation())
2546       {
2547         if (!alan.autoCalculated)
2548         {
2549           newap.av.getAlignment().deleteAnnotation(alan);
2550         }
2551         ;
2552       }
2553     }
2554
2555     newap.av.gatherViewsHere = false;
2556
2557     if (viewport.viewName == null)
2558     {
2559       viewport.viewName = "Original";
2560     }
2561
2562     newap.av.historyList = viewport.historyList;
2563     newap.av.redoList = viewport.redoList;
2564
2565     int index = Desktop.getViewCount(viewport.getSequenceSetId());
2566     // make sure the new view has a unique name - this is essential for Jalview
2567     // 2 archives
2568     boolean addFirstIndex = false;
2569     if (viewTitle == null || viewTitle.trim().length() == 0)
2570     {
2571       viewTitle = "View";
2572       addFirstIndex = true;
2573     }
2574     else
2575     {
2576       index = 1;// we count from 1 if given a specific name
2577     }
2578     String newViewName = viewTitle + ((addFirstIndex) ? " " + index : "");
2579     Vector comps = (Vector) PaintRefresher.components.get(viewport
2580             .getSequenceSetId());
2581     Vector existingNames = new Vector();
2582     for (int i = 0; i < comps.size(); i++)
2583     {
2584       if (comps.elementAt(i) instanceof AlignmentPanel)
2585       {
2586         AlignmentPanel ap = (AlignmentPanel) comps.elementAt(i);
2587         if (!existingNames.contains(ap.av.viewName))
2588         {
2589           existingNames.addElement(ap.av.viewName);
2590         }
2591       }
2592     }
2593
2594     while (existingNames.contains(newViewName))
2595     {
2596       newViewName = viewTitle + " " + (++index);
2597     }
2598
2599     newap.av.viewName = newViewName;
2600
2601     addAlignmentPanel(newap, true);
2602     newap.alignmentChanged();
2603     
2604     if (alignPanels.size() == 2)
2605     {
2606       viewport.gatherViewsHere = true;
2607     }
2608     tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
2609     return newap;
2610   }
2611
2612   @Override
2613   public void expandViews_actionPerformed(ActionEvent e)
2614   {
2615     Desktop.instance.explodeViews(this);
2616   }
2617
2618   @Override
2619   public void gatherViews_actionPerformed(ActionEvent e)
2620   {
2621     Desktop.instance.gatherViews(this);
2622   }
2623
2624   /**
2625    * DOCUMENT ME!
2626    * 
2627    * @param e
2628    *          DOCUMENT ME!
2629    */
2630   @Override
2631   public void font_actionPerformed(ActionEvent e)
2632   {
2633     new FontChooser(alignPanel);
2634   }
2635
2636   /**
2637    * DOCUMENT ME!
2638    * 
2639    * @param e
2640    *          DOCUMENT ME!
2641    */
2642   @Override
2643   protected void seqLimit_actionPerformed(ActionEvent e)
2644   {
2645     viewport.setShowJVSuffix(seqLimits.isSelected());
2646
2647     alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel
2648             .calculateIdWidth());
2649     alignPanel.paintAlignment(true);
2650   }
2651
2652   @Override
2653   public void idRightAlign_actionPerformed(ActionEvent e)
2654   {
2655     viewport.rightAlignIds = idRightAlign.isSelected();
2656     alignPanel.paintAlignment(true);
2657   }
2658
2659   @Override
2660   public void centreColumnLabels_actionPerformed(ActionEvent e)
2661   {
2662     viewport.centreColumnLabels = centreColumnLabelsMenuItem.getState();
2663     alignPanel.paintAlignment(true);
2664   }
2665
2666   /*
2667    * (non-Javadoc)
2668    * 
2669    * @see jalview.jbgui.GAlignFrame#followHighlight_actionPerformed()
2670    */
2671   @Override
2672   protected void followHighlight_actionPerformed()
2673   {
2674     if (viewport.followHighlight = this.followHighlightMenuItem.getState())
2675     {
2676       alignPanel.scrollToPosition(
2677               alignPanel.seqPanel.seqCanvas.searchResults, false);
2678     }
2679   }
2680
2681   /**
2682    * DOCUMENT ME!
2683    * 
2684    * @param e
2685    *          DOCUMENT ME!
2686    */
2687   @Override
2688   protected void colourTextMenuItem_actionPerformed(ActionEvent e)
2689   {
2690     viewport.setColourText(colourTextMenuItem.isSelected());
2691     alignPanel.paintAlignment(true);
2692   }
2693
2694   /**
2695    * DOCUMENT ME!
2696    * 
2697    * @param e
2698    *          DOCUMENT ME!
2699    */
2700   @Override
2701   public void wrapMenuItem_actionPerformed(ActionEvent e)
2702   {
2703     scaleAbove.setVisible(wrapMenuItem.isSelected());
2704     scaleLeft.setVisible(wrapMenuItem.isSelected());
2705     scaleRight.setVisible(wrapMenuItem.isSelected());
2706     viewport.setWrapAlignment(wrapMenuItem.isSelected());
2707     alignPanel.setWrapAlignment(wrapMenuItem.isSelected());
2708   }
2709
2710   @Override
2711   public void showAllSeqs_actionPerformed(ActionEvent e)
2712   {
2713     viewport.showAllHiddenSeqs();
2714   }
2715
2716   @Override
2717   public void showAllColumns_actionPerformed(ActionEvent e)
2718   {
2719     viewport.showAllHiddenColumns();
2720     repaint();
2721   }
2722
2723   @Override
2724   public void hideSelSequences_actionPerformed(ActionEvent e)
2725   {
2726     viewport.hideAllSelectedSeqs();
2727     alignPanel.paintAlignment(true);
2728   }
2729
2730   /**
2731    * called by key handler and the hide all/show all menu items
2732    * 
2733    * @param toggleSeqs
2734    * @param toggleCols
2735    */
2736   private void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
2737   {
2738
2739     boolean hide = false;
2740     SequenceGroup sg = viewport.getSelectionGroup();
2741     if (!toggleSeqs && !toggleCols)
2742     {
2743       // Hide everything by the current selection - this is a hack - we do the
2744       // invert and then hide
2745       // first check that there will be visible columns after the invert.
2746       if ((viewport.getColumnSelection() != null
2747               && viewport.getColumnSelection().getSelected() != null && viewport
2748               .getColumnSelection().getSelected().size() > 0)
2749               || (sg != null && sg.getSize() > 0 && sg.getStartRes() <= sg
2750                       .getEndRes()))
2751       {
2752         // now invert the sequence set, if required - empty selection implies
2753         // that no hiding is required.
2754         if (sg != null)
2755         {
2756           invertSequenceMenuItem_actionPerformed(null);
2757           sg = viewport.getSelectionGroup();
2758           toggleSeqs = true;
2759
2760         }
2761         viewport.expandColSelection(sg, true);
2762         // finally invert the column selection and get the new sequence
2763         // selection.
2764         invertColSel_actionPerformed(null);
2765         toggleCols = true;
2766       }
2767     }
2768
2769     if (toggleSeqs)
2770     {
2771       if (sg != null && sg.getSize() != viewport.getAlignment().getHeight())
2772       {
2773         hideSelSequences_actionPerformed(null);
2774         hide = true;
2775       }
2776       else if (!(toggleCols && viewport.getColumnSelection().getSelected()
2777               .size() > 0))
2778       {
2779         showAllSeqs_actionPerformed(null);
2780       }
2781     }
2782
2783     if (toggleCols)
2784     {
2785       if (viewport.getColumnSelection().getSelected().size() > 0)
2786       {
2787         hideSelColumns_actionPerformed(null);
2788         if (!toggleSeqs)
2789         {
2790           viewport.setSelectionGroup(sg);
2791         }
2792       }
2793       else if (!hide)
2794       {
2795         showAllColumns_actionPerformed(null);
2796       }
2797     }
2798   }
2799
2800   /*
2801    * (non-Javadoc)
2802    * 
2803    * @see
2804    * jalview.jbgui.GAlignFrame#hideAllButSelection_actionPerformed(java.awt.
2805    * event.ActionEvent)
2806    */
2807   @Override
2808   public void hideAllButSelection_actionPerformed(ActionEvent e)
2809   {
2810     toggleHiddenRegions(false, false);
2811   }
2812
2813   /*
2814    * (non-Javadoc)
2815    * 
2816    * @see
2817    * jalview.jbgui.GAlignFrame#hideAllSelection_actionPerformed(java.awt.event
2818    * .ActionEvent)
2819    */
2820   @Override
2821   public void hideAllSelection_actionPerformed(ActionEvent e)
2822   {
2823     SequenceGroup sg = viewport.getSelectionGroup();
2824     viewport.expandColSelection(sg, false);
2825     viewport.hideAllSelectedSeqs();
2826     viewport.hideSelectedColumns();
2827     alignPanel.paintAlignment(true);
2828   }
2829
2830   /*
2831    * (non-Javadoc)
2832    * 
2833    * @see
2834    * jalview.jbgui.GAlignFrame#showAllhidden_actionPerformed(java.awt.event.
2835    * ActionEvent)
2836    */
2837   @Override
2838   public void showAllhidden_actionPerformed(ActionEvent e)
2839   {
2840     viewport.showAllHiddenColumns();
2841     viewport.showAllHiddenSeqs();
2842     alignPanel.paintAlignment(true);
2843   }
2844
2845   @Override
2846   public void hideSelColumns_actionPerformed(ActionEvent e)
2847   {
2848     viewport.hideSelectedColumns();
2849     alignPanel.paintAlignment(true);
2850   }
2851
2852   @Override
2853   public void hiddenMarkers_actionPerformed(ActionEvent e)
2854   {
2855     viewport.setShowHiddenMarkers(hiddenMarkers.isSelected());
2856     repaint();
2857   }
2858
2859   /**
2860    * DOCUMENT ME!
2861    * 
2862    * @param e
2863    *          DOCUMENT ME!
2864    */
2865   @Override
2866   protected void scaleAbove_actionPerformed(ActionEvent e)
2867   {
2868     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
2869     alignPanel.paintAlignment(true);
2870   }
2871
2872   /**
2873    * DOCUMENT ME!
2874    * 
2875    * @param e
2876    *          DOCUMENT ME!
2877    */
2878   @Override
2879   protected void scaleLeft_actionPerformed(ActionEvent e)
2880   {
2881     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
2882     alignPanel.paintAlignment(true);
2883   }
2884
2885   /**
2886    * DOCUMENT ME!
2887    * 
2888    * @param e
2889    *          DOCUMENT ME!
2890    */
2891   @Override
2892   protected void scaleRight_actionPerformed(ActionEvent e)
2893   {
2894     viewport.setScaleRightWrapped(scaleRight.isSelected());
2895     alignPanel.paintAlignment(true);
2896   }
2897
2898   /**
2899    * DOCUMENT ME!
2900    * 
2901    * @param e
2902    *          DOCUMENT ME!
2903    */
2904   @Override
2905   public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
2906   {
2907     viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
2908     alignPanel.paintAlignment(true);
2909   }
2910
2911   /**
2912    * DOCUMENT ME!
2913    * 
2914    * @param e
2915    *          DOCUMENT ME!
2916    */
2917   @Override
2918   public void viewTextMenuItem_actionPerformed(ActionEvent e)
2919   {
2920     viewport.setShowText(viewTextMenuItem.isSelected());
2921     alignPanel.paintAlignment(true);
2922   }
2923
2924   /**
2925    * DOCUMENT ME!
2926    * 
2927    * @param e
2928    *          DOCUMENT ME!
2929    */
2930   @Override
2931   protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
2932   {
2933     viewport.setRenderGaps(renderGapsMenuItem.isSelected());
2934     alignPanel.paintAlignment(true);
2935   }
2936
2937   public FeatureSettings featureSettings;
2938
2939   @Override
2940   public void featureSettings_actionPerformed(ActionEvent e)
2941   {
2942     if (featureSettings != null)
2943     {
2944       featureSettings.close();
2945       featureSettings = null;
2946     }
2947     if (!showSeqFeatures.isSelected())
2948     {
2949       // make sure features are actually displayed
2950       showSeqFeatures.setSelected(true);
2951       showSeqFeatures_actionPerformed(null);
2952     }
2953     featureSettings = new FeatureSettings(this);
2954   }
2955
2956   /**
2957    * Set or clear 'Show Sequence Features'
2958    * 
2959    * @param evt
2960    *          DOCUMENT ME!
2961    */
2962   @Override
2963   public void showSeqFeatures_actionPerformed(ActionEvent evt)
2964   {
2965     viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
2966     alignPanel.paintAlignment(true);
2967     if (alignPanel.getOverviewPanel() != null)
2968     {
2969       alignPanel.getOverviewPanel().updateOverviewImage();
2970     }
2971   }
2972
2973   /**
2974    * Set or clear 'Show Sequence Features'
2975    * 
2976    * @param evt
2977    *          DOCUMENT ME!
2978    */
2979   @Override
2980   public void showSeqFeaturesHeight_actionPerformed(ActionEvent evt)
2981   {
2982     viewport.setShowSequenceFeaturesHeight(showSeqFeaturesHeight
2983             .isSelected());
2984     if (viewport.getShowSequenceFeaturesHeight())
2985     {
2986       // ensure we're actually displaying features
2987       viewport.setShowSequenceFeatures(true);
2988       showSeqFeatures.setSelected(true);
2989     }
2990     alignPanel.paintAlignment(true);
2991     if (alignPanel.getOverviewPanel() != null)
2992     {
2993       alignPanel.getOverviewPanel().updateOverviewImage();
2994     }
2995   }
2996
2997   /**
2998    * DOCUMENT ME!
2999    * 
3000    * @param e
3001    *          DOCUMENT ME!
3002    */
3003   @Override
3004   public void annotationPanelMenuItem_actionPerformed(ActionEvent e)
3005   {
3006     viewport.setShowAnnotation(annotationPanelMenuItem.isSelected());
3007     alignPanel.setAnnotationVisible(annotationPanelMenuItem.isSelected());
3008   }
3009
3010   @Override
3011   public void alignmentProperties()
3012   {
3013     JEditorPane editPane = new JEditorPane("text/html", "");
3014     editPane.setEditable(false);
3015     StringBuffer contents = new AlignmentProperties(viewport.getAlignment())
3016             .formatAsHtml();
3017     editPane.setText(MessageManager.formatMessage("label.html_content", new String[]{contents.toString()}));
3018     JInternalFrame frame = new JInternalFrame();
3019     frame.getContentPane().add(new JScrollPane(editPane));
3020
3021     Desktop.instance.addInternalFrame(frame, MessageManager.formatMessage("label.alignment_properties", new String[]{getTitle()}), 500, 400);\r
3022   }
3023
3024   /**
3025    * DOCUMENT ME!
3026    * 
3027    * @param e
3028    *          DOCUMENT ME!
3029    */
3030   @Override
3031   public void overviewMenuItem_actionPerformed(ActionEvent e)
3032   {
3033     if (alignPanel.overviewPanel != null)
3034     {
3035       return;
3036     }
3037
3038     JInternalFrame frame = new JInternalFrame();
3039     OverviewPanel overview = new OverviewPanel(alignPanel);
3040     frame.setContentPane(overview);
3041     Desktop.addInternalFrame(frame, MessageManager.formatMessage("label.overview_params", new String[]{this.getTitle()}),\r
3042             frame.getWidth(), frame.getHeight());
3043     frame.pack();
3044     frame.setLayer(JLayeredPane.PALETTE_LAYER);
3045     frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
3046     {
3047       @Override
3048       public void internalFrameClosed(
3049               javax.swing.event.InternalFrameEvent evt)
3050       {
3051         alignPanel.setOverviewPanel(null);
3052       };
3053     });
3054
3055     alignPanel.setOverviewPanel(overview);
3056   }
3057
3058   @Override
3059   public void textColour_actionPerformed(ActionEvent e)
3060   {
3061     new TextColourChooser().chooseColour(alignPanel, null);
3062   }
3063
3064   /**
3065    * DOCUMENT ME!
3066    * 
3067    * @param e
3068    *          DOCUMENT ME!
3069    */
3070   @Override
3071   protected void noColourmenuItem_actionPerformed(ActionEvent e)
3072   {
3073     changeColour(null);
3074   }
3075
3076   /**
3077    * DOCUMENT ME!
3078    * 
3079    * @param e
3080    *          DOCUMENT ME!
3081    */
3082   @Override
3083   public void clustalColour_actionPerformed(ActionEvent e)
3084   {
3085     changeColour(new ClustalxColourScheme(viewport.getAlignment(),
3086             viewport.getHiddenRepSequences()));
3087   }
3088
3089   /**
3090    * DOCUMENT ME!
3091    * 
3092    * @param e
3093    *          DOCUMENT ME!
3094    */
3095   @Override
3096   public void zappoColour_actionPerformed(ActionEvent e)
3097   {
3098     changeColour(new ZappoColourScheme());
3099   }
3100
3101   /**
3102    * DOCUMENT ME!
3103    * 
3104    * @param e
3105    *          DOCUMENT ME!
3106    */
3107   @Override
3108   public void taylorColour_actionPerformed(ActionEvent e)
3109   {
3110     changeColour(new TaylorColourScheme());
3111   }
3112
3113   /**
3114    * DOCUMENT ME!
3115    * 
3116    * @param e
3117    *          DOCUMENT ME!
3118    */
3119   @Override
3120   public void hydrophobicityColour_actionPerformed(ActionEvent e)
3121   {
3122     changeColour(new HydrophobicColourScheme());
3123   }
3124
3125   /**
3126    * DOCUMENT ME!
3127    * 
3128    * @param e
3129    *          DOCUMENT ME!
3130    */
3131   @Override
3132   public void helixColour_actionPerformed(ActionEvent e)
3133   {
3134     changeColour(new HelixColourScheme());
3135   }
3136
3137   /**
3138    * DOCUMENT ME!
3139    * 
3140    * @param e
3141    *          DOCUMENT ME!
3142    */
3143   @Override
3144   public void strandColour_actionPerformed(ActionEvent e)
3145   {
3146     changeColour(new StrandColourScheme());
3147   }
3148
3149   /**
3150    * DOCUMENT ME!
3151    * 
3152    * @param e
3153    *          DOCUMENT ME!
3154    */
3155   @Override
3156   public void turnColour_actionPerformed(ActionEvent e)
3157   {
3158     changeColour(new TurnColourScheme());
3159   }
3160
3161   /**
3162    * DOCUMENT ME!
3163    * 
3164    * @param e
3165    *          DOCUMENT ME!
3166    */
3167   @Override
3168   public void buriedColour_actionPerformed(ActionEvent e)
3169   {
3170     changeColour(new BuriedColourScheme());
3171   }
3172
3173   /**
3174    * DOCUMENT ME!
3175    * 
3176    * @param e
3177    *          DOCUMENT ME!
3178    */
3179   @Override
3180   public void nucleotideColour_actionPerformed(ActionEvent e)
3181   {
3182     changeColour(new NucleotideColourScheme());
3183   }
3184
3185   @Override
3186   public void purinePyrimidineColour_actionPerformed(ActionEvent e)
3187   {
3188     changeColour(new PurinePyrimidineColourScheme());
3189   }
3190
3191   /*
3192    * public void covariationColour_actionPerformed(ActionEvent e) {
3193    * changeColour(new
3194    * CovariationColourScheme(viewport.getAlignment().getAlignmentAnnotation
3195    * ()[0])); }
3196    */
3197   @Override
3198   public void annotationColour_actionPerformed(ActionEvent e)
3199   {
3200     new AnnotationColourChooser(viewport, alignPanel);
3201   }
3202
3203   @Override
3204   public void rnahelicesColour_actionPerformed(ActionEvent e)
3205   {
3206     new RNAHelicesColourChooser(viewport, alignPanel);
3207   }
3208
3209   /**
3210    * DOCUMENT ME!
3211    * 
3212    * @param e
3213    *          DOCUMENT ME!
3214    */
3215   @Override
3216   protected void applyToAllGroups_actionPerformed(ActionEvent e)
3217   {
3218     viewport.setColourAppliesToAllGroups(applyToAllGroups.isSelected());
3219   }
3220
3221   /**
3222    * DOCUMENT ME!
3223    * 
3224    * @param cs
3225    *          DOCUMENT ME!
3226    */
3227   public void changeColour(ColourSchemeI cs)
3228   {
3229     // TODO: compare with applet and pull up to model method
3230     int threshold = 0;
3231
3232     if (cs != null)
3233     {
3234       if (viewport.getAbovePIDThreshold())
3235       {
3236         threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
3237                 "Background");
3238
3239         cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
3240
3241         viewport.setGlobalColourScheme(cs);
3242       }
3243       else
3244       {
3245         cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
3246       }
3247
3248       if (viewport.getConservationSelected())
3249       {
3250
3251         Alignment al = (Alignment) viewport.getAlignment();
3252         Conservation c = new Conservation("All",
3253                 ResidueProperties.propHash, 3, al.getSequences(), 0,
3254                 al.getWidth() - 1);
3255
3256         c.calculate();
3257         c.verdict(false, viewport.getConsPercGaps());
3258
3259         cs.setConservation(c);
3260
3261         cs.setConservationInc(SliderPanel.setConservationSlider(alignPanel,
3262                 cs, "Background"));
3263       }
3264       else
3265       {
3266         cs.setConservation(null);
3267       }
3268
3269       cs.setConsensus(viewport.getSequenceConsensusHash());
3270     }
3271
3272     viewport.setGlobalColourScheme(cs);
3273
3274     if (viewport.getColourAppliesToAllGroups())
3275     {
3276
3277       for (SequenceGroup sg : viewport.getAlignment().getGroups())
3278       {
3279         if (cs == null)
3280         {
3281           sg.cs = null;
3282           continue;
3283         }
3284
3285         if (cs instanceof ClustalxColourScheme)
3286         {
3287           sg.cs = new ClustalxColourScheme(sg,
3288                   viewport.getHiddenRepSequences());
3289         }
3290         else if (cs instanceof UserColourScheme)
3291         {
3292           sg.cs = new UserColourScheme(((UserColourScheme) cs).getColours());
3293         }
3294         else
3295         {
3296           try
3297           {
3298             sg.cs = cs.getClass().newInstance();
3299           } catch (Exception ex)
3300           {
3301           }
3302         }
3303
3304         if (viewport.getAbovePIDThreshold()
3305                 || cs instanceof PIDColourScheme
3306                 || cs instanceof Blosum62ColourScheme)
3307         {
3308           sg.cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
3309
3310           sg.cs.setConsensus(AAFrequency.calculate(
3311                   sg.getSequences(viewport.getHiddenRepSequences()),
3312                   sg.getStartRes(), sg.getEndRes() + 1));
3313         }
3314         else
3315         {
3316           sg.cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
3317         }
3318
3319         if (viewport.getConservationSelected())
3320         {
3321           Conservation c = new Conservation("Group",
3322                   ResidueProperties.propHash, 3, sg.getSequences(viewport
3323                           .getHiddenRepSequences()), sg.getStartRes(),
3324                   sg.getEndRes() + 1);
3325           c.calculate();
3326           c.verdict(false, viewport.getConsPercGaps());
3327           sg.cs.setConservation(c);
3328         }
3329         else
3330         {
3331           sg.cs.setConservation(null);
3332         }
3333       }
3334     }
3335
3336     if (alignPanel.getOverviewPanel() != null)
3337     {
3338       alignPanel.getOverviewPanel().updateOverviewImage();
3339     }
3340
3341     alignPanel.paintAlignment(true);
3342   }
3343
3344   /**
3345    * DOCUMENT ME!
3346    * 
3347    * @param e
3348    *          DOCUMENT ME!
3349    */
3350   @Override
3351   protected void modifyPID_actionPerformed(ActionEvent e)
3352   {
3353     if (viewport.getAbovePIDThreshold()
3354             && viewport.getGlobalColourScheme() != null)
3355     {
3356       SliderPanel.setPIDSliderSource(alignPanel,
3357               viewport.getGlobalColourScheme(), "Background");
3358       SliderPanel.showPIDSlider();
3359     }
3360   }
3361
3362   /**
3363    * DOCUMENT ME!
3364    * 
3365    * @param e
3366    *          DOCUMENT ME!
3367    */
3368   @Override
3369   protected void modifyConservation_actionPerformed(ActionEvent e)
3370   {
3371     if (viewport.getConservationSelected()
3372             && viewport.getGlobalColourScheme() != null)
3373     {
3374       SliderPanel.setConservationSlider(alignPanel,
3375               viewport.getGlobalColourScheme(), "Background");
3376       SliderPanel.showConservationSlider();
3377     }
3378   }
3379
3380   /**
3381    * DOCUMENT ME!
3382    * 
3383    * @param e
3384    *          DOCUMENT ME!
3385    */
3386   @Override
3387   protected void conservationMenuItem_actionPerformed(ActionEvent e)
3388   {
3389     viewport.setConservationSelected(conservationMenuItem.isSelected());
3390
3391     viewport.setAbovePIDThreshold(false);
3392     abovePIDThreshold.setSelected(false);
3393
3394     changeColour(viewport.getGlobalColourScheme());
3395
3396     modifyConservation_actionPerformed(null);
3397   }
3398
3399   /**
3400    * DOCUMENT ME!
3401    * 
3402    * @param e
3403    *          DOCUMENT ME!
3404    */
3405   @Override
3406   public void abovePIDThreshold_actionPerformed(ActionEvent e)
3407   {
3408     viewport.setAbovePIDThreshold(abovePIDThreshold.isSelected());
3409
3410     conservationMenuItem.setSelected(false);
3411     viewport.setConservationSelected(false);
3412
3413     changeColour(viewport.getGlobalColourScheme());
3414
3415     modifyPID_actionPerformed(null);
3416   }
3417
3418   /**
3419    * DOCUMENT ME!
3420    * 
3421    * @param e
3422    *          DOCUMENT ME!
3423    */
3424   @Override
3425   public void userDefinedColour_actionPerformed(ActionEvent e)
3426   {
3427     if (e.getActionCommand().equals(MessageManager.getString("action.user_defined")))\r
3428     {
3429       new UserDefinedColours(alignPanel, null);
3430     }
3431     else
3432     {
3433       UserColourScheme udc = (UserColourScheme) UserDefinedColours
3434               .getUserColourSchemes().get(e.getActionCommand());
3435
3436       changeColour(udc);
3437     }
3438   }
3439
3440   public void updateUserColourMenu()
3441   {
3442
3443     Component[] menuItems = colourMenu.getMenuComponents();
3444     int i, iSize = menuItems.length;
3445     for (i = 0; i < iSize; i++)
3446     {
3447       if (menuItems[i].getName() != null
3448               && menuItems[i].getName().equals("USER_DEFINED"))
3449       {
3450         colourMenu.remove(menuItems[i]);
3451         iSize--;
3452       }
3453     }
3454     if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)
3455     {
3456       java.util.Enumeration userColours = jalview.gui.UserDefinedColours
3457               .getUserColourSchemes().keys();
3458
3459       while (userColours.hasMoreElements())
3460       {
3461         final JRadioButtonMenuItem radioItem = new JRadioButtonMenuItem(
3462                 userColours.nextElement().toString());
3463         radioItem.setName("USER_DEFINED");
3464         radioItem.addMouseListener(new MouseAdapter()
3465         {
3466           @Override
3467           public void mousePressed(MouseEvent evt)
3468           {
3469             if (evt.isControlDown()
3470                     || SwingUtilities.isRightMouseButton(evt))
3471             {
3472               radioItem.removeActionListener(radioItem.getActionListeners()[0]);
3473
3474               int option = JOptionPane.showInternalConfirmDialog(
3475                       jalview.gui.Desktop.desktop,
3476                       MessageManager.getString("label.remove_from_default_list"),
3477                       MessageManager.getString("label.remove_user_defined_colour"),
3478                       JOptionPane.YES_NO_OPTION);
3479               if (option == JOptionPane.YES_OPTION)
3480               {
3481                 jalview.gui.UserDefinedColours
3482                         .removeColourFromDefaults(radioItem.getText());
3483                 colourMenu.remove(radioItem);
3484               }
3485               else
3486               {
3487                 radioItem.addActionListener(new ActionListener()
3488                 {
3489                   @Override
3490                   public void actionPerformed(ActionEvent evt)
3491                   {
3492                     userDefinedColour_actionPerformed(evt);
3493                   }
3494                 });
3495               }
3496             }
3497           }
3498         });
3499         radioItem.addActionListener(new ActionListener()
3500         {
3501           @Override
3502           public void actionPerformed(ActionEvent evt)
3503           {
3504             userDefinedColour_actionPerformed(evt);
3505           }
3506         });
3507
3508         colourMenu.insert(radioItem, 15);
3509         colours.add(radioItem);
3510       }
3511     }
3512   }
3513
3514   /**
3515    * DOCUMENT ME!
3516    * 
3517    * @param e
3518    *          DOCUMENT ME!
3519    */
3520   @Override
3521   public void PIDColour_actionPerformed(ActionEvent e)
3522   {
3523     changeColour(new PIDColourScheme());
3524   }
3525
3526   /**
3527    * DOCUMENT ME!
3528    * 
3529    * @param e
3530    *          DOCUMENT ME!
3531    */
3532   @Override
3533   public void BLOSUM62Colour_actionPerformed(ActionEvent e)
3534   {
3535     changeColour(new Blosum62ColourScheme());
3536   }
3537
3538   /**
3539    * DOCUMENT ME!
3540    * 
3541    * @param e
3542    *          DOCUMENT ME!
3543    */
3544   @Override
3545   public void sortPairwiseMenuItem_actionPerformed(ActionEvent e)
3546   {
3547     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3548     AlignmentSorter.sortByPID(viewport.getAlignment(), viewport
3549             .getAlignment().getSequenceAt(0), null);
3550     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
3551             viewport.getAlignment()));
3552     alignPanel.paintAlignment(true);
3553   }
3554
3555   /**
3556    * DOCUMENT ME!
3557    * 
3558    * @param e
3559    *          DOCUMENT ME!
3560    */
3561   @Override
3562   public void sortIDMenuItem_actionPerformed(ActionEvent e)
3563   {
3564     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3565     AlignmentSorter.sortByID(viewport.getAlignment());
3566     addHistoryItem(new OrderCommand("ID Sort", oldOrder,
3567             viewport.getAlignment()));
3568     alignPanel.paintAlignment(true);
3569   }
3570
3571   /**
3572    * DOCUMENT ME!
3573    * 
3574    * @param e
3575    *          DOCUMENT ME!
3576    */
3577   @Override
3578   public void sortLengthMenuItem_actionPerformed(ActionEvent e)
3579   {
3580     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3581     AlignmentSorter.sortByLength(viewport.getAlignment());
3582     addHistoryItem(new OrderCommand("Length Sort", oldOrder,
3583             viewport.getAlignment()));
3584     alignPanel.paintAlignment(true);
3585   }
3586
3587   /**
3588    * DOCUMENT ME!
3589    * 
3590    * @param e
3591    *          DOCUMENT ME!
3592    */
3593   @Override
3594   public void sortGroupMenuItem_actionPerformed(ActionEvent e)
3595   {
3596     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3597     AlignmentSorter.sortByGroup(viewport.getAlignment());
3598     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
3599             viewport.getAlignment()));
3600
3601     alignPanel.paintAlignment(true);
3602   }
3603
3604   /**
3605    * DOCUMENT ME!
3606    * 
3607    * @param e
3608    *          DOCUMENT ME!
3609    */
3610   @Override
3611   public void removeRedundancyMenuItem_actionPerformed(ActionEvent e)
3612   {
3613     new RedundancyPanel(alignPanel, this);
3614   }
3615
3616   /**
3617    * DOCUMENT ME!
3618    * 
3619    * @param e
3620    *          DOCUMENT ME!
3621    */
3622   @Override
3623   public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e)
3624   {
3625     if ((viewport.getSelectionGroup() == null)
3626             || (viewport.getSelectionGroup().getSize() < 2))
3627     {
3628       JOptionPane.showInternalMessageDialog(this,
3629               MessageManager.getString("label.you_must_select_least_two_sequences"), MessageManager.getString("label.invalid_selection"),
3630               JOptionPane.WARNING_MESSAGE);
3631     }
3632     else
3633     {
3634       JInternalFrame frame = new JInternalFrame();
3635       frame.setContentPane(new PairwiseAlignPanel(viewport));
3636       Desktop.addInternalFrame(frame, MessageManager.getString("action.pairwise_alignment"), 600, 500);\r
3637     }
3638   }
3639
3640   /**
3641    * DOCUMENT ME!
3642    * 
3643    * @param e
3644    *          DOCUMENT ME!
3645    */
3646   @Override
3647   public void PCAMenuItem_actionPerformed(ActionEvent e)
3648   {
3649     if (((viewport.getSelectionGroup() != null)
3650             && (viewport.getSelectionGroup().getSize() < 4) && (viewport
3651             .getSelectionGroup().getSize() > 0))
3652             || (viewport.getAlignment().getHeight() < 4))
3653     {
3654       JOptionPane.showInternalMessageDialog(this,
3655               MessageManager.getString("label.principal_component_analysis_must_take_least_four_input_sequences"),
3656               MessageManager.getString("label.sequence_selection_insufficient"),
3657               JOptionPane.WARNING_MESSAGE);
3658
3659       return;
3660     }
3661
3662     new PCAPanel(alignPanel);
3663   }
3664
3665   @Override
3666   public void autoCalculate_actionPerformed(ActionEvent e)
3667   {
3668     viewport.autoCalculateConsensus = autoCalculate.isSelected();
3669     if (viewport.autoCalculateConsensus)
3670     {
3671       viewport.firePropertyChange("alignment", null, viewport
3672               .getAlignment().getSequences());
3673     }
3674   }
3675
3676   @Override
3677   public void sortByTreeOption_actionPerformed(ActionEvent e)
3678   {
3679     viewport.sortByTree = sortByTree.isSelected();
3680   }
3681
3682   @Override
3683   protected void listenToViewSelections_actionPerformed(ActionEvent e)
3684   {
3685     viewport.followSelection = listenToViewSelections.isSelected();
3686   }
3687
3688   /**
3689    * DOCUMENT ME!
3690    * 
3691    * @param e
3692    *          DOCUMENT ME!
3693    */
3694   @Override
3695   public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)
3696   {
3697     NewTreePanel("AV", "PID", "Average distance tree using PID");
3698   }
3699
3700   /**
3701    * DOCUMENT ME!
3702    * 
3703    * @param e
3704    *          DOCUMENT ME!
3705    */
3706   @Override
3707   public void neighbourTreeMenuItem_actionPerformed(ActionEvent e)
3708   {
3709     NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
3710   }
3711
3712   /**
3713    * DOCUMENT ME!
3714    * 
3715    * @param e
3716    *          DOCUMENT ME!
3717    */
3718   @Override
3719   protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)
3720   {
3721     NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
3722   }
3723
3724   /**
3725    * DOCUMENT ME!
3726    * 
3727    * @param e
3728    *          DOCUMENT ME!
3729    */
3730   @Override
3731   protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e)
3732   {
3733     NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
3734   }
3735
3736   /**
3737    * DOCUMENT ME!
3738    * 
3739    * @param type
3740    *          DOCUMENT ME!
3741    * @param pwType
3742    *          DOCUMENT ME!
3743    * @param title
3744    *          DOCUMENT ME!
3745    */
3746   void NewTreePanel(String type, String pwType, String title)
3747   {
3748     TreePanel tp;
3749
3750     if (viewport.getSelectionGroup() != null
3751             && viewport.getSelectionGroup().getSize() > 0)
3752     {
3753       if (viewport.getSelectionGroup().getSize() < 3)
3754       {
3755         JOptionPane
3756                 .showMessageDialog(
3757                         Desktop.desktop,
3758                         MessageManager.getString("label.you_need_more_two_sequences_selected_build_tree"),
3759                         MessageManager.getString("label.not_enough_sequences"), JOptionPane.WARNING_MESSAGE);
3760         return;
3761       }
3762
3763       SequenceGroup sg = viewport.getSelectionGroup();
3764
3765       /* Decide if the selection is a column region */
3766       for (SequenceI _s : sg.getSequences())
3767       {
3768         if (_s.getLength() < sg.getEndRes())
3769         {
3770           JOptionPane
3771                   .showMessageDialog(
3772                           Desktop.desktop,
3773                           MessageManager.getString("label.selected_region_to_tree_may_only_contain_residues_or_gaps"),
3774                           MessageManager.getString("label.sequences_selection_not_aligned"),
3775                           JOptionPane.WARNING_MESSAGE);
3776
3777           return;
3778         }
3779       }
3780
3781       title = title + " on region";
3782       tp = new TreePanel(alignPanel, type, pwType);
3783     }
3784     else
3785     {
3786       // are the visible sequences aligned?
3787       if (!viewport.getAlignment().isAligned(false))
3788       {
3789         JOptionPane
3790                 .showMessageDialog(
3791                         Desktop.desktop,
3792                         MessageManager.getString("label.sequences_must_be_aligned_before_creating_tree"),
3793                         MessageManager.getString("label.sequences_not_aligned"),
3794                         JOptionPane.WARNING_MESSAGE);
3795
3796         return;
3797       }
3798
3799       if (viewport.getAlignment().getHeight() < 2)
3800       {
3801         return;
3802       }
3803
3804       tp = new TreePanel(alignPanel, type, pwType);
3805     }
3806
3807     title += " from ";
3808
3809     if (viewport.viewName != null)
3810     {
3811       title += viewport.viewName + " of ";
3812     }
3813
3814     title += this.title;
3815
3816     Desktop.addInternalFrame(tp, title, 600, 500);
3817   }
3818
3819   /**
3820    * DOCUMENT ME!
3821    * 
3822    * @param title
3823    *          DOCUMENT ME!
3824    * @param order
3825    *          DOCUMENT ME!
3826    */
3827   public void addSortByOrderMenuItem(String title,
3828           final AlignmentOrder order)
3829   {
3830     final JMenuItem item = new JMenuItem("by " + title);
3831     sort.add(item);
3832     item.addActionListener(new java.awt.event.ActionListener()
3833     {
3834       @Override
3835       public void actionPerformed(ActionEvent e)
3836       {
3837         SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3838
3839         // TODO: JBPNote - have to map order entries to curent SequenceI
3840         // pointers
3841         AlignmentSorter.sortBy(viewport.getAlignment(), order);
3842
3843         addHistoryItem(new OrderCommand(order.getName(), oldOrder, viewport
3844                 .getAlignment()));
3845
3846         alignPanel.paintAlignment(true);
3847       }
3848     });
3849   }
3850
3851   /**
3852    * Add a new sort by annotation score menu item
3853    * 
3854    * @param sort
3855    *          the menu to add the option to
3856    * @param scoreLabel
3857    *          the label used to retrieve scores for each sequence on the
3858    *          alignment
3859    */
3860   public void addSortByAnnotScoreMenuItem(JMenu sort,
3861           final String scoreLabel)
3862   {
3863     final JMenuItem item = new JMenuItem(scoreLabel);
3864     sort.add(item);
3865     item.addActionListener(new java.awt.event.ActionListener()
3866     {
3867       @Override
3868       public void actionPerformed(ActionEvent e)
3869       {
3870         SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3871         AlignmentSorter.sortByAnnotationScore(scoreLabel,
3872                 viewport.getAlignment());// ,viewport.getSelectionGroup());
3873         addHistoryItem(new OrderCommand("Sort by " + scoreLabel, oldOrder,
3874                 viewport.getAlignment()));
3875         alignPanel.paintAlignment(true);
3876       }
3877     });
3878   }
3879
3880   /**
3881    * last hash for alignment's annotation array - used to minimise cost of
3882    * rebuild.
3883    */
3884   protected int _annotationScoreVectorHash;
3885
3886   /**
3887    * search the alignment and rebuild the sort by annotation score submenu the
3888    * last alignment annotation vector hash is stored to minimize cost of
3889    * rebuilding in subsequence calls.
3890    * 
3891    */
3892   @Override
3893   public void buildSortByAnnotationScoresMenu()
3894   {
3895     if (viewport.getAlignment().getAlignmentAnnotation() == null)
3896     {
3897       return;
3898     }
3899
3900     if (viewport.getAlignment().getAlignmentAnnotation().hashCode() != _annotationScoreVectorHash)
3901     {
3902       sortByAnnotScore.removeAll();
3903       // almost certainly a quicker way to do this - but we keep it simple
3904       Hashtable scoreSorts = new Hashtable();
3905       AlignmentAnnotation aann[];
3906       for (SequenceI sqa : viewport.getAlignment().getSequences())
3907       {
3908         aann = sqa.getAnnotation();
3909         for (int i = 0; aann != null && i < aann.length; i++)
3910         {
3911           if (aann[i].hasScore() && aann[i].sequenceRef != null)
3912           {
3913             scoreSorts.put(aann[i].label, aann[i].label);
3914           }
3915         }
3916       }
3917       Enumeration labels = scoreSorts.keys();
3918       while (labels.hasMoreElements())
3919       {
3920         addSortByAnnotScoreMenuItem(sortByAnnotScore,
3921                 (String) labels.nextElement());
3922       }
3923       sortByAnnotScore.setVisible(scoreSorts.size() > 0);
3924       scoreSorts.clear();
3925
3926       _annotationScoreVectorHash = viewport.getAlignment()
3927               .getAlignmentAnnotation().hashCode();
3928     }
3929   }
3930
3931   /**
3932    * Maintain the Order by->Displayed Tree menu. Creates a new menu item for a
3933    * TreePanel with an appropriate <code>jalview.analysis.AlignmentSorter</code>
3934    * call. Listeners are added to remove the menu item when the treePanel is
3935    * closed, and adjust the tree leaf to sequence mapping when the alignment is
3936    * modified.
3937    * 
3938    * @param treePanel
3939    *          Displayed tree window.
3940    * @param title
3941    *          SortBy menu item title.
3942    */
3943   @Override
3944   public void buildTreeMenu()
3945   {
3946     calculateTree.removeAll();
3947     // build the calculate menu
3948     
3949     for (final String type:new String[] {"NJ", "AV"})
3950     {
3951       String treecalcnm = MessageManager.getString("label.tree_calc_"+type.toLowerCase());
3952       for (final Object pwtype: ResidueProperties.scoreMatrices.keySet())
3953       {
3954         JMenuItem tm = new JMenuItem();
3955         ScoreModelI sm = ResidueProperties.scoreMatrices.get(pwtype);
3956         if (sm.isProtein()==!viewport.getAlignment().isNucleotide())
3957         {
3958           String smn = MessageManager.getStringOrReturn(
3959                   "label.score_model_", sm.getName());
3960           final String title = MessageManager.formatMessage(
3961                   "label.treecalc_title", treecalcnm, smn);
3962           tm.setText(title);//
3963           tm.addActionListener(new java.awt.event.ActionListener()
3964           {
3965             public void actionPerformed(ActionEvent e)
3966             {
3967               NewTreePanel(type, (String) pwtype, title);
3968             }
3969           });
3970           calculateTree.add(tm);
3971         }
3972
3973       }
3974     }
3975     sortByTreeMenu.removeAll();
3976
3977     Vector comps = (Vector) PaintRefresher.components.get(viewport
3978             .getSequenceSetId());
3979     Vector treePanels = new Vector();
3980     int i, iSize = comps.size();
3981     for (i = 0; i < iSize; i++)
3982     {
3983       if (comps.elementAt(i) instanceof TreePanel)
3984       {
3985         treePanels.add(comps.elementAt(i));
3986       }
3987     }
3988
3989     iSize = treePanels.size();
3990
3991     if (iSize < 1)
3992     {
3993       sortByTreeMenu.setVisible(false);
3994       return;
3995     }
3996
3997     sortByTreeMenu.setVisible(true);
3998
3999     for (i = 0; i < treePanels.size(); i++)
4000     {
4001       final TreePanel tp = (TreePanel) treePanels.elementAt(i);
4002       final JMenuItem item = new JMenuItem(tp.getTitle());
4003       final NJTree tree = ((TreePanel) treePanels.elementAt(i)).getTree();
4004       item.addActionListener(new java.awt.event.ActionListener()
4005       {
4006         @Override
4007         public void actionPerformed(ActionEvent e)
4008         {
4009           tp.sortByTree_actionPerformed(null);
4010           addHistoryItem(tp.sortAlignmentIn(alignPanel));
4011
4012         }
4013       });
4014
4015       sortByTreeMenu.add(item);
4016     }
4017   }
4018
4019   public boolean sortBy(AlignmentOrder alorder, String undoname)
4020   {
4021     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
4022     AlignmentSorter.sortBy(viewport.getAlignment(), alorder);
4023     if (undoname != null)
4024     {
4025       addHistoryItem(new OrderCommand(undoname, oldOrder,
4026               viewport.getAlignment()));
4027     }
4028     alignPanel.paintAlignment(true);
4029     return true;
4030   }
4031
4032   /**
4033    * Work out whether the whole set of sequences or just the selected set will
4034    * be submitted for multiple alignment.
4035    * 
4036    */
4037   public jalview.datamodel.AlignmentView gatherSequencesForAlignment()
4038   {
4039     // Now, check we have enough sequences
4040     AlignmentView msa = null;
4041
4042     if ((viewport.getSelectionGroup() != null)
4043             && (viewport.getSelectionGroup().getSize() > 1))
4044     {
4045       // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to
4046       // some common interface!
4047       /*
4048        * SequenceGroup seqs = viewport.getSelectionGroup(); int sz; msa = new
4049        * SequenceI[sz = seqs.getSize(false)];
4050        * 
4051        * for (int i = 0; i < sz; i++) { msa[i] = (SequenceI)
4052        * seqs.getSequenceAt(i); }
4053        */
4054       msa = viewport.getAlignmentView(true);
4055     }
4056     else
4057     {
4058       /*
4059        * Vector seqs = viewport.getAlignment().getSequences();
4060        * 
4061        * if (seqs.size() > 1) { msa = new SequenceI[seqs.size()];
4062        * 
4063        * for (int i = 0; i < seqs.size(); i++) { msa[i] = (SequenceI)
4064        * seqs.elementAt(i); } }
4065        */
4066       msa = viewport.getAlignmentView(false);
4067     }
4068     return msa;
4069   }
4070
4071   /**
4072    * Decides what is submitted to a secondary structure prediction service: the
4073    * first sequence in the alignment, or in the current selection, or, if the
4074    * alignment is 'aligned' (ie padded with gaps), then the currently selected
4075    * region or the whole alignment. (where the first sequence in the set is the
4076    * one that the prediction will be for).
4077    */
4078   public AlignmentView gatherSeqOrMsaForSecStrPrediction()
4079   {
4080     AlignmentView seqs = null;
4081
4082     if ((viewport.getSelectionGroup() != null)
4083             && (viewport.getSelectionGroup().getSize() > 0))
4084     {
4085       seqs = viewport.getAlignmentView(true);
4086     }
4087     else
4088     {
4089       seqs = viewport.getAlignmentView(false);
4090     }
4091     // limit sequences - JBPNote in future - could spawn multiple prediction
4092     // jobs
4093     // TODO: viewport.getAlignment().isAligned is a global state - the local
4094     // selection may well be aligned - we preserve 2.0.8 behaviour for moment.
4095     if (!viewport.getAlignment().isAligned(false))
4096     {
4097       seqs.setSequences(new SeqCigar[]
4098       { seqs.getSequences()[0] });
4099       // TODO: if seqs.getSequences().length>1 then should really have warned
4100       // user!
4101
4102     }
4103     return seqs;
4104   }
4105
4106   /**
4107    * DOCUMENT ME!
4108    * 
4109    * @param e
4110    *          DOCUMENT ME!
4111    */
4112   @Override
4113   protected void LoadtreeMenuItem_actionPerformed(ActionEvent e)
4114   {
4115     // Pick the tree file
4116     JalviewFileChooser chooser = new JalviewFileChooser(
4117             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
4118     chooser.setFileView(new JalviewFileView());
4119     chooser.setDialogTitle(MessageManager.getString("label.select_newick_like_tree_file"));\r
4120     chooser.setToolTipText(MessageManager.getString("label.load_tree_file"));\r
4121
4122     int value = chooser.showOpenDialog(null);
4123
4124     if (value == JalviewFileChooser.APPROVE_OPTION)
4125     {
4126       String choice = chooser.getSelectedFile().getPath();
4127       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
4128       jalview.io.NewickFile fin = null;
4129       try
4130       {
4131         fin = new jalview.io.NewickFile(choice, "File");
4132         viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
4133       } catch (Exception ex)
4134       {
4135         JOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(),
4136                 MessageManager.getString("label.problem_reading_tree_file"), JOptionPane.WARNING_MESSAGE);
4137         ex.printStackTrace();
4138       }
4139       if (fin != null && fin.hasWarningMessage())
4140       {
4141         JOptionPane.showMessageDialog(Desktop.desktop,
4142                 fin.getWarningMessage(), MessageManager.getString("label.possible_problem_with_tree_file"),
4143                 JOptionPane.WARNING_MESSAGE);
4144       }
4145     }
4146   }
4147
4148   @Override
4149   protected void tcoffeeColorScheme_actionPerformed(ActionEvent e)
4150   {
4151     changeColour(new TCoffeeColourScheme(alignPanel.getAlignment()));
4152   }
4153
4154   public TreePanel ShowNewickTree(NewickFile nf, String title)
4155   {
4156     return ShowNewickTree(nf, title, 600, 500, 4, 5);
4157   }
4158
4159   public TreePanel ShowNewickTree(NewickFile nf, String title,
4160           AlignmentView input)
4161   {
4162     return ShowNewickTree(nf, title, input, 600, 500, 4, 5);
4163   }
4164
4165   public TreePanel ShowNewickTree(NewickFile nf, String title, int w,
4166           int h, int x, int y)
4167   {
4168     return ShowNewickTree(nf, title, null, w, h, x, y);
4169   }
4170
4171   /**
4172    * Add a treeviewer for the tree extracted from a newick file object to the
4173    * current alignment view
4174    * 
4175    * @param nf
4176    *          the tree
4177    * @param title
4178    *          tree viewer title
4179    * @param input
4180    *          Associated alignment input data (or null)
4181    * @param w
4182    *          width
4183    * @param h
4184    *          height
4185    * @param x
4186    *          position
4187    * @param y
4188    *          position
4189    * @return TreePanel handle
4190    */
4191   public TreePanel ShowNewickTree(NewickFile nf, String title,
4192           AlignmentView input, int w, int h, int x, int y)
4193   {
4194     TreePanel tp = null;
4195
4196     try
4197     {
4198       nf.parse();
4199
4200       if (nf.getTree() != null)
4201       {
4202         tp = new TreePanel(alignPanel, "FromFile", title, nf, input);
4203
4204         tp.setSize(w, h);
4205
4206         if (x > 0 && y > 0)
4207         {
4208           tp.setLocation(x, y);
4209         }
4210
4211         Desktop.addInternalFrame(tp, title, w, h);
4212       }
4213     } catch (Exception ex)
4214     {
4215       ex.printStackTrace();
4216     }
4217
4218     return tp;
4219   }
4220
4221   private boolean buildingMenu = false;
4222
4223   /**
4224    * Generates menu items and listener event actions for web service clients
4225    * 
4226    */
4227   public void BuildWebServiceMenu()
4228   {
4229     while (buildingMenu)
4230     {
4231       try
4232       {
4233         System.err.println("Waiting for building menu to finish.");
4234         Thread.sleep(10);
4235       } catch (Exception e)
4236       {
4237       }
4238       ;
4239     }
4240     final AlignFrame me = this;
4241     buildingMenu = true;
4242     new Thread(new Runnable()
4243     {
4244       @Override
4245       public void run()
4246       {
4247         final List<JMenuItem> legacyItems=new ArrayList<JMenuItem>();
4248         try
4249         {
4250           System.err.println("Building ws menu again "
4251                   + Thread.currentThread());
4252           // TODO: add support for context dependent disabling of services based
4253           // on
4254           // alignment and current selection
4255           // TODO: add additional serviceHandle parameter to specify abstract
4256           // handler
4257           // class independently of AbstractName
4258           // TODO: add in rediscovery GUI function to restart discoverer
4259           // TODO: group services by location as well as function and/or
4260           // introduce
4261           // object broker mechanism.
4262           final Vector<JMenu> wsmenu = new Vector<JMenu>();
4263           final IProgressIndicator af = me;
4264           final JMenu msawsmenu = new JMenu("Alignment");
4265           final JMenu secstrmenu = new JMenu(
4266                   "Secondary Structure Prediction");
4267           final JMenu seqsrchmenu = new JMenu("Sequence Database Search");
4268           final JMenu analymenu = new JMenu("Analysis");
4269           final JMenu dismenu = new JMenu("Protein Disorder");
4270           // JAL-940 - only show secondary structure prediction services from
4271           // the legacy server
4272           if (// Cache.getDefault("SHOW_JWS1_SERVICES", true)
4273               // &&
4274           Discoverer.services != null && (Discoverer.services.size() > 0))
4275           {
4276             // TODO: refactor to allow list of AbstractName/Handler bindings to
4277             // be
4278             // stored or retrieved from elsewhere
4279             // No MSAWS used any more:
4280             // Vector msaws = null; // (Vector) Discoverer.services.get("MsaWS");
4281             Vector secstrpr = (Vector) Discoverer.services
4282                     .get("SecStrPred");
4283             if (secstrpr != null)
4284             {
4285               // Add any secondary structure prediction services
4286               for (int i = 0, j = secstrpr.size(); i < j; i++)
4287               {
4288                 final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr
4289                         .get(i);
4290                 jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
4291                         .getServiceClient(sh);
4292                 int p=secstrmenu.getItemCount();
4293                 impl.attachWSMenuEntry(secstrmenu, me);
4294                 int q=secstrmenu.getItemCount();
4295                 for (int litm=p;litm<q; litm++)
4296                 {
4297                   legacyItems.add(secstrmenu.getItem(litm));
4298                 }
4299               }
4300             }
4301           }
4302           
4303           // Add all submenus in the order they should appear on the web
4304           // services menu
4305           wsmenu.add(msawsmenu);
4306           wsmenu.add(secstrmenu);
4307           wsmenu.add(dismenu);
4308           wsmenu.add(analymenu);
4309           // No search services yet
4310           // wsmenu.add(seqsrchmenu);
4311
4312           javax.swing.SwingUtilities.invokeLater(new Runnable()
4313           {
4314             @Override
4315             public void run()
4316             {
4317               try
4318               {
4319                 webService.removeAll();
4320                 // first, add discovered services onto the webservices menu
4321                 if (wsmenu.size() > 0)
4322                 {
4323                   for (int i = 0, j = wsmenu.size(); i < j; i++)
4324                   {
4325                     webService.add(wsmenu.get(i));
4326                   }
4327                 }
4328                 else
4329                 {
4330                   webService.add(me.webServiceNoServices);
4331                 }
4332                 // TODO: move into separate menu builder class.
4333                 boolean new_sspred=false;
4334                 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
4335                 {
4336                   Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer();
4337                   if (jws2servs != null)
4338                   {
4339                     if (jws2servs.hasServices())
4340                     {
4341                       jws2servs.attachWSMenuEntry(webService, me);
4342                       for (Jws2Instance sv:jws2servs.getServices()) {
4343                         if (sv.description.toLowerCase().contains("jpred"))
4344                         {
4345                           for (JMenuItem jmi:legacyItems)
4346                           {
4347                             jmi.setVisible(false);
4348                           }
4349                         }
4350                       }
4351                       
4352                     }
4353                     if (jws2servs.isRunning())
4354                     {
4355                       JMenuItem tm = new JMenuItem(
4356                               "Still discovering JABA Services");
4357                       tm.setEnabled(false);
4358                       webService.add(tm);
4359                     }
4360                   }
4361                 }
4362                 build_urlServiceMenu(me.webService);
4363                 build_fetchdbmenu(webService);
4364                 for (JMenu item : wsmenu)
4365                 {
4366                   if (item.getItemCount() == 0)
4367                   {
4368                     item.setEnabled(false);
4369                   }
4370                   else
4371                   {
4372                     item.setEnabled(true);
4373                   }
4374                 }
4375               } catch (Exception e)
4376               {
4377                 Cache.log
4378                         .debug("Exception during web service menu building process.",
4379                                 e);
4380               }
4381               ;
4382             }
4383           });
4384         } catch (Exception e)
4385         {
4386         }
4387         ;
4388
4389         buildingMenu = false;
4390       }
4391     }).start();
4392
4393   }
4394
4395   /**
4396    * construct any groupURL type service menu entries.
4397    * 
4398    * @param webService
4399    */
4400   private void build_urlServiceMenu(JMenu webService)
4401   {
4402     // TODO: remove this code when 2.7 is released
4403     // DEBUG - alignmentView
4404     /*
4405      * JMenuItem testAlView = new JMenuItem("Test AlignmentView"); final
4406      * AlignFrame af = this; testAlView.addActionListener(new ActionListener() {
4407      * 
4408      * @Override public void actionPerformed(ActionEvent e) {
4409      * jalview.datamodel.AlignmentView
4410      * .testSelectionViews(af.viewport.getAlignment(),
4411      * af.viewport.getColumnSelection(), af.viewport.selectionGroup); }
4412      * 
4413      * }); webService.add(testAlView);
4414      */
4415     // TODO: refactor to RestClient discoverer and merge menu entries for
4416     // rest-style services with other types of analysis/calculation service
4417     // SHmmr test client - still being implemented.
4418     // DEBUG - alignmentView
4419
4420     for (jalview.ws.rest.RestClient client : jalview.ws.rest.RestClient
4421             .getRestClients())
4422     {
4423       client.attachWSMenuEntry(
4424               JvSwingUtils.findOrCreateMenu(webService, client.getAction()),
4425               this);
4426     }
4427
4428     if (Cache.getDefault("SHOW_ENFIN_SERVICES", true))
4429     {
4430       jalview.ws.EnfinEnvision2OneWay.getInstance().attachWSMenuEntry(
4431               webService, this);
4432     }
4433   }
4434
4435   /*
4436    * public void vamsasStore_actionPerformed(ActionEvent e) { JalviewFileChooser
4437    * chooser = new JalviewFileChooser(jalview.bin.Cache.
4438    * getProperty("LAST_DIRECTORY"));
4439    * 
4440    * chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle("Export
4441    * to Vamsas file"); chooser.setToolTipText("Export");
4442    * 
4443    * int value = chooser.showSaveDialog(this);
4444    * 
4445    * if (value == JalviewFileChooser.APPROVE_OPTION) {
4446    * jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport);
4447    * //vs.store(chooser.getSelectedFile().getAbsolutePath() ); vs.storeJalview(
4448    * chooser.getSelectedFile().getAbsolutePath(), this); } }
4449    */
4450   /**
4451    * prototype of an automatically enabled/disabled analysis function
4452    * 
4453    */
4454   protected void setShowProductsEnabled()
4455   {
4456     SequenceI[] selection = viewport.getSequenceSelection();
4457     if (canShowProducts(selection, viewport.getSelectionGroup() != null,
4458             viewport.getAlignment().getDataset()))
4459     {
4460       showProducts.setEnabled(true);
4461
4462     }
4463     else
4464     {
4465       showProducts.setEnabled(false);
4466     }
4467   }
4468
4469   /**
4470    * search selection for sequence xRef products and build the show products
4471    * menu.
4472    * 
4473    * @param selection
4474    * @param dataset
4475    * @return true if showProducts menu should be enabled.
4476    */
4477   public boolean canShowProducts(SequenceI[] selection,
4478           boolean isRegionSelection, Alignment dataset)
4479   {
4480     boolean showp = false;
4481     try
4482     {
4483       showProducts.removeAll();
4484       final boolean dna = viewport.getAlignment().isNucleotide();
4485       final Alignment ds = dataset;
4486       String[] ptypes = (selection == null || selection.length == 0) ? null
4487               : CrossRef.findSequenceXrefTypes(dna, selection, dataset);
4488       // Object[] prods =
4489       // CrossRef.buildXProductsList(viewport.getAlignment().isNucleotide(),
4490       // selection, dataset, true);
4491       final SequenceI[] sel = selection;
4492       for (int t = 0; ptypes != null && t < ptypes.length; t++)
4493       {
4494         showp = true;
4495         final boolean isRegSel = isRegionSelection;
4496         final AlignFrame af = this;
4497         final String source = ptypes[t];
4498         JMenuItem xtype = new JMenuItem(ptypes[t]);
4499         xtype.addActionListener(new ActionListener()
4500         {
4501
4502           @Override
4503           public void actionPerformed(ActionEvent e)
4504           {
4505             // TODO: new thread for this call with vis-delay
4506             af.showProductsFor(af.viewport.getSequenceSelection(), ds,
4507                     isRegSel, dna, source);
4508           }
4509
4510         });
4511         showProducts.add(xtype);
4512       }
4513       showProducts.setVisible(showp);
4514       showProducts.setEnabled(showp);
4515     } catch (Exception e)
4516     {
4517       jalview.bin.Cache.log
4518               .warn("canTranslate threw an exception - please report to help@jalview.org",
4519                       e);
4520       return false;
4521     }
4522     return showp;
4523   }
4524
4525   protected void showProductsFor(SequenceI[] sel, Alignment ds,
4526           boolean isRegSel, boolean dna, String source)
4527   {
4528     final boolean fisRegSel = isRegSel;
4529     final boolean fdna = dna;
4530     final String fsrc = source;
4531     final AlignFrame ths = this;
4532     final SequenceI[] fsel = sel;
4533     Runnable foo = new Runnable()
4534     {
4535
4536       @Override
4537       public void run()
4538       {
4539         final long sttime = System.currentTimeMillis();
4540         ths.setProgressBar("Searching for sequences from " + fsrc, sttime);
4541         try
4542         {
4543           Alignment ds = ths.getViewport().getAlignment().getDataset(); // update
4544           // our local
4545           // dataset
4546           // reference
4547           Alignment prods = CrossRef
4548                   .findXrefSequences(fsel, fdna, fsrc, ds);
4549           if (prods != null)
4550           {
4551             SequenceI[] sprods = new SequenceI[prods.getHeight()];
4552             for (int s = 0; s < sprods.length; s++)
4553             {
4554               sprods[s] = (prods.getSequenceAt(s)).deriveSequence();
4555               if (ds.getSequences() == null
4556                       || !ds.getSequences().contains(
4557                               sprods[s].getDatasetSequence()))
4558                 ds.addSequence(sprods[s].getDatasetSequence());
4559               sprods[s].updatePDBIds();
4560             }
4561             Alignment al = new Alignment(sprods);
4562             AlignedCodonFrame[] cf = prods.getCodonFrames();
4563             al.setDataset(ds);
4564             for (int s = 0; cf != null && s < cf.length; s++)
4565             {
4566               al.addCodonFrame(cf[s]);
4567               cf[s] = null;
4568             }
4569             AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH,
4570                     DEFAULT_HEIGHT);
4571             String newtitle = "" + ((fdna) ? "Proteins " : "Nucleotides ")
4572                     + " for " + ((fisRegSel) ? "selected region of " : "")
4573                     + getTitle();
4574             Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,
4575                     DEFAULT_HEIGHT);
4576           }
4577           else
4578           {
4579             System.err.println("No Sequences generated for xRef type "
4580                     + fsrc);
4581           }
4582         } catch (Exception e)
4583         {
4584           jalview.bin.Cache.log.error(
4585                   "Exception when finding crossreferences", e);
4586         } catch (OutOfMemoryError e)
4587         {
4588           new OOMWarning("whilst fetching crossreferences", e);
4589         } catch (Error e)
4590         {
4591           jalview.bin.Cache.log.error("Error when finding crossreferences",
4592                   e);
4593         }
4594         ths.setProgressBar("Finished searching for sequences from " + fsrc,
4595                 sttime);
4596       }
4597
4598     };
4599     Thread frunner = new Thread(foo);
4600     frunner.start();
4601   }
4602
4603   public boolean canShowTranslationProducts(SequenceI[] selection,
4604           AlignmentI alignment)
4605   {
4606     // old way
4607     try
4608     {
4609       return (jalview.analysis.Dna.canTranslate(selection,
4610               viewport.getViewAsVisibleContigs(true)));
4611     } catch (Exception e)
4612     {
4613       jalview.bin.Cache.log
4614               .warn("canTranslate threw an exception - please report to help@jalview.org",
4615                       e);
4616       return false;
4617     }
4618   }
4619
4620   @Override
4621   public void showProducts_actionPerformed(ActionEvent e)
4622   {
4623     // /////////////////////////////
4624     // Collect Data to be translated/transferred
4625
4626     SequenceI[] selection = viewport.getSequenceSelection();
4627     AlignmentI al = null;
4628     try
4629     {
4630       al = jalview.analysis.Dna.CdnaTranslate(selection, viewport
4631               .getViewAsVisibleContigs(true), viewport.getGapCharacter(),
4632               viewport.getAlignment().getDataset());
4633     } catch (Exception ex)
4634     {
4635       al = null;
4636       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4637     }
4638     if (al == null)
4639     {
4640       JOptionPane
4641               .showMessageDialog(
4642                       Desktop.desktop,
4643                       MessageManager.getString("label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation"),
4644                       MessageManager.getString("label.translation_failed"), JOptionPane.WARNING_MESSAGE);
4645     }
4646     else
4647     {
4648       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4649       Desktop.addInternalFrame(af, MessageManager.formatMessage("label.translation_of_params", new String[]{this.getTitle()}),\r
4650               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4651     }
4652   }
4653
4654   @Override
4655   public void showTranslation_actionPerformed(ActionEvent e)
4656   {
4657     // /////////////////////////////
4658     // Collect Data to be translated/transferred
4659
4660     SequenceI[] selection = viewport.getSequenceSelection();
4661     String[] seqstring = viewport.getViewAsString(true);
4662     AlignmentI al = null;
4663     try
4664     {
4665       al = jalview.analysis.Dna.CdnaTranslate(selection, seqstring,
4666               viewport.getViewAsVisibleContigs(true), viewport
4667                       .getGapCharacter(), viewport.getAlignment()
4668                       .getAlignmentAnnotation(), viewport.getAlignment()
4669                       .getWidth(), viewport.getAlignment().getDataset());
4670     } catch (Exception ex)
4671     {
4672       al = null;
4673       jalview.bin.Cache.log.error("Exception during translation. Please report this !", ex);
4674       JOptionPane
4675       .showMessageDialog(
4676               Desktop.desktop,
4677               MessageManager.getString("label.error_when_translating_sequences_submit_bug_report"),
4678               MessageManager.getString("label.implementation_error") + MessageManager.getString("translation_failed"), JOptionPane.ERROR_MESSAGE);
4679       return;
4680     }
4681     if (al == null)
4682     {
4683       JOptionPane
4684               .showMessageDialog(
4685                       Desktop.desktop,
4686                       MessageManager.getString("label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation"),
4687                       MessageManager.getString("label.translation_failed"), JOptionPane.WARNING_MESSAGE);
4688     }
4689     else
4690     {
4691       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4692       Desktop.addInternalFrame(af, MessageManager.formatMessage("label.translation_of_params", new String[]{this.getTitle()}),\r
4693               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4694     }
4695   }
4696
4697   /**
4698    * Try to load a features file onto the alignment.
4699    * 
4700    * @param file
4701    *          contents or path to retrieve file
4702    * @param type
4703    *          access mode of file (see jalview.io.AlignFile)
4704    * @return true if features file was parsed corectly.
4705    */
4706   public boolean parseFeaturesFile(String file, String type)
4707   {
4708     boolean featuresFile = false;
4709     try
4710     {
4711       featuresFile = new FeaturesFile(file, type).parse(viewport
4712               .getAlignment().getDataset(), alignPanel.seqPanel.seqCanvas
4713               .getFeatureRenderer().featureColours, false,
4714               jalview.bin.Cache.getDefault("RELAXEDSEQIDMATCHING", false));
4715     } catch (Exception ex)
4716     {
4717       ex.printStackTrace();
4718     }
4719
4720     if (featuresFile)
4721     {
4722       viewport.showSequenceFeatures = true;
4723       showSeqFeatures.setSelected(true);
4724       if (alignPanel.seqPanel.seqCanvas.fr != null)
4725       {
4726         // update the min/max ranges where necessary
4727         alignPanel.seqPanel.seqCanvas.fr.findAllFeatures(true);
4728       }
4729       if (featureSettings != null)
4730       {
4731         featureSettings.setTableData();
4732       }
4733       alignPanel.paintAlignment(true);
4734     }
4735
4736     return featuresFile;
4737   }
4738
4739   @Override
4740   public void dragEnter(DropTargetDragEvent evt)
4741   {
4742   }
4743
4744   @Override
4745   public void dragExit(DropTargetEvent evt)
4746   {
4747   }
4748
4749   @Override
4750   public void dragOver(DropTargetDragEvent evt)
4751   {
4752   }
4753
4754   @Override
4755   public void dropActionChanged(DropTargetDragEvent evt)
4756   {
4757   }
4758
4759   @Override
4760   public void drop(DropTargetDropEvent evt)
4761   {
4762     Transferable t = evt.getTransferable();
4763     java.util.List files = null;
4764
4765     try
4766     {
4767       DataFlavor uriListFlavor = new DataFlavor(
4768               "text/uri-list;class=java.lang.String");
4769       if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
4770       {
4771         // Works on Windows and MacOSX
4772         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4773         files = (java.util.List) t
4774                 .getTransferData(DataFlavor.javaFileListFlavor);
4775       }
4776       else if (t.isDataFlavorSupported(uriListFlavor))
4777       {
4778         // This is used by Unix drag system
4779         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4780         String data = (String) t.getTransferData(uriListFlavor);
4781         files = new java.util.ArrayList(1);
4782         for (java.util.StringTokenizer st = new java.util.StringTokenizer(
4783                 data, "\r\n"); st.hasMoreTokens();)
4784         {
4785           String s = st.nextToken();
4786           if (s.startsWith("#"))
4787           {
4788             // the line is a comment (as per the RFC 2483)
4789             continue;
4790           }
4791
4792           java.net.URI uri = new java.net.URI(s);
4793           // check to see if we can handle this kind of URI
4794           if (uri.getScheme().toLowerCase().startsWith("http"))
4795           {
4796             files.add(uri.toString());
4797           }
4798           else
4799           {
4800             // otherwise preserve old behaviour: catch all for file objects
4801             java.io.File file = new java.io.File(uri);
4802             files.add(file.toString());
4803           }
4804         }
4805       }
4806     } catch (Exception e)
4807     {
4808       e.printStackTrace();
4809     }
4810     if (files != null)
4811     {
4812       try
4813       {
4814         // check to see if any of these files have names matching sequences in
4815         // the alignment
4816         SequenceIdMatcher idm = new SequenceIdMatcher(viewport
4817                 .getAlignment().getSequencesArray());
4818         /**
4819          * Object[] { String,SequenceI}
4820          */
4821         ArrayList<Object[]> filesmatched = new ArrayList<Object[]>();
4822         ArrayList<String> filesnotmatched = new ArrayList<String>();
4823         for (int i = 0; i < files.size(); i++)
4824         {
4825           String file = files.get(i).toString();
4826           String pdbfn = "";
4827           String protocol = FormatAdapter.checkProtocol(file);
4828           if (protocol == jalview.io.FormatAdapter.FILE)
4829           {
4830             File fl = new File(file);
4831             pdbfn = fl.getName();
4832           }
4833           else if (protocol == jalview.io.FormatAdapter.URL)
4834           {
4835             URL url = new URL(file);
4836             pdbfn = url.getFile();
4837           }
4838           if (pdbfn.length() > 0)
4839           {
4840             // attempt to find a match in the alignment
4841             SequenceI[] mtch = idm.findAllIdMatches(pdbfn);
4842             int l = 0, c = pdbfn.indexOf(".");
4843             while (mtch == null && c != -1)
4844             {
4845               do
4846               {
4847                 l = c;
4848               } while ((c = pdbfn.indexOf(".", l)) > l);
4849               if (l > -1)
4850               {
4851                 pdbfn = pdbfn.substring(0, l);
4852               }
4853               mtch = idm.findAllIdMatches(pdbfn);
4854             }
4855             if (mtch != null)
4856             {
4857               String type = null;
4858               try
4859               {
4860                 type = new IdentifyFile().Identify(file, protocol);
4861               } catch (Exception ex)
4862               {
4863                 type = null;
4864               }
4865               if (type != null)
4866               {
4867                 if (type.equalsIgnoreCase("PDB"))
4868                 {
4869                   filesmatched.add(new Object[]
4870                   { file, protocol, mtch });
4871                   continue;
4872                 }
4873               }
4874             }
4875             // File wasn't named like one of the sequences or wasn't a PDB file.
4876             filesnotmatched.add(file);
4877           }
4878         }
4879         int assocfiles = 0;
4880         if (filesmatched.size() > 0)
4881         {
4882           if (Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false)
4883                   || JOptionPane
4884                           .showConfirmDialog(
4885                                   this,
4886                                   MessageManager.formatMessage("label.automatically_associate_pdb_files_with_sequences_same_name",
4887                                                   new String[]{Integer.valueOf(filesmatched.size()).toString()}),
4888                                   MessageManager.getString("label.automatically_associate_pdb_files_by_name"),
4889                                   JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
4890
4891           {
4892             for (Object[] fm : filesmatched)
4893             {
4894               // try and associate
4895               // TODO: may want to set a standard ID naming formalism for
4896               // associating PDB files which have no IDs.
4897               for (SequenceI toassoc : (SequenceI[]) fm[2])
4898               {
4899                 PDBEntry pe = new AssociatePdbFileWithSeq()
4900                         .associatePdbWithSeq((String) fm[0],
4901                                 (String) fm[1], toassoc, false);
4902                 if (pe != null)
4903                 {
4904                   System.err.println("Associated file : "
4905                           + ((String) fm[0]) + " with "
4906                           + toassoc.getDisplayId(true));
4907                   assocfiles++;
4908                 }
4909               }
4910               alignPanel.paintAlignment(true);
4911             }
4912           }
4913         }
4914         if (filesnotmatched.size() > 0)
4915         {
4916           if (assocfiles > 0
4917                   && (Cache.getDefault(
4918                           "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false) || JOptionPane
4919                           .showConfirmDialog(
4920                                   this,
4921                                   MessageManager.formatMessage("label.ignore_unmatched_dropped_files_info", new String[]{Integer.valueOf(filesnotmatched.size()).toString()}),
4922                                   MessageManager.getString("label.ignore_unmatched_dropped_files"),
4923                                   JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))
4924           {
4925             return;
4926           }
4927           for (String fn : filesnotmatched)
4928           {
4929             loadJalviewDataFile(fn, null, null, null);
4930           }
4931
4932         }
4933       } catch (Exception ex)
4934       {
4935         ex.printStackTrace();
4936       }
4937     }
4938   }
4939
4940   /**
4941    * Attempt to load a "dropped" file or URL string: First by testing whether
4942    * it's and Annotation file, then a JNet file, and finally a features file. If
4943    * all are false then the user may have dropped an alignment file onto this
4944    * AlignFrame.
4945    * 
4946    * @param file
4947    *          either a filename or a URL string.
4948    */
4949   public void loadJalviewDataFile(String file, String protocol,
4950           String format, SequenceI assocSeq)
4951   {
4952     try
4953     {
4954       if (protocol == null)
4955       {
4956         protocol = jalview.io.FormatAdapter.checkProtocol(file);
4957       }
4958       // if the file isn't identified, or not positively identified as some
4959       // other filetype (PFAM is default unidentified alignment file type) then
4960       // try to parse as annotation.
4961       boolean isAnnotation = (format == null || format
4962               .equalsIgnoreCase("PFAM")) ? new AnnotationFile()
4963               .readAnnotationFile(viewport.getAlignment(), file, protocol)
4964               : false;
4965
4966       if (!isAnnotation)
4967       {
4968         // first see if its a T-COFFEE score file
4969         TCoffeeScoreFile tcf = null;
4970         try
4971         {
4972           tcf = new TCoffeeScoreFile(file, protocol);
4973           if (tcf.isValid())
4974           {
4975             if (tcf.annotateAlignment(viewport.getAlignment(), true))
4976             {
4977               tcoffeeColour.setEnabled(true);
4978               tcoffeeColour.setSelected(true);
4979               changeColour(new TCoffeeColourScheme(viewport.getAlignment()));
4980               isAnnotation = true;
4981               statusBar.setText(MessageManager.getString("label.successfully_pasted_tcoffee_scores_to_alignment"));
4982             }
4983             else
4984             {
4985               // some problem - if no warning its probable that the ID matching
4986               // process didn't work
4987               JOptionPane
4988                       .showMessageDialog(
4989                               Desktop.desktop,
4990                               tcf.getWarningMessage() == null ? MessageManager.getString("label.check_file_matches_sequence_ids_alignment")
4991                                       : tcf.getWarningMessage(),
4992                               MessageManager.getString("label.problem_reading_tcoffee_score_file"),
4993                               JOptionPane.WARNING_MESSAGE);
4994             }
4995           }
4996           else
4997           {
4998             tcf = null;
4999           }
5000         } catch (Exception x)
5001         {
5002           Cache.log
5003                   .debug("Exception when processing data source as T-COFFEE score file",
5004                           x);
5005           tcf = null;
5006         }
5007         if (tcf == null)
5008         {
5009           // try to see if its a JNet 'concise' style annotation file *before*
5010           // we
5011           // try to parse it as a features file
5012           if (format == null)
5013           {
5014             format = new IdentifyFile().Identify(file, protocol);
5015           }
5016           if (format.equalsIgnoreCase("JnetFile"))
5017           {
5018             jalview.io.JPredFile predictions = new jalview.io.JPredFile(
5019                     file, protocol);
5020             new JnetAnnotationMaker().add_annotation(predictions,
5021                     viewport.getAlignment(), 0, false);
5022             isAnnotation = true;
5023           }
5024           else
5025           {
5026             /*
5027              * if (format.equalsIgnoreCase("PDB")) {
5028              * 
5029              * String pdbfn = ""; // try to match up filename with sequence id
5030              * try { if (protocol == jalview.io.FormatAdapter.FILE) { File fl =
5031              * new File(file); pdbfn = fl.getName(); } else if (protocol ==
5032              * jalview.io.FormatAdapter.URL) { URL url = new URL(file); pdbfn =
5033              * url.getFile(); } } catch (Exception e) { } ; if (assocSeq ==
5034              * null) { SequenceIdMatcher idm = new SequenceIdMatcher(viewport
5035              * .getAlignment().getSequencesArray()); if (pdbfn.length() > 0) {
5036              * // attempt to find a match in the alignment SequenceI mtch =
5037              * idm.findIdMatch(pdbfn); int l = 0, c = pdbfn.indexOf("."); while
5038              * (mtch == null && c != -1) { while ((c = pdbfn.indexOf(".", l)) >
5039              * l) { l = c; } if (l > -1) { pdbfn = pdbfn.substring(0, l); } mtch
5040              * = idm.findIdMatch(pdbfn); } if (mtch != null) { // try and
5041              * associate // prompt ? PDBEntry pe = new AssociatePdbFileWithSeq()
5042              * .associatePdbWithSeq(file, protocol, mtch, true); if (pe != null)
5043              * { System.err.println("Associated file : " + file + " with " +
5044              * mtch.getDisplayId(true)); alignPanel.paintAlignment(true); } } //
5045              * TODO: maybe need to load as normal otherwise return; } }
5046              */
5047             // try to parse it as a features file
5048             boolean isGroupsFile = parseFeaturesFile(file, protocol);
5049             // if it wasn't a features file then we just treat it as a general
5050             // alignment file to load into the current view.
5051             if (!isGroupsFile)
5052             {
5053               new FileLoader().LoadFile(viewport, file, protocol, format);
5054             }
5055             else
5056             {
5057               alignPanel.paintAlignment(true);
5058             }
5059           }
5060         }
5061       }
5062       if (isAnnotation)
5063       {
5064
5065         alignPanel.adjustAnnotationHeight();
5066         viewport.updateSequenceIdColours();
5067         buildSortByAnnotationScoresMenu();
5068         alignPanel.paintAlignment(true);
5069       }
5070     } catch (Exception ex)
5071     {
5072       ex.printStackTrace();
5073     } catch (OutOfMemoryError oom)
5074     {
5075       try
5076       {
5077         System.gc();
5078       } catch (Exception x)
5079       {
5080       }
5081       ;
5082       new OOMWarning(
5083               "loading data "
5084                       + (protocol != null ? (protocol.equals(FormatAdapter.PASTE) ? "from clipboard."
5085                               : "using " + protocol + " from " + file)
5086                               : ".")
5087                       + (format != null ? "(parsing as '" + format
5088                               + "' file)" : ""), oom, Desktop.desktop);
5089     }
5090   }
5091
5092   @Override
5093   public void tabSelectionChanged(int index)
5094   {
5095     if (index > -1)
5096     {
5097       alignPanel = (AlignmentPanel) alignPanels.elementAt(index);
5098       viewport = alignPanel.av;
5099       avc.setViewportAndAlignmentPanel(viewport, alignPanel);
5100       setMenusFromViewport(viewport);
5101     }
5102   }
5103
5104   @Override
5105   public void tabbedPane_mousePressed(MouseEvent e)
5106   {
5107     if (SwingUtilities.isRightMouseButton(e))
5108     {
5109       String reply = JOptionPane.showInternalInputDialog(this,
5110               MessageManager.getString("label.enter_view_name"), MessageManager.getString("label.enter_view_name"),
5111               JOptionPane.QUESTION_MESSAGE);
5112
5113       if (reply != null)
5114       {
5115         viewport.viewName = reply;
5116         tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
5117       }
5118     }
5119   }
5120
5121   public AlignViewport getCurrentView()
5122   {
5123     return viewport;
5124   }
5125
5126   /**
5127    * Open the dialog for regex description parsing.
5128    */
5129   @Override
5130   protected void extractScores_actionPerformed(ActionEvent e)
5131   {
5132     ParseProperties pp = new jalview.analysis.ParseProperties(
5133             viewport.getAlignment());
5134     // TODO: verify regex and introduce GUI dialog for version 2.5
5135     // if (pp.getScoresFromDescription("col", "score column ",
5136     // "\\W*([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)",
5137     // true)>0)
5138     if (pp.getScoresFromDescription("description column",
5139             "score in description column ", "\\W*([-+eE0-9.]+)", true) > 0)
5140     {
5141       buildSortByAnnotationScoresMenu();
5142     }
5143   }
5144
5145   /*
5146    * (non-Javadoc)
5147    * 
5148    * @see
5149    * jalview.jbgui.GAlignFrame#showDbRefs_actionPerformed(java.awt.event.ActionEvent
5150    * )
5151    */
5152   @Override
5153   protected void showDbRefs_actionPerformed(ActionEvent e)
5154   {
5155     viewport.setShowDbRefs(showDbRefsMenuitem.isSelected());
5156   }
5157
5158   /*
5159    * (non-Javadoc)
5160    * 
5161    * @seejalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event.
5162    * ActionEvent)
5163    */
5164   @Override
5165   protected void showNpFeats_actionPerformed(ActionEvent e)
5166   {
5167     viewport.setShowNpFeats(showNpFeatsMenuitem.isSelected());
5168   }
5169
5170   /**
5171    * find the viewport amongst the tabs in this alignment frame and close that
5172    * tab
5173    * 
5174    * @param av
5175    */
5176   public boolean closeView(AlignViewport av)
5177   {
5178     if (viewport == av)
5179     {
5180       this.closeMenuItem_actionPerformed(false);
5181       return true;
5182     }
5183     Component[] comp = tabbedPane.getComponents();
5184     for (int i = 0; comp != null && i < comp.length; i++)
5185     {
5186       if (comp[i] instanceof AlignmentPanel)
5187       {
5188         if (((AlignmentPanel) comp[i]).av == av)
5189         {
5190           // close the view.
5191           closeView((AlignmentPanel) comp[i]);
5192           return true;
5193         }
5194       }
5195     }
5196     return false;
5197   }
5198
5199   protected void build_fetchdbmenu(JMenu webService)
5200   {
5201     // Temporary hack - DBRef Fetcher always top level ws entry.
5202     // TODO We probably want to store a sequence database checklist in
5203     // preferences and have checkboxes.. rather than individual sources selected
5204     // here
5205     final JMenu rfetch = new JMenu(MessageManager.getString("action.fetch_db_references"));\r
5206     rfetch.setToolTipText(MessageManager.getString("label.retrieve_parse_sequence_database_records_alignment_or_selected_sequences"));\r
5207     webService.add(rfetch);
5208
5209     final JCheckBoxMenuItem trimrs = new JCheckBoxMenuItem(MessageManager.getString("option.trim_retrieved_seqs"));
5210     trimrs.setToolTipText(MessageManager.getString("label.trim_retrieved_sequences"));
5211     trimrs.setSelected(Cache.getDefault("TRIM_FETCHED_DATASET_SEQS", true));
5212     trimrs.addActionListener(new ActionListener()
5213     {
5214       public void actionPerformed(ActionEvent e) {
5215       trimrs.setSelected(trimrs.isSelected());
5216       Cache.setProperty("TRIM_FETCHED_DATASET_SEQS", Boolean.valueOf(trimrs.isSelected()).toString());
5217     };
5218     });
5219     rfetch.add(trimrs);
5220     JMenuItem fetchr = new JMenuItem(MessageManager.getString("label.standard_databases"));\r
5221     fetchr.setToolTipText(MessageManager.getString("label.fetch_embl_uniprot"));\r
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(), alignPanel.alignFrame)
5236                     .fetchDBRefs(false);
5237           }
5238         }).start();
5239
5240       }
5241
5242     });
5243     rfetch.add(fetchr);
5244     final AlignFrame me = this;
5245     new Thread(new Runnable()
5246     {
5247       @Override
5248       public void run()
5249       {
5250         final jalview.ws.SequenceFetcher sf = SequenceFetcher
5251                 .getSequenceFetcherSingleton(me);
5252         javax.swing.SwingUtilities.invokeLater(new Runnable()
5253         {
5254           @Override
5255           public void run()
5256           {
5257             String[] dbclasses = sf.getOrderedSupportedSources();
5258             // sf.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);
5259             // jalview.util.QuickSort.sort(otherdb, otherdb);
5260             List<DbSourceProxy> otherdb;
5261             JMenu dfetch = new JMenu();
5262             JMenu ifetch = new JMenu();
5263             JMenuItem fetchr = null;
5264             int comp = 0, icomp = 0, mcomp = 15;
5265             String mname = null;
5266             int dbi = 0;
5267             for (String dbclass : dbclasses)
5268             {
5269               otherdb = sf.getSourceProxy(dbclass);
5270               // add a single entry for this class, or submenu allowing 'fetch
5271               // all' or pick one
5272               if (otherdb == null || otherdb.size() < 1)
5273               {
5274                 continue;
5275               }
5276               // List<DbSourceProxy> dbs=otherdb;
5277               // otherdb=new ArrayList<DbSourceProxy>();
5278               // for (DbSourceProxy db:dbs)
5279               // {
5280               // if (!db.isA(DBRefSource.ALIGNMENTDB)
5281               // }
5282               if (mname == null)
5283               {
5284                 mname = "From " + dbclass;
5285               }
5286               if (otherdb.size() == 1)
5287               {
5288                 final DbSourceProxy[] dassource = otherdb
5289                         .toArray(new DbSourceProxy[0]);
5290                 DbSourceProxy src = otherdb.get(0);
5291                 fetchr = new JMenuItem(src.getDbSource());
5292                 fetchr.addActionListener(new ActionListener()
5293                 {
5294
5295                   @Override
5296                   public void actionPerformed(ActionEvent e)
5297                   {
5298                     new Thread(new Runnable()
5299                     {
5300
5301                       @Override
5302                       public void run()
5303                       {
5304                         new jalview.ws.DBRefFetcher(alignPanel.av
5305                                 .getSequenceSelection(),
5306                                 alignPanel.alignFrame, dassource)
5307                                 .fetchDBRefs(false);
5308                       }
5309                     }).start();
5310                   }
5311
5312                 });
5313                 fetchr.setToolTipText("<html>"
5314                         + JvSwingUtils.wrapTooltip("Retrieve from "
5315                                 + src.getDbName()) + "<html>");
5316                 dfetch.add(fetchr);
5317                 comp++;
5318               }
5319               else
5320               {
5321                 final DbSourceProxy[] dassource = otherdb
5322                         .toArray(new DbSourceProxy[0]);
5323                 // fetch all entry
5324                 DbSourceProxy src = otherdb.get(0);
5325                 fetchr = new JMenuItem(MessageManager.formatMessage("label.fetch_all_param", new String[]{src.getDbSource()}));\r
5326                 fetchr.addActionListener(new ActionListener()
5327                 {
5328                   @Override
5329                   public void actionPerformed(ActionEvent e)
5330                   {
5331                     new Thread(new Runnable()
5332                     {
5333
5334                       @Override
5335                       public void run()
5336                       {
5337                         new jalview.ws.DBRefFetcher(alignPanel.av
5338                                 .getSequenceSelection(),
5339                                 alignPanel.alignFrame, dassource)
5340                                 .fetchDBRefs(false);
5341                       }
5342                     }).start();
5343                   }
5344                 });
5345
5346                 fetchr.setToolTipText("<html>"
5347                         + JvSwingUtils.wrapTooltip("Retrieve from all "
5348                                 + otherdb.size() + " sources in "
5349                                 + src.getDbSource() + "<br>First is :"
5350                                 + src.getDbName()) + "<html>");
5351                 dfetch.add(fetchr);
5352                 comp++;
5353                 // and then build the rest of the individual menus
5354                 ifetch = new JMenu("Sources from " + src.getDbSource());
5355                 icomp = 0;
5356                 String imname = null;
5357                 int i = 0;
5358                 for (DbSourceProxy sproxy : otherdb)
5359                 {
5360                   String dbname = sproxy.getDbName();
5361                   String sname = dbname.length() > 5 ? dbname.substring(0,
5362                           5) + "..." : dbname;
5363                   String msname = dbname.length() > 10 ? dbname.substring(
5364                           0, 10) + "..." : dbname;
5365                   if (imname == null)
5366                   {
5367                     imname = "from '" + sname + "'";
5368                   }
5369                   fetchr = new JMenuItem(msname);
5370                   final DbSourceProxy[] dassrc =
5371                   { sproxy };
5372                   fetchr.addActionListener(new ActionListener()
5373                   {
5374
5375                     @Override
5376                     public void actionPerformed(ActionEvent e)
5377                     {
5378                       new Thread(new Runnable()
5379                       {
5380
5381                         @Override
5382                         public void run()
5383                         {
5384                           new jalview.ws.DBRefFetcher(alignPanel.av
5385                                   .getSequenceSelection(),
5386                                   alignPanel.alignFrame, dassrc)
5387                                   .fetchDBRefs(false);
5388                         }
5389                       }).start();
5390                     }
5391
5392                   });
5393                   fetchr.setToolTipText("<html>"
5394                           + JvSwingUtils.wrapTooltip("Retrieve from "
5395                                   + dbname) + "</html>");
5396                   ifetch.add(fetchr);
5397                   ++i;
5398                   if (++icomp >= mcomp || i == (otherdb.size()))
5399                   {
5400                     ifetch.setText(MessageManager.formatMessage("label.source_to_target",imname,sname));
5401                     dfetch.add(ifetch);
5402                     ifetch = new JMenu();
5403                     imname = null;
5404                     icomp = 0;
5405                     comp++;
5406                   }
5407                 }
5408               }
5409               ++dbi;
5410               if (comp >= mcomp || dbi >= (dbclasses.length))
5411               {
5412                 dfetch.setText(MessageManager.formatMessage("label.source_to_target",mname,dbclass));
5413                 rfetch.add(dfetch);
5414                 dfetch = new JMenu();
5415                 mname = null;
5416                 comp = 0;
5417               }
5418             }
5419           }
5420         });
5421       }
5422     }).start();
5423
5424   }
5425
5426   /**
5427    * Left justify the whole alignment.
5428    */
5429   @Override
5430   protected void justifyLeftMenuItem_actionPerformed(ActionEvent e)
5431   {
5432     AlignmentI al = viewport.getAlignment();
5433     al.justify(false);
5434     viewport.firePropertyChange("alignment", null, al);
5435   }
5436
5437   /**
5438    * Right justify the whole alignment.
5439    */
5440   @Override
5441   protected void justifyRightMenuItem_actionPerformed(ActionEvent e)
5442   {
5443     AlignmentI al = viewport.getAlignment();
5444     al.justify(true);
5445     viewport.firePropertyChange("alignment", null, al);
5446   }
5447
5448   public void setShowSeqFeatures(boolean b)
5449   {
5450     showSeqFeatures.setSelected(true);
5451     viewport.setShowSequenceFeatures(true);
5452   }
5453
5454   /*
5455    * (non-Javadoc)
5456    * 
5457    * @see
5458    * jalview.jbgui.GAlignFrame#showUnconservedMenuItem_actionPerformed(java.
5459    * awt.event.ActionEvent)
5460    */
5461   @Override
5462   protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)
5463   {
5464     viewport.setShowUnconserved(showNonconservedMenuItem.getState());
5465     alignPanel.paintAlignment(true);
5466   }
5467
5468   /*
5469    * (non-Javadoc)
5470    * 
5471    * @see
5472    * jalview.jbgui.GAlignFrame#showGroupConsensus_actionPerformed(java.awt.event
5473    * .ActionEvent)
5474    */
5475   @Override
5476   protected void showGroupConsensus_actionPerformed(ActionEvent e)
5477   {
5478     viewport.setShowGroupConsensus(showGroupConsensus.getState());
5479     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5480
5481   }
5482
5483   /*
5484    * (non-Javadoc)
5485    * 
5486    * @see
5487    * jalview.jbgui.GAlignFrame#showGroupConservation_actionPerformed(java.awt
5488    * .event.ActionEvent)
5489    */
5490   @Override
5491   protected void showGroupConservation_actionPerformed(ActionEvent e)
5492   {
5493     viewport.setShowGroupConservation(showGroupConservation.getState());
5494     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5495   }
5496
5497   /*
5498    * (non-Javadoc)
5499    * 
5500    * @see
5501    * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt
5502    * .event.ActionEvent)
5503    */
5504   @Override
5505   protected void showConsensusHistogram_actionPerformed(ActionEvent e)
5506   {
5507     viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
5508     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5509   }
5510
5511   /*
5512    * (non-Javadoc)
5513    * 
5514    * @see
5515    * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt
5516    * .event.ActionEvent)
5517    */
5518   @Override
5519   protected void showSequenceLogo_actionPerformed(ActionEvent e)
5520   {
5521     viewport.setShowSequenceLogo(showSequenceLogo.getState());
5522     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5523   }
5524
5525   @Override
5526   protected void normaliseSequenceLogo_actionPerformed(ActionEvent e)
5527   {
5528     showSequenceLogo.setState(true);
5529     viewport.setShowSequenceLogo(true);
5530     viewport.setNormaliseSequenceLogo(normaliseSequenceLogo.getState());
5531     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5532   }
5533
5534   @Override
5535   protected void applyAutoAnnotationSettings_actionPerformed(ActionEvent e)
5536   {
5537     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5538   }
5539
5540   /*
5541    * (non-Javadoc)
5542    * 
5543    * @see
5544    * jalview.jbgui.GAlignFrame#makeGrpsFromSelection_actionPerformed(java.awt
5545    * .event.ActionEvent)
5546    */
5547   @Override
5548   protected void makeGrpsFromSelection_actionPerformed(ActionEvent e)
5549   {
5550     if (avc.makeGroupsFromSelection()) {
5551       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
5552       alignPanel.updateAnnotation();
5553       alignPanel.paintAlignment(true);
5554     }
5555   }
5556
5557   @Override
5558   protected void createGroup_actionPerformed(ActionEvent e)
5559   {
5560     if (avc.createGroup())
5561     {
5562       alignPanel.alignmentChanged();
5563     }
5564   }
5565
5566   @Override
5567   protected void unGroup_actionPerformed(ActionEvent e)
5568   {
5569     if (avc.unGroup())
5570     {
5571       alignPanel.alignmentChanged();
5572     }
5573   }
5574
5575   /**
5576    * make the given alignmentPanel the currently selected tab
5577    * 
5578    * @param alignmentPanel
5579    */
5580   public void setDisplayedView(AlignmentPanel alignmentPanel)
5581   {
5582     if (!viewport.getSequenceSetId().equals(
5583             alignmentPanel.av.getSequenceSetId()))
5584     {
5585       throw new Error(
5586               "Implementation error: cannot show a view from another alignment in an AlignFrame.");
5587     }
5588     if (tabbedPane != null
5589             & alignPanels.indexOf(alignmentPanel) != tabbedPane
5590                     .getSelectedIndex())
5591     {
5592       tabbedPane.setSelectedIndex(alignPanels.indexOf(alignmentPanel));
5593     }
5594   }
5595 }
5596
5597 class PrintThread extends Thread
5598 {
5599   AlignmentPanel ap;
5600
5601   public PrintThread(AlignmentPanel ap)
5602   {
5603     this.ap = ap;
5604   }
5605
5606   static PageFormat pf;
5607
5608   @Override
5609   public void run()
5610   {
5611     PrinterJob printJob = PrinterJob.getPrinterJob();
5612
5613     if (pf != null)
5614     {
5615       printJob.setPrintable(ap, pf);
5616     }
5617     else
5618     {
5619       printJob.setPrintable(ap);
5620     }
5621
5622     if (printJob.printDialog())
5623     {
5624       try
5625       {
5626         printJob.print();
5627       } catch (Exception PrintException)
5628       {
5629         PrintException.printStackTrace();
5630       }
5631     }
5632   }
5633 }