Clover icon

Coverage Report

  1. Project Clover database Thu Aug 13 2020 12:04:21 BST
  2. Package jalview.gui

File AlignFrame.java

 

Coverage histogram

../../img/srcFileCovDistChart3.png
47% of files have more coverage

Code metrics

610
1,699
236
2
5,847
4,159
666
0.39
7.2
118
2.82

Classes

Class Line # Actions
AlignFrame 165 1,690 661
0.3023715330.2%
PrintThread 5811 9 5
0.00%
 

Contributing tests

This file is covered by 181 tests. .

Source view

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