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