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