Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 14:43:25 GMT
  2. Package jalview.gui

File AlignFrame.java

 

Coverage histogram

../../img/srcFileCovDistChart4.png
49% of files have more coverage

Code metrics

762
2,144
303
2
7,272
5,203
840
0.39
7.08
151.5
2.77

Classes

Class Line # Actions
AlignFrame 208 2,135 835
0.3171571831.7%
AlignFrame.PrintThread 7235 9 5
0.00%
 

Contributing tests

This file is covered by 501 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.Dimension;
27    import java.awt.Graphics;
28    import java.awt.Rectangle;
29    import java.awt.Toolkit;
30    import java.awt.datatransfer.Clipboard;
31    import java.awt.datatransfer.DataFlavor;
32    import java.awt.datatransfer.StringSelection;
33    import java.awt.datatransfer.Transferable;
34    import java.awt.dnd.DnDConstants;
35    import java.awt.dnd.DropTargetDragEvent;
36    import java.awt.dnd.DropTargetDropEvent;
37    import java.awt.dnd.DropTargetEvent;
38    import java.awt.dnd.DropTargetListener;
39    import java.awt.event.ActionEvent;
40    import java.awt.event.ActionListener;
41    import java.awt.event.FocusAdapter;
42    import java.awt.event.FocusEvent;
43    import java.awt.event.ItemEvent;
44    import java.awt.event.ItemListener;
45    import java.awt.event.KeyAdapter;
46    import java.awt.event.KeyEvent;
47    import java.awt.event.KeyListener;
48    import java.awt.event.MouseAdapter;
49    import java.awt.event.MouseEvent;
50    import java.awt.print.PageFormat;
51    import java.awt.print.PrinterJob;
52    import java.beans.PropertyChangeListener;
53    import java.io.File;
54    import java.io.FileWriter;
55    import java.io.IOException;
56    import java.io.OutputStreamWriter;
57    import java.io.PrintWriter;
58    import java.net.URL;
59    import java.util.ArrayList;
60    import java.util.Arrays;
61    import java.util.Collection;
62    import java.util.Deque;
63    import java.util.HashMap;
64    import java.util.HashSet;
65    import java.util.List;
66    import java.util.Locale;
67    import java.util.Map;
68    import java.util.Set;
69    import java.util.Vector;
70   
71    import javax.swing.ButtonGroup;
72    import javax.swing.JCheckBoxMenuItem;
73    import javax.swing.JComponent;
74    import javax.swing.JEditorPane;
75    import javax.swing.JFileChooser;
76    import javax.swing.JInternalFrame;
77    import javax.swing.JLabel;
78    import javax.swing.JLayeredPane;
79    import javax.swing.JMenu;
80    import javax.swing.JMenuItem;
81    import javax.swing.JOptionPane;
82    import javax.swing.JPanel;
83    import javax.swing.JProgressBar;
84    import javax.swing.JRootPane;
85    import javax.swing.JScrollPane;
86    import javax.swing.SwingUtilities;
87    import javax.swing.event.InternalFrameAdapter;
88    import javax.swing.event.InternalFrameEvent;
89   
90    import jalview.analysis.AlignmentAnnotationUtils;
91    import jalview.analysis.AlignmentSorter;
92    import jalview.analysis.AlignmentUtils;
93    import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
94    import jalview.analysis.CrossRef;
95    import jalview.analysis.Dna;
96    import jalview.analysis.GeneticCodeI;
97    import jalview.analysis.ParseProperties;
98    import jalview.analysis.SequenceIdMatcher;
99    import jalview.api.AlignExportSettingsI;
100    import jalview.api.AlignViewControllerGuiI;
101    import jalview.api.AlignViewControllerI;
102    import jalview.api.AlignViewportI;
103    import jalview.api.AlignmentViewPanel;
104    import jalview.api.FeatureSettingsControllerI;
105    import jalview.api.FeatureSettingsModelI;
106    import jalview.api.SplitContainerI;
107    import jalview.api.ViewStyleI;
108    import jalview.api.analysis.SimilarityParamsI;
109    import jalview.bin.Cache;
110    import jalview.bin.Console;
111    import jalview.bin.Jalview;
112    import jalview.bin.groovy.JalviewObjectI;
113    import jalview.commands.CommandI;
114    import jalview.commands.EditCommand;
115    import jalview.commands.EditCommand.Action;
116    import jalview.commands.OrderCommand;
117    import jalview.commands.RemoveGapColCommand;
118    import jalview.commands.RemoveGapsCommand;
119    import jalview.commands.SlideSequencesCommand;
120    import jalview.commands.TrimRegionCommand;
121    import jalview.datamodel.AlignExportSettingsAdapter;
122    import jalview.datamodel.AlignedCodonFrame;
123    import jalview.datamodel.Alignment;
124    import jalview.datamodel.AlignmentAnnotation;
125    import jalview.datamodel.AlignmentExportData;
126    import jalview.datamodel.AlignmentI;
127    import jalview.datamodel.AlignmentOrder;
128    import jalview.datamodel.AlignmentView;
129    import jalview.datamodel.ColumnSelection;
130    import jalview.datamodel.ContactMatrixI;
131    import jalview.datamodel.HiddenColumns;
132    import jalview.datamodel.PDBEntry;
133    import jalview.datamodel.SeqCigar;
134    import jalview.datamodel.Sequence;
135    import jalview.datamodel.SequenceGroup;
136    import jalview.datamodel.SequenceI;
137    import jalview.datamodel.annotations.AlphaFoldAnnotationRowBuilder;
138    import jalview.gui.ColourMenuHelper.ColourChangeListener;
139    import jalview.gui.ViewSelectionMenu.ViewSetProvider;
140    import jalview.hmmer.HMMAlign;
141    import jalview.hmmer.HMMBuild;
142    import jalview.hmmer.HMMERParamStore;
143    import jalview.hmmer.HMMERPreset;
144    import jalview.hmmer.HMMSearch;
145    import jalview.hmmer.HmmerCommand;
146    import jalview.hmmer.JackHMMER;
147    import jalview.io.AlignmentProperties;
148    import jalview.io.AnnotationFile;
149    import jalview.io.BackupFiles;
150    import jalview.io.BioJsHTMLOutput;
151    import jalview.io.DataSourceType;
152    import jalview.io.FileFormat;
153    import jalview.io.FileFormatI;
154    import jalview.io.FileFormats;
155    import jalview.io.FileLoader;
156    import jalview.io.FileParse;
157    import jalview.io.FormatAdapter;
158    import jalview.io.HtmlSvgOutput;
159    import jalview.io.IdentifyFile;
160    import jalview.io.JPredFile;
161    import jalview.io.JalviewFileChooser;
162    import jalview.io.JalviewFileView;
163    import jalview.io.JnetAnnotationMaker;
164    import jalview.io.NewickFile;
165    import jalview.io.ScoreMatrixFile;
166    import jalview.io.TCoffeeScoreFile;
167    import jalview.io.exceptions.ImageOutputException;
168    import jalview.io.vcf.VCFLoader;
169    import jalview.jbgui.GAlignFrame;
170    import jalview.project.Jalview2XML;
171    import jalview.schemes.ColourSchemeI;
172    import jalview.schemes.ColourSchemes;
173    import jalview.schemes.ResidueColourScheme;
174    import jalview.schemes.TCoffeeColourScheme;
175    import jalview.util.Constants;
176    import jalview.util.HttpUtils;
177    import jalview.util.ImageMaker.TYPE;
178    import jalview.util.MessageManager;
179    import jalview.util.Platform;
180    import jalview.util.imagemaker.BitmapImageSizing;
181    import jalview.viewmodel.AlignmentViewport;
182    import jalview.viewmodel.ViewportRanges;
183    import jalview.ws.DBRefFetcher;
184    import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
185    import jalview.ws.ServiceChangeListener;
186    import jalview.ws.WSDiscovererI;
187    import jalview.ws.api.ServiceWithParameters;
188    import jalview.ws.jws1.Discoverer;
189    import jalview.ws.jws2.Jws2Discoverer;
190    import jalview.ws.jws2.PreferredServiceRegistry;
191    import jalview.ws.params.ArgumentI;
192    import jalview.ws.params.ParamDatastoreI;
193    import jalview.ws.params.WsParamSetI;
194    import jalview.ws.seqfetcher.DbSourceProxy;
195    import jalview.ws2.client.api.WebServiceDiscovererI;
196    import jalview.ws2.client.ebi.JobDispatcherWSDiscoverer;
197    import jalview.ws2.client.jpred4.JPred4WSDiscoverer;
198    import jalview.ws2.client.slivka.SlivkaWSDiscoverer;
199    import jalview.ws2.gui.WebServicesMenuManager;
200   
201    /**
202    * DOCUMENT ME!
203    *
204    * @author $author$
205    * @version $Revision$
206    */
207    @SuppressWarnings("serial")
 
208    public class AlignFrame extends GAlignFrame
209    implements DropTargetListener, IProgressIndicator,
210    AlignViewControllerGuiI, ColourChangeListener, ServiceChangeListener
211    {
212   
213    public static int frameCount;
214   
215    public static final int DEFAULT_WIDTH = 700;
216   
217    public static final int DEFAULT_HEIGHT = 500;
218   
219    /*
220    * The currently displayed panel (selected tabbed view if more than one)
221    */
222    public AlignmentPanel alignPanel;
223   
224    AlignViewport viewport;
225   
226    public AlignViewControllerI avc;
227   
228    List<AlignmentPanel> alignPanels = new ArrayList<>();
229   
230    /**
231    * Last format used to load or save alignments in this window
232    */
233    FileFormatI currentFileFormat = null;
234   
235    /**
236    * Current filename for this alignment
237    */
238    String fileName = null;
239   
240    /**
241    * TODO: remove reference to 'FileObject' in AlignFrame - not correct mapping
242    */
243    File fileObject;
244   
245    private int id;
246   
247    private DataSourceType protocol;
248   
249    /**
250    * Creates a new AlignFrame object with specific width and height.
251    *
252    * @param al
253    * @param width
254    * @param height
255    */
 
256  381 toggle public AlignFrame(AlignmentI al, int width, int height)
257    {
258  381 this(al, null, width, height);
259    }
260   
261    /**
262    * Creates a new AlignFrame object with specific width, height and
263    * sequenceSetId
264    *
265    * @param al
266    * @param width
267    * @param height
268    * @param sequenceSetId
269    */
 
270  0 toggle public AlignFrame(AlignmentI al, int width, int height,
271    String sequenceSetId)
272    {
273  0 this(al, null, width, height, sequenceSetId);
274    }
275   
276    /**
277    * Creates a new AlignFrame object with specific width, height and
278    * sequenceSetId
279    *
280    * @param al
281    * @param width
282    * @param height
283    * @param sequenceSetId
284    * @param viewId
285    */
 
286  96 toggle public AlignFrame(AlignmentI al, int width, int height,
287    String sequenceSetId, String viewId)
288    {
289  96 this(al, null, width, height, sequenceSetId, viewId);
290    }
291   
292    /**
293    * new alignment window with hidden columns
294    *
295    * @param al
296    * AlignmentI
297    * @param hiddenColumns
298    * ColumnSelection or null
299    * @param width
300    * Width of alignment frame
301    * @param height
302    * height of frame.
303    */
 
304  381 toggle public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns, int width,
305    int height)
306    {
307  381 this(al, hiddenColumns, width, height, null);
308    }
309   
310    /**
311    * Create alignment frame for al with hiddenColumns, a specific width and
312    * height, and specific sequenceId
313    *
314    * @param al
315    * @param hiddenColumns
316    * @param width
317    * @param height
318    * @param sequenceSetId
319    * (may be null)
320    */
 
321  381 toggle public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns, int width,
322    int height, String sequenceSetId)
323    {
324  381 this(al, hiddenColumns, width, height, sequenceSetId, null);
325    }
326   
327    /**
328    * Create alignment frame for al with hiddenColumns, a specific width and
329    * height, and specific sequenceId
330    *
331    * @param al
332    * @param hiddenColumns
333    * @param width
334    * @param height
335    * @param sequenceSetId
336    * (may be null)
337    * @param viewId
338    * (may be null)
339    */
 
340  477 toggle public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns, int width,
341    int height, String sequenceSetId, String viewId)
342    {
343  477 id = (++frameCount);
344  477 setSize(width, height);
345   
346  477 if (al.getDataset() == null)
347    {
348  349 al.setDataset(null);
349    }
350   
351  477 viewport = new AlignViewport(al, hiddenColumns, sequenceSetId, viewId);
352   
353    // JalviewJS needs to distinguish a new panel from an old one in init()
354    // alignPanel = new AlignmentPanel(this, viewport);
355    // addAlignmentPanel(alignPanel, true);
356  477 init();
357    }
358   
 
359  5 toggle public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
360    HiddenColumns hiddenColumns, int width, int height)
361    {
362  5 setSize(width, height);
363   
364  5 if (al.getDataset() == null)
365    {
366  5 al.setDataset(null);
367    }
368   
369  5 viewport = new AlignViewport(al, hiddenColumns);
370   
371  5 if (hiddenSeqs != null && hiddenSeqs.length > 0)
372    {
373  5 viewport.hideSequence(hiddenSeqs);
374    }
375    // alignPanel = new AlignmentPanel(this, viewport);
376    // addAlignmentPanel(alignPanel, true);
377  5 init();
378    }
379   
380    /**
381    * Make a new AlignFrame from existing alignmentPanels
382    *
383    * @param ap
384    * AlignmentPanel
385    * @param av
386    * AlignViewport
387    */
 
388  5 toggle public AlignFrame(AlignmentPanel ap)
389    {
390  5 viewport = ap.av;
391  5 alignPanel = ap;
392    // addAlignmentPanel(ap, false);
393  5 init();
394    }
395   
396    /**
397    * initalise the alignframe from the underlying viewport data and the
398    * configurations
399    */
 
400  487 toggle void init()
401    {
402  487 setFrameIcon(null);
403   
404  487 boolean newPanel = (alignPanel == null);
405  487 viewport.setShowAutocalculatedAbove(isShowAutoCalculatedAbove());
406  487 if (newPanel)
407    {
408  482 if (Platform.isJS())
409    {
410    // need to set this up front if NOANNOTATION is
411    // used in conjunction with SHOWOVERVIEW.
412   
413    // I have not determined if this is appropriate for
414    // Jalview/Java, as it means we are setting this flag
415    // for all subsequent AlignFrames. For now, at least,
416    // I am setting it to be JalviewJS-only.
417   
418  0 boolean showAnnotation = Jalview.getInstance().getShowAnnotation();
419  0 viewport.setShowAnnotation(showAnnotation);
420    }
421  482 alignPanel = new AlignmentPanel(this, viewport);
422    }
423  487 addAlignmentPanel(alignPanel, newPanel);
424    // setBackground(Color.white); // BH 2019
425   
426  487 if (!Jalview.isHeadlessMode())
427    {
428  439 progressBar = new ProgressBar(this.statusPanel, this.statusBar);
429    // JalviewJS options
430  439 statusPanel.setVisible(Jalview.getInstance().getShowStatus());
431  439 alignFrameMenuBar.setVisible(Jalview.getInstance().getAllowMenuBar());
432    }
433    // always do this - JAL-4594 and co - we don't see SS consensus otherwise right now.
434   
435  487 avc = new jalview.controller.AlignViewController(this, viewport,
436    alignPanel);
437  487 if (viewport.getAlignmentConservationAnnotation() == null)
438    {
439    // BLOSUM62Colour.setEnabled(false);
440  82 conservationMenuItem.setEnabled(false);
441  82 modifyConservation.setEnabled(false);
442    // PIDColour.setEnabled(false);
443    // abovePIDThreshold.setEnabled(false);
444    // modifyPID.setEnabled(false);
445    }
446   
447  487 String sortby = Cache.getDefault(Preferences.SORT_ALIGNMENT, "No sort");
448   
449  487 if (sortby.equals("Id"))
450    {
451  0 sortIDMenuItem_actionPerformed(null);
452    }
453  487 else if (sortby.equals("Pairwise Identity"))
454    {
455  0 sortPairwiseMenuItem_actionPerformed(null);
456    }
457   
458    // BH see above
459    //
460    // this.alignPanel.av
461    // .setShowAutocalculatedAbove(isShowAutoCalculatedAbove());
462   
463  487 setMenusFromViewport(viewport);
464  487 buildSortByAnnotationScoresMenu();
465  487 calculateTree.addActionListener(new ActionListener()
466    {
467   
 
468  0 toggle @Override
469    public void actionPerformed(ActionEvent e)
470    {
471  0 openTreePcaDialog();
472    }
473    });
474  487 buildColourMenu();
475   
476  487 if (Desktop.getDesktopPane() != null)
477    {
478  439 this.setDropTarget(new java.awt.dnd.DropTarget(this, this));
479  439 addServiceListeners();
480  439 if (!Platform.isJS())
481    {
482    }
483  439 setGUINucleotide();
484    }
485   
486  487 if (viewport.getWrapAlignment())
487    {
488  7 wrapMenuItem_actionPerformed(null);
489    }
490   
491  487 if (Cache.getDefault(Preferences.SHOW_OVERVIEW, false))
492    {
493  28 this.overviewMenuItem_actionPerformed(null);
494    }
495   
496  487 addKeyListener();
497   
498  487 final List<AlignmentViewPanel> selviews = new ArrayList<>();
499  487 final List<AlignmentPanel> origview = new ArrayList<>();
500  487 final String menuLabel = MessageManager
501    .getString("label.copy_format_from");
502  487 ViewSelectionMenu vsel = new ViewSelectionMenu(menuLabel,
503    new ViewSetProvider()
504    {
505   
 
506  0 toggle @Override
507    public AlignmentPanel[] getAllAlignmentPanels()
508    {
509  0 origview.clear();
510  0 origview.add(alignPanel);
511    // make an array of all alignment panels except for this one
512  0 List<AlignmentViewPanel> aps = new ArrayList<>(
513    Arrays.asList(Desktop.getAlignmentPanels(null)));
514  0 aps.remove(AlignFrame.this.alignPanel);
515  0 return aps.toArray(new AlignmentPanel[aps.size()]);
516    }
517    }, selviews, new ItemListener()
518    {
519   
 
520  0 toggle @Override
521    public void itemStateChanged(ItemEvent e)
522    {
523  0 if (origview.size() > 0)
524    {
525  0 final AlignmentPanel ap = origview.get(0);
526   
527    /*
528    * Copy the ViewStyle of the selected panel to 'this one'. Don't change value of
529    * 'scaleProteinAsCdna' unless copying from a SplitFrame.
530    */
531  0 ViewStyleI vs = selviews.get(0).getAlignViewport()
532    .getViewStyle();
533  0 boolean fromSplitFrame = selviews.get(0)
534    .getAlignViewport().getCodingComplement() != null;
535  0 if (!fromSplitFrame)
536    {
537  0 vs.setScaleProteinAsCdna(ap.getAlignViewport()
538    .getViewStyle().isScaleProteinAsCdna());
539    }
540  0 ap.getAlignViewport().setViewStyle(vs);
541   
542    /*
543    * Also rescale ViewStyle of SplitFrame complement if there is one _and_ it is
544    * set to 'scaledProteinAsCdna'; we don't copy the whole ViewStyle (allow cDNA
545    * protein to have different fonts)
546    */
547  0 AlignViewportI complement = ap.getAlignViewport()
548    .getCodingComplement();
549  0 if (complement != null && vs.isScaleProteinAsCdna())
550    {
551  0 AlignFrame af = Desktop.getAlignFrameFor(complement);
552  0 ((SplitFrame) af.getSplitViewContainer())
553    .adjustLayout();
554  0 af.setMenusForViewport();
555    }
556   
557  0 ap.updateLayout();
558  0 ap.setSelected(true);
559  0 ap.alignFrame.setMenusForViewport();
560   
561    }
562    }
563    });
564  487 if (Cache.getDefault("VERSION", "DEVELOPMENT").toLowerCase(Locale.ROOT)
565    .indexOf("devel") > -1
566    || Cache.getDefault("VERSION", "DEVELOPMENT")
567    .toLowerCase(Locale.ROOT).indexOf("test") > -1)
568    {
569  487 formatMenu.add(vsel);
570    }
571  487 addFocusListener(new FocusAdapter()
572    {
 
573  357 toggle @Override
574    public void focusGained(FocusEvent e)
575    {
576  357 Jalview.getInstance().setCurrentAlignFrame(AlignFrame.this);
577    }
578    });
579   
580    }
581   
582    /**
583    * Change the filename and format for the alignment, and enable the 'reload'
584    * button functionality.
585    *
586    * @param file
587    * valid filename
588    * @param format
589    * format of file
590    */
 
591  0 toggle @Deprecated
592    public void setFileName(String file, FileFormatI format)
593    {
594  0 fileName = file;
595  0 setFileFormat(format);
596  0 reload.setEnabled(true);
597    }
598   
599    /**
600    *
601    * @param fileName
602    * @param file
603    * from SwingJS; may contain bytes -- for reload
604    * @param protocol
605    * from SwingJS; may be RELATIVE_URL
606    * @param format
607    */
 
608  341 toggle public void setFile(String fileName, File file, DataSourceType protocol,
609    FileFormatI format)
610    {
611  341 this.fileName = fileName;
612  341 this.fileObject = file;
613  341 this.protocol = protocol;
614  341 setFileFormat(format);
615  341 reload.setEnabled(true);
616    }
617   
618    /**
619    * JavaScript will have this, maybe others. More dependable than a file name
620    * and maintains a reference to the actual bytes loaded.
621    *
622    * @param file
623    */
 
624  96 toggle public void setFileObject(File file)
625    {
626  96 this.fileObject = file;
627    }
628   
629    /**
630    * Add a KeyListener with handlers for various KeyPressed and KeyReleased
631    * events
632    */
 
633  487 toggle void addKeyListener()
634    {
635  487 addKeyListener(new KeyAdapter()
636    {
 
637  0 toggle @Override
638    public void keyPressed(KeyEvent evt)
639    {
640  0 if (viewport.cursorMode
641    && ((evt.getKeyCode() >= KeyEvent.VK_0
642    && evt.getKeyCode() <= KeyEvent.VK_9)
643    || (evt.getKeyCode() >= KeyEvent.VK_NUMPAD0
644    && evt.getKeyCode() <= KeyEvent.VK_NUMPAD9))
645    && Character.isDigit(evt.getKeyChar()))
646    {
647  0 alignPanel.getSeqPanel().numberPressed(evt.getKeyChar());
648    }
649   
650  0 switch (evt.getKeyCode())
651    {
652   
653  0 case KeyEvent.VK_ESCAPE: // escape key
654    // alignPanel.deselectAllSequences();
655  0 alignPanel.deselectAllSequences();
656   
657  0 break;
658   
659  0 case KeyEvent.VK_DOWN:
660  0 if (evt.isAltDown() || !viewport.cursorMode)
661    {
662  0 moveSelectedSequences(false);
663    }
664  0 if (viewport.cursorMode)
665    {
666  0 alignPanel.getSeqPanel().moveCursor(0, 1, evt.isShiftDown());
667    }
668  0 break;
669   
670  0 case KeyEvent.VK_UP:
671  0 if (evt.isAltDown() || !viewport.cursorMode)
672    {
673  0 moveSelectedSequences(true);
674    }
675  0 if (viewport.cursorMode)
676    {
677  0 alignPanel.getSeqPanel().moveCursor(0, -1, evt.isShiftDown());
678    }
679   
680  0 break;
681   
682  0 case KeyEvent.VK_LEFT:
683  0 if (evt.isAltDown() || !viewport.cursorMode)
684    {
685  0 slideSequences(false,
686    alignPanel.getSeqPanel().getKeyboardNo1());
687    }
688    else
689    {
690  0 alignPanel.getSeqPanel().moveCursor(-1, 0, evt.isShiftDown());
691    }
692   
693  0 break;
694   
695  0 case KeyEvent.VK_RIGHT:
696  0 if (evt.isAltDown() || !viewport.cursorMode)
697    {
698  0 slideSequences(true, alignPanel.getSeqPanel().getKeyboardNo1());
699    }
700    else
701    {
702  0 alignPanel.getSeqPanel().moveCursor(1, 0, evt.isShiftDown());
703    }
704  0 break;
705   
706  0 case KeyEvent.VK_SPACE:
707  0 if (viewport.cursorMode)
708    {
709  0 alignPanel.getSeqPanel().insertGapAtCursor(evt.isControlDown()
710    || evt.isShiftDown() || evt.isAltDown());
711    }
712  0 break;
713   
714    // case KeyEvent.VK_A:
715    // if (viewport.cursorMode)
716    // {
717    // alignPanel.seqPanel.insertNucAtCursor(false,"A");
718    // //jalview.bin.Console.outPrintln("A");
719    // }
720    // break;
721    /*
722    * case KeyEvent.VK_CLOSE_BRACKET: if (viewport.cursorMode) {
723    * jalview.bin.Console.outPrintln("closing bracket"); } break;
724    */
725  0 case KeyEvent.VK_DELETE:
726  0 case KeyEvent.VK_BACK_SPACE:
727  0 if (!viewport.cursorMode)
728    {
729  0 cut_actionPerformed();
730    }
731    else
732    {
733  0 alignPanel.getSeqPanel().deleteGapAtCursor(evt.isControlDown()
734    || evt.isShiftDown() || evt.isAltDown());
735    }
736   
737  0 break;
738   
739  0 case KeyEvent.VK_S:
740  0 if (viewport.cursorMode)
741    {
742  0 alignPanel.getSeqPanel().setCursorRow();
743    }
744  0 break;
745  0 case KeyEvent.VK_C:
746  0 if (viewport.cursorMode && !evt.isControlDown())
747    {
748  0 alignPanel.getSeqPanel().setCursorColumn();
749    }
750  0 break;
751  0 case KeyEvent.VK_P:
752  0 if (viewport.cursorMode)
753    {
754  0 alignPanel.getSeqPanel().setCursorPosition();
755    }
756  0 break;
757   
758  0 case KeyEvent.VK_ENTER:
759  0 case KeyEvent.VK_COMMA:
760  0 if (viewport.cursorMode)
761    {
762  0 alignPanel.getSeqPanel().setCursorRowAndColumn();
763    }
764  0 break;
765   
766  0 case KeyEvent.VK_Q:
767  0 if (viewport.cursorMode)
768    {
769  0 alignPanel.getSeqPanel().setSelectionAreaAtCursor(true);
770    }
771  0 break;
772  0 case KeyEvent.VK_M:
773  0 if (viewport.cursorMode)
774    {
775  0 alignPanel.getSeqPanel().setSelectionAreaAtCursor(false);
776    }
777  0 break;
778   
779  0 case KeyEvent.VK_F2:
780  0 viewport.cursorMode = !viewport.cursorMode;
781  0 setStatus(MessageManager
782    .formatMessage("label.keyboard_editing_mode", new String[]
783  0 { (viewport.cursorMode ? "on" : "off") }));
784  0 if (viewport.cursorMode)
785    {
786  0 ViewportRanges ranges = viewport.getRanges();
787  0 alignPanel.getSeqPanel().seqCanvas.cursorX = ranges
788    .getStartRes();
789  0 alignPanel.getSeqPanel().seqCanvas.cursorY = ranges
790    .getStartSeq();
791    }
792  0 alignPanel.getSeqPanel().seqCanvas.repaint();
793  0 break;
794   
795  0 case KeyEvent.VK_F1:
796  0 try
797    {
798  0 Help.showHelpWindow();
799    } catch (Exception ex)
800    {
801  0 ex.printStackTrace();
802    }
803  0 break;
804  0 case KeyEvent.VK_H:
805    {
806  0 boolean toggleSeqs = !evt.isControlDown();
807  0 boolean toggleCols = !evt.isShiftDown();
808  0 toggleHiddenRegions(toggleSeqs, toggleCols);
809  0 break;
810    }
811  0 case KeyEvent.VK_B:
812    {
813  0 boolean toggleSel = evt.isControlDown() || evt.isMetaDown();
814  0 boolean modifyExisting = true; // always modify, don't clear
815    // evt.isShiftDown();
816  0 boolean invertHighlighted = evt.isAltDown();
817  0 avc.markHighlightedColumns(invertHighlighted, modifyExisting,
818    toggleSel);
819  0 break;
820    }
821  0 case KeyEvent.VK_PAGE_UP:
822  0 viewport.getRanges().pageUp();
823  0 break;
824  0 case KeyEvent.VK_PAGE_DOWN:
825  0 viewport.getRanges().pageDown();
826  0 break;
827    }
828    }
829   
 
830  0 toggle @Override
831    public void keyReleased(KeyEvent evt)
832    {
833  0 switch (evt.getKeyCode())
834    {
835  0 case KeyEvent.VK_LEFT:
836  0 if (evt.isAltDown() || !viewport.cursorMode)
837    {
838  0 viewport.notifyAlignment();
839    }
840  0 break;
841   
842  0 case KeyEvent.VK_RIGHT:
843  0 if (evt.isAltDown() || !viewport.cursorMode)
844    {
845  0 viewport.notifyAlignment();
846    }
847  0 break;
848    }
849    }
850    });
851    }
852   
 
853  536 toggle public void addAlignmentPanel(final AlignmentPanel ap, boolean newPanel)
854    {
855  536 ap.alignFrame = this;
856  536 avc = new jalview.controller.AlignViewController(this, viewport,
857    alignPanel);
858   
859  536 alignPanels.add(ap);
860   
861  536 PaintRefresher.Register(ap, ap.av.getSequenceSetId());
862   
863  536 int aSize = alignPanels.size();
864   
865  536 tabbedPane.setVisible(aSize > 1 || ap.av.getViewName() != null);
866   
867  536 if (aSize == 1 && ap.av.getViewName() == null)
868    {
869  482 this.getContentPane().add(ap, BorderLayout.CENTER);
870    }
871    else
872    {
873  54 if (aSize == 2)
874    {
875  23 setInitialTabVisible();
876    }
877   
878  54 expandViews.setEnabled(true);
879  54 gatherViews.setEnabled(true);
880  54 tabbedPane.addTab(ap.av.getViewName(), ap);
881   
882  54 ap.setVisible(false);
883    }
884   
885  536 if (newPanel)
886    {
887  492 if (ap.av.isPadGaps())
888    {
889  186 ap.av.getAlignment().padGaps();
890    }
891  492 if (Jalview.getInstance().getStartCalculations())
892    {
893  492 ap.av.updateConservation(ap);
894  492 ap.av.updateConsensus(ap);
895  492 ap.av.updateSecondaryStructureConsensus(ap);
896  492 ap.av.updateStrucConsensus(ap);
897  492 ap.av.initInformationWorker(ap);
898    }
899    }
900    }
901   
 
902  82 toggle public void setInitialTabVisible()
903    {
904  82 expandViews.setEnabled(true);
905  82 gatherViews.setEnabled(true);
906  82 tabbedPane.setVisible(true);
907  82 AlignmentPanel first = alignPanels.get(0);
908  82 tabbedPane.addTab(first.av.getViewName(), first);
909  82 this.getContentPane().add(tabbedPane, BorderLayout.CENTER);
910    }
911   
 
912  266736 toggle public AlignViewport getViewport()
913    {
914  266736 return viewport;
915    }
916   
 
917  7794 toggle @Override
918    public void servicesChanged(WSDiscovererI discoverer,
919    Collection<? extends ServiceWithParameters> services)
920    {
921  7794 buildWebServicesMenu();
922    }
923   
924    private WebServiceDiscovererI.ServicesChangeListener slivkaServiceChangeListener = (
925    discoverer, services) -> {
926    // run when slivka services change
927  3012 var menu = AlignFrame.this.slivkaMenu;
928  3012 menu.setServices(discoverer);
929  3012 menu.setInProgress(discoverer.isRunning());
930  3012 menu.setNoServices(services.isEmpty() && discoverer.isDone());
931    };
932   
933    private WebServiceDiscovererI.ServicesChangeListener ebiServiceChangeListener = (
934    discoverer, services) -> {
935    // run when ebi services change
936  11484 var menu = AlignFrame.this.ebiMenu;
937  11484 menu.setServices(discoverer);
938  11484 menu.setInProgress(discoverer.isRunning());
939  11484 menu.setNoServices(services.isEmpty() && discoverer.isDone());
940    };
941   
942    private WebServiceDiscovererI.ServicesChangeListener jpred4ServiceChangeListener = (
943    discoverer, services) -> {
944    // run when jpred4 services change
945  2410 var menu = AlignFrame.this.jpred4Menu;
946  2410 menu.setServices(discoverer);
947  2410 menu.setInProgress(discoverer.isRunning());
948  2410 menu.setNoServices(services.isEmpty() && discoverer.isDone());
949    };
950   
951    /* Set up intrinsic listeners for dynamically generated GUI bits. */
 
952  439 toggle private void addServiceListeners()
953    {
954  439 if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true))
955    {
956  439 WebServiceDiscovererI discoverer = SlivkaWSDiscoverer.getInstance();
957  439 discoverer.addServicesChangeListener(slivkaServiceChangeListener);
958    }
959  439 if (Cache.getDefault("SHOW_EBI_SERVICES", true))
960    {
961  439 JobDispatcherWSDiscoverer.getInstance()
962    .addServicesChangeListener(ebiServiceChangeListener);
963    }
964  439 if (Cache.getDefault("SHOW_JPRED4_SERVICES", true))
965    {
966  439 JPred4WSDiscoverer.getInstance()
967    .addServicesChangeListener(jpred4ServiceChangeListener);
968    }
969  439 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
970    {
971  439 WSDiscovererI discoverer = Jws2Discoverer.getInstance();
972  439 discoverer.addServiceChangeListener(this);
973    }
974    // legacy event listener for compatibility with jws1
975  439 PropertyChangeListener legacyListener = (changeEvent) -> {
976  0 buildWebServicesMenu();
977    };
978  439 Desktop.getInstance().addJalviewPropertyChangeListener("services",
979    legacyListener);
980   
981  439 addInternalFrameListener(new InternalFrameAdapter()
982    {
 
983  326 toggle @Override
984    public void internalFrameClosed(InternalFrameEvent e)
985    {
986  326 System.out.println("deregistering discoverer listener");
987  326 SlivkaWSDiscoverer.getInstance()
988    .removeServicesChangeListener(slivkaServiceChangeListener);
989  326 JPred4WSDiscoverer.getInstance()
990    .removeServicesChangeListener(jpred4ServiceChangeListener);
991  326 Jws2Discoverer.getInstance()
992    .removeServiceChangeListener(AlignFrame.this);
993  326 Desktop.getInstance().removeJalviewPropertyChangeListener(
994    "services", legacyListener);
995  326 closeMenuItem_actionPerformed(true);
996    }
997    });
998  439 buildWebServicesMenu();
999    }
1000   
1001    /**
1002    * Configure menu items that vary according to whether the alignment is
1003    * nucleotide or protein
1004    */
 
1005  439 toggle public void setGUINucleotide()
1006    {
1007  439 AlignmentI al = getViewport().getAlignment();
1008  439 boolean nucleotide = al.isNucleotide();
1009   
1010  439 loadVcf.setVisible(nucleotide);
1011  439 showTranslation.setVisible(nucleotide);
1012  439 showReverse.setVisible(nucleotide);
1013  439 showReverseComplement.setVisible(nucleotide);
1014  439 conservationMenuItem.setEnabled(!nucleotide);
1015  439 modifyConservation
1016    .setEnabled(!nucleotide && conservationMenuItem.isSelected());
1017  439 byConsensusSecondaryStructureMenuItem.setEnabled(!nucleotide);
1018  439 modifyConsensusSecondaryStructureThreshold.setEnabled(!nucleotide
1019    && byConsensusSecondaryStructureMenuItem.isSelected());
1020  439 showGroupConservation.setEnabled(!nucleotide);
1021   
1022  439 showComplementMenuItem
1023  439 .setText(nucleotide ? MessageManager.getString("label.protein")
1024    : MessageManager.getString("label.nucleotide"));
1025    }
1026   
1027    /**
1028    * set up menus for the current viewport. This may be called after any
1029    * operation that affects the data in the current view (selection changed,
1030    * etc) to update the menus to reflect the new state.
1031    */
 
1032  41 toggle @Override
1033    public void setMenusForViewport()
1034    {
1035  41 setMenusFromViewport(viewport);
1036    }
1037   
1038    /**
1039    * Need to call this method when tabs are selected for multiple views, or when
1040    * loading from Jalview2XML.java
1041    *
1042    * @param av
1043    * AlignViewport
1044    */
 
1045  729 toggle public void setMenusFromViewport(AlignViewport av)
1046    {
1047  729 padGapsMenuitem.setSelected(av.isPadGaps());
1048  729 colourTextMenuItem.setSelected(av.isShowColourText());
1049  729 abovePIDThreshold.setSelected(av.getAbovePIDThreshold());
1050  729 modifyPID.setEnabled(abovePIDThreshold.isSelected());
1051  729 conservationMenuItem.setSelected(av.getConservationSelected());
1052  729 modifyConservation.setEnabled(conservationMenuItem.isSelected());
1053  729 byConsensusSecondaryStructureMenuItem
1054    .setSelected(av.getByConsensusSecondaryStructureSelected());
1055  729 modifyConsensusSecondaryStructureThreshold
1056    .setEnabled(byConsensusSecondaryStructureMenuItem.isSelected());
1057  729 seqLimits.setSelected(av.getShowJVSuffix());
1058  729 idRightAlign.setSelected(av.isRightAlignIds());
1059  729 centreColumnLabelsMenuItem.setState(av.isCentreColumnLabels());
1060  729 renderGapsMenuItem.setSelected(av.isRenderGaps());
1061  729 wrapMenuItem.setSelected(av.getWrapAlignment());
1062  729 scaleAbove.setVisible(av.getWrapAlignment());
1063  729 scaleLeft.setVisible(av.getWrapAlignment());
1064  729 scaleRight.setVisible(av.getWrapAlignment());
1065  729 annotationPanelMenuItem.setState(av.isShowAnnotation());
1066    // Show/hide annotations only enabled if annotation panel is shown
1067  729 syncAnnotationMenuItems(av.isShowAnnotation());
1068  729 viewBoxesMenuItem.setSelected(av.getShowBoxes());
1069  729 viewTextMenuItem.setSelected(av.getShowText());
1070  729 showNonconservedMenuItem.setSelected(av.getShowUnconserved());
1071  729 showGroupConsensus.setSelected(av.isShowGroupConsensus());
1072  729 showGroupSSConsensus.setSelected(av.isShowGroupSSConsensus());
1073  729 showStrucProvider.setSelected(av.isShowStructureProvider());
1074  729 showGroupConservation.setSelected(av.isShowGroupConservation());
1075  729 showConsensusHistogram.setSelected(av.isShowConsensusHistogram());
1076  729 showSequenceLogo.setSelected(av.isShowSequenceLogo());
1077  729 normaliseSequenceLogo.setSelected(av.isNormaliseSequenceLogo());
1078  729 showInformationHistogram.setSelected(av.isShowInformationHistogram());
1079  729 showHMMSequenceLogo.setSelected(av.isShowHMMSequenceLogo());
1080  729 normaliseHMMSequenceLogo.setSelected(av.isNormaliseHMMSequenceLogo());
1081   
1082  729 ColourMenuHelper.setColourSelected(colourMenu,
1083    av.getGlobalColourScheme());
1084   
1085  729 showSeqFeatures.setSelected(av.isShowSequenceFeatures());
1086  729 hiddenMarkers.setState(av.getShowHiddenMarkers());
1087  729 applyToAllGroups.setState(av.getColourAppliesToAllGroups());
1088  729 showNpFeatsMenuitem.setSelected(av.isShowNPFeats());
1089  729 showDbRefsMenuitem.setSelected(av.isShowDBRefs());
1090  729 autoCalculate
1091    .setSelected(av.getAutoCalculateConsensusAndConservation());
1092  729 sortByTree.setSelected(av.sortByTree);
1093  729 listenToViewSelections.setSelected(av.followSelection);
1094   
1095  729 showProducts.setEnabled(canShowProducts());
1096  729 setGroovyEnabled(Desktop.getGroovyConsole() != null);
1097   
1098  729 updateEditMenuBar();
1099    }
1100   
1101    /**
1102    * Set the enabled state of the 'Run Groovy' option in the Calculate menu
1103    *
1104    * @param b
1105    */
 
1106  729 toggle public void setGroovyEnabled(boolean b)
1107    {
1108  729 runGroovy.setEnabled(b);
1109    }
1110   
1111    private IProgressIndicator progressBar;
1112   
1113    /*
1114    * (non-Javadoc)
1115    *
1116    * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
1117    */
 
1118  550 toggle @Override
1119    public void setProgressBar(String message, long id)
1120    {
1121  550 if (!Platform.isHeadless() && progressBar != null)
1122  521 progressBar.setProgressBar(message, id);
1123    }
1124   
1125    // JAL-4107 TODO: check progress bars for pasimap/pca still work in 2.12 and
1126    // in headless - semantics diverged
 
1127  0 toggle @Override
1128    public void addProgressBar(long id, String message)
1129    {
1130  0 progressBar.addProgressBar(id, message);
1131    }
1132   
 
1133  0 toggle @Override
1134    public void removeProgressBar(long id)
1135    {
1136  0 progressBar.removeProgressBar(id);
1137    }
1138   
 
1139  0 toggle @Override
1140    public JProgressBar getProgressBar(long id)
1141    {
1142  0 if (progressBar != null)
1143  0 return progressBar.getProgressBar(id);
1144  0 return null;
1145    }
1146   
 
1147  0 toggle @Override
1148    public String getMessage(long id)
1149    {
1150  0 return progressBar.getMessage(id);
1151    }
1152   
 
1153  0 toggle @Override
1154    public void setProgressBarMessage(long id, String message)
1155    {
1156  0 progressBar.setProgressBarMessage(id, message);
1157    }
1158   
 
1159  0 toggle @Override
1160    public void registerHandler(final long id,
1161    final IProgressIndicatorHandler handler)
1162    {
1163  0 if (progressBar != null)
1164  0 progressBar.registerHandler(id, handler);
1165    }
1166   
1167    /**
1168    *
1169    * @return true if any progress bars are still active
1170    */
 
1171  41 toggle @Override
1172    public boolean operationInProgress()
1173    {
1174  41 return progressBar == null ? false : progressBar.operationInProgress();
1175    }
1176   
1177    /**
1178    * Sets the text of the status bar. Note that setting a null or empty value
1179    * will cause the status bar to be hidden, with possibly undesirable flicker
1180    * of the screen layout.
1181    */
 
1182  401 toggle @Override
1183    public void setStatus(String text)
1184    {
1185  401 statusBar.setText(text == null || text.isEmpty() ? " " : text);
1186    }
1187   
1188    /*
1189    * Added so Castor Mapping file can obtain Jalview Version
1190    */
 
1191  0 toggle public String getVersion()
1192    {
1193  0 return Cache.getProperty("VERSION");
1194    }
1195   
 
1196  50 toggle public FeatureRenderer getFeatureRenderer()
1197    {
1198  50 return alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer();
1199    }
1200   
 
1201  0 toggle @Override
1202    public void fetchSequence_actionPerformed()
1203    {
1204  0 new SequenceFetcher(this);
1205    }
1206   
 
1207  0 toggle @Override
1208    public void addFromFile_actionPerformed(ActionEvent e)
1209    {
1210  0 Desktop.getInstance().inputLocalFileMenuItem_actionPerformed(viewport);
1211    }
1212   
 
1213  0 toggle @Override
1214    public void hmmBuild_actionPerformed(boolean withDefaults)
1215    {
1216  0 if (!alignmentIsSufficient(1))
1217    {
1218  0 return;
1219    }
1220   
1221    /*
1222    * get default parameters, and optionally show a dialog
1223    * to allow them to be modified
1224    */
1225  0 ParamDatastoreI store = HMMERParamStore.forBuild(viewport);
1226  0 List<ArgumentI> args = store.getServiceParameters();
1227   
1228  0 if (!withDefaults)
1229    {
1230  0 WsParamSetI set = new HMMERPreset();
1231  0 WsJobParameters params = new WsJobParameters(store, set, args);
1232  0 params.showRunDialog().thenAccept((startJob) -> {
1233  0 if (startJob)
1234    {
1235  0 var args2 = params.getJobParams();
1236  0 new Thread(new HMMBuild(this, args2)).start();
1237    }
1238    });
1239    }
1240    else
1241    {
1242  0 new Thread(new HMMBuild(this, args)).start();
1243    }
1244    }
1245   
 
1246  0 toggle @Override
1247    public void hmmAlign_actionPerformed(boolean withDefaults)
1248    {
1249  0 if (!(checkForHMM() && alignmentIsSufficient(2)))
1250    {
1251  0 return;
1252    }
1253   
1254    /*
1255    * get default parameters, and optionally show a dialog
1256    * to allow them to be modified
1257    */
1258  0 ParamDatastoreI store = HMMERParamStore.forAlign(viewport);
1259  0 List<ArgumentI> args = store.getServiceParameters();
1260   
1261  0 if (!withDefaults)
1262    {
1263  0 WsParamSetI set = new HMMERPreset();
1264  0 WsJobParameters params = new WsJobParameters(store, set, args);
1265  0 params.showRunDialog().thenAccept((startJob) -> {
1266  0 if (startJob)
1267    {
1268  0 var args2 = params.getJobParams();
1269  0 new Thread(new HMMAlign(this, args2)).start();
1270    }
1271    });
1272    }
1273    else
1274    {
1275  0 new Thread(new HMMAlign(this, args)).start();
1276    }
1277    }
1278   
 
1279  0 toggle @Override
1280    public void hmmSearch_actionPerformed(boolean withDefaults)
1281    {
1282  0 if (!checkForHMM())
1283    {
1284  0 return;
1285    }
1286   
1287    /*
1288    * get default parameters, and (if requested) show
1289    * dialog to allow modification
1290    */
1291  0 ParamDatastoreI store = HMMERParamStore.forSearch(viewport);
1292  0 List<ArgumentI> args = store.getServiceParameters();
1293   
1294  0 if (!withDefaults)
1295    {
1296  0 WsParamSetI set = new HMMERPreset();
1297  0 WsJobParameters params = new WsJobParameters(store, set, args);
1298  0 params.showRunDialog().thenAccept((startJob) -> {
1299  0 if (startJob)
1300    {
1301  0 var args2 = params.getJobParams();
1302  0 new Thread(new HMMSearch(this, args2)).start();
1303  0 alignPanel.repaint();
1304    }
1305    });
1306    }
1307    else
1308    {
1309  0 new Thread(new HMMSearch(this, args)).start();
1310  0 alignPanel.repaint();
1311    }
1312    }
1313   
 
1314  0 toggle @Override
1315    public void jackhmmer_actionPerformed(boolean withDefaults)
1316    {
1317   
1318    /*
1319    * get default parameters, and (if requested) show
1320    * dialog to allow modification
1321    */
1322   
1323  0 ParamDatastoreI store = HMMERParamStore.forJackhmmer(viewport);
1324  0 List<ArgumentI> args = store.getServiceParameters();
1325   
1326  0 if (!withDefaults)
1327    {
1328  0 WsParamSetI set = new HMMERPreset();
1329  0 WsJobParameters params = new WsJobParameters(store, set, args);
1330  0 params.showRunDialog().thenAccept((startJob) -> {
1331  0 if (startJob)
1332    {
1333  0 var args2 = params.getJobParams();
1334  0 new Thread(new JackHMMER(this, args2)).start();
1335  0 alignPanel.repaint();
1336    }
1337    });
1338    }
1339    else
1340    {
1341  0 new Thread(new JackHMMER(this, args)).start();
1342  0 alignPanel.repaint();
1343    }
1344    }
1345   
1346    /**
1347    * Checks if the alignment has at least one hidden Markov model, if not shows
1348    * a dialog advising to run hmmbuild or load an HMM profile
1349    *
1350    * @return
1351    */
 
1352  0 toggle private boolean checkForHMM()
1353    {
1354  0 if (viewport.getAlignment().getHmmSequences().isEmpty())
1355    {
1356  0 JOptionPane.showMessageDialog(this,
1357    MessageManager.getString("warn.no_hmm"));
1358  0 return false;
1359    }
1360  0 return true;
1361    }
1362   
 
1363  0 toggle @Override
1364    protected void filterByEValue_actionPerformed()
1365    {
1366  0 viewport.filterByEvalue(inputDouble("Enter E-Value Cutoff"));
1367    }
1368   
 
1369  0 toggle @Override
1370    protected void filterByScore_actionPerformed()
1371    {
1372  0 viewport.filterByScore(inputDouble("Enter Bit Score Threshold"));
1373    }
1374   
 
1375  0 toggle private double inputDouble(String message)
1376    {
1377  0 String str = null;
1378  0 Double d = null;
1379  0 while (d == null || d <= 0)
1380    {
1381  0 str = JOptionPane.showInputDialog(this.alignPanel, message);
1382  0 try
1383    {
1384  0 d = Double.valueOf(str);
1385    } catch (NumberFormatException e)
1386    {
1387    }
1388    }
1389  0 return d;
1390    }
1391   
1392    /**
1393    * Checks if the alignment contains the required number of sequences.
1394    *
1395    * @param required
1396    * @return
1397    */
 
1398  0 toggle public boolean alignmentIsSufficient(int required)
1399    {
1400  0 if (getViewport().getSequenceSelection().length < required)
1401    {
1402  0 JOptionPane.showMessageDialog(this,
1403    MessageManager.getString("label.not_enough_sequences"));
1404  0 return false;
1405    }
1406  0 return true;
1407    }
1408   
1409    /**
1410    * Opens a file browser and adds the selected file, if in Fasta, Stockholm or
1411    * Pfam format, to the list held under preference key "HMMSEARCH_DBS" (as a
1412    * comma-separated list)
1413    */
 
1414  0 toggle @Override
1415    public void addDatabase_actionPerformed() throws IOException
1416    {
1417  0 if (Cache.getProperty(Preferences.HMMSEARCH_DBS) == null)
1418    {
1419  0 Cache.setProperty(Preferences.HMMSEARCH_DBS, "");
1420    }
1421   
1422  0 String path = openFileChooser(false);
1423  0 if (path != null && new File(path).exists())
1424    {
1425  0 IdentifyFile identifier = new IdentifyFile();
1426  0 FileFormatI format = identifier.identify(path, DataSourceType.FILE);
1427  0 if (format == FileFormat.Fasta || format == FileFormat.Stockholm
1428    || format == FileFormat.Pfam)
1429    {
1430  0 String currentDbPaths = Cache
1431    .getProperty(Preferences.HMMSEARCH_DBS);
1432  0 currentDbPaths += Preferences.COMMA + path;
1433  0 Cache.setProperty(Preferences.HMMSEARCH_DBS, currentDbPaths);
1434    }
1435    else
1436    {
1437  0 JOptionPane.showMessageDialog(this,
1438    MessageManager.getString("warn.invalid_format"));
1439    }
1440    }
1441    }
1442   
1443    /**
1444    * Opens a file chooser, optionally restricted to selecting folders
1445    * (directories) only. Answers the path to the selected file or folder, or
1446    * null if none is chosen.
1447    *
1448    * @param
1449    * @return
1450    */
 
1451  0 toggle protected String openFileChooser(boolean forFolder)
1452    {
1453    // TODO duplicates GPreferences method - relocate to JalviewFileChooser?
1454  0 String choice = null;
1455  0 JFileChooser chooser = new JFileChooser();
1456  0 if (forFolder)
1457    {
1458  0 chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
1459    }
1460  0 chooser.setDialogTitle(
1461    MessageManager.getString("label.open_local_file"));
1462  0 chooser.setToolTipText(MessageManager.getString("action.open"));
1463   
1464  0 int value = chooser.showOpenDialog(this);
1465   
1466  0 if (value == JFileChooser.APPROVE_OPTION)
1467    {
1468  0 choice = chooser.getSelectedFile().getPath();
1469    }
1470  0 return choice;
1471    }
1472   
 
1473  0 toggle @Override
1474    public void reload_actionPerformed(ActionEvent e)
1475    {
1476  0 if (fileName == null && fileObject == null)
1477    {
1478  0 return;
1479    }
1480    // TODO: JAL-1108 - ensure all associated frames are closed regardless of
1481    // originating file's format
1482    // TODO: work out how to recover feature settings for correct view(s) when
1483    // file is reloaded.
1484  0 if (FileFormat.Jalview.equals(currentFileFormat))
1485    {
1486  0 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
1487  0 for (int i = 0; i < frames.length; i++)
1488    {
1489  0 if (frames[i] instanceof AlignFrame && frames[i] != this
1490    && ((AlignFrame) frames[i]).fileName != null
1491    && ((AlignFrame) frames[i]).fileName.equals(fileName))
1492    {
1493  0 try
1494    {
1495  0 frames[i].setSelected(true);
1496  0 Desktop.getInstance().closeAssociatedWindows();
1497    } catch (java.beans.PropertyVetoException ex)
1498    {
1499    }
1500    }
1501   
1502    }
1503  0 Desktop.getInstance().closeAssociatedWindows();
1504   
1505  0 FileLoader loader = new FileLoader();
1506  0 loader.LoadFile(viewport,
1507  0 (fileObject == null ? fileName : fileObject), protocol,
1508    currentFileFormat);
1509    }
1510    else
1511    {
1512  0 Rectangle bounds = this.getBounds();
1513   
1514  0 FileLoader loader = new FileLoader();
1515   
1516  0 AlignFrame newframe = null;
1517   
1518  0 if (fileObject == null)
1519    {
1520  0 newframe = loader.LoadFileWaitTillLoaded(fileName, protocol,
1521    currentFileFormat);
1522    }
1523    else
1524    {
1525  0 newframe = loader.LoadFileWaitTillLoaded(fileObject,
1526    DataSourceType.FILE, currentFileFormat);
1527    }
1528   
1529  0 newframe.setBounds(bounds);
1530  0 if (featureSettings != null && featureSettings.isShowing())
1531    {
1532  0 final Rectangle fspos = featureSettings.frame.getBounds();
1533    // TODO: need a 'show feature settings' function that takes bounds -
1534    // need to refactor Desktop.addFrame
1535  0 newframe.featureSettings_actionPerformed(null);
1536  0 final FeatureSettings nfs = newframe.featureSettings;
1537  0 SwingUtilities.invokeLater(new Runnable()
1538    {
 
1539  0 toggle @Override
1540    public void run()
1541    {
1542  0 nfs.frame.setBounds(fspos);
1543    }
1544    });
1545  0 this.featureSettings.close();
1546  0 this.featureSettings = null;
1547    }
1548  0 this.closeMenuItem_actionPerformed(true);
1549    }
1550    }
1551   
 
1552  0 toggle @Override
1553    public void addFromText_actionPerformed(ActionEvent e)
1554    {
1555  0 Desktop.getInstance()
1556    .inputTextboxMenuItem_actionPerformed(viewport.getAlignPanel());
1557    }
1558   
 
1559  0 toggle @Override
1560    public void addFromURL_actionPerformed(ActionEvent e)
1561    {
1562  0 Desktop.getInstance().inputURLMenuItem_actionPerformed(viewport);
1563    }
1564   
 
1565  0 toggle @Override
1566    public void save_actionPerformed(ActionEvent e)
1567    {
1568  0 if (fileName == null || (currentFileFormat == null)
1569    || HttpUtils.startsWithHttpOrHttps(fileName))
1570    {
1571  0 saveAs_actionPerformed();
1572    }
1573    else
1574    {
1575  0 saveAlignment(fileName, currentFileFormat);
1576    }
1577    }
1578   
1579    /**
1580    * Saves the alignment to a file with a name chosen by the user, if necessary
1581    * warning if a file would be overwritten
1582    */
 
1583  0 toggle @Override
1584    public void saveAs_actionPerformed()
1585    {
1586  0 JalviewFileChooser chooser = JalviewFileChooser.forWrite(
1587    Cache.getProperty("LAST_DIRECTORY"),
1588  0 currentFileFormat == null ? null : currentFileFormat.getName(),
1589    true);
1590   
1591  0 chooser.setFileView(new JalviewFileView());
1592  0 chooser.setDialogTitle(
1593    MessageManager.getString("label.save_alignment_to_file"));
1594  0 chooser.setToolTipText(MessageManager.getString("action.save"));
1595   
1596  0 int value = chooser.showSaveDialog(this);
1597   
1598  0 if (value != JalviewFileChooser.APPROVE_OPTION)
1599    {
1600  0 return;
1601    }
1602  0 currentFileFormat = chooser.getSelectedFormat();
1603  0 while (currentFileFormat == null)
1604    {
1605    // if the autodetect format from extension failed..
1606  0 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
1607    MessageManager
1608    .getString("label.select_file_format_before_saving"),
1609    MessageManager.getString("label.file_format_not_specified"),
1610    JvOptionPane.WARNING_MESSAGE);
1611  0 value = chooser.showSaveDialog(this);
1612  0 if (value != JalviewFileChooser.APPROVE_OPTION)
1613    {
1614  0 return;
1615    }
1616  0 currentFileFormat = chooser.getSelectedFormat();
1617    }
1618   
1619  0 fileName = chooser.getSelectedFile().getPath();
1620   
1621  0 Cache.setProperty("DEFAULT_FILE_FORMAT", currentFileFormat.getName());
1622  0 Cache.setProperty("LAST_DIRECTORY", fileName);
1623  0 saveAlignment(fileName, currentFileFormat);
1624    }
1625   
1626    boolean lastSaveSuccessful = false;
1627   
1628    FileFormatI lastFormatSaved;
1629   
1630    String lastFilenameSaved;
1631   
1632    // globalLastFormatSaved across alignment windows (only for alignments with no
1633    // previous format)
1634    private static FileFormatI globalLastFormatSaved = null;
1635   
 
1636  28 toggle public static void setLastAlignmentSavedFormat(FileFormatI f)
1637    {
1638  28 globalLastFormatSaved = f;
1639    }
1640   
 
1641  6 toggle public static FileFormatI getLastAlignmentSavedFormat()
1642    {
1643  6 return globalLastFormatSaved;
1644    }
1645   
1646    /**
1647    * Raise a dialog or status message for the last call to saveAlignment.
1648    *
1649    * @return true if last call to saveAlignment(file, format) was successful.
1650    */
 
1651  88 toggle public boolean isSaveAlignmentSuccessful()
1652    {
1653   
1654  88 if (!lastSaveSuccessful)
1655    {
1656  0 if (!Platform.isHeadless())
1657    {
1658  0 JvOptionPane.showInternalMessageDialog(this, MessageManager
1659    .formatMessage("label.couldnt_save_file", new Object[]
1660    { lastFilenameSaved }),
1661    MessageManager.getString("label.error_saving_file"),
1662    JvOptionPane.WARNING_MESSAGE);
1663    }
1664    else
1665    {
1666  0 Console.error(MessageManager
1667    .formatMessage("label.couldnt_save_file", new Object[]
1668    { lastFilenameSaved }));
1669    }
1670    }
1671    else
1672    {
1673   
1674  88 setStatus(MessageManager.formatMessage(
1675    "label.successfully_saved_to_file_in_format", new Object[]
1676    { lastFilenameSaved, lastFormatSaved }));
1677   
1678    }
1679  88 return lastSaveSuccessful;
1680    }
1681   
1682    /**
1683    * Saves the alignment to the specified file path, in the specified format,
1684    * which may be an alignment format, or Jalview project format. If the
1685    * alignment has hidden regions, or the format is one capable of including
1686    * non-sequence data (features, annotations, groups), then the user may be
1687    * prompted to specify what to include in the output.
1688    *
1689    * @param file
1690    * @param format
1691    */
 
1692  54 toggle public void saveAlignment(String file, FileFormatI format)
1693    {
1694  54 saveAlignment(file, format, false, false);
1695    }
1696   
 
1697  128 toggle public void saveAlignment(String file, FileFormatI format, boolean stdout,
1698    boolean forceBackup)
1699    {
1700  128 lastSaveSuccessful = true;
1701  128 if (!stdout)
1702    {
1703  116 lastFilenameSaved = file;
1704    }
1705  128 lastFormatSaved = format;
1706  128 globalLastFormatSaved = format;
1707   
1708  128 if (FileFormat.Jalview.equals(format))
1709    {
1710  8 String shortName = title;
1711  8 if (shortName.indexOf(File.separatorChar) > -1)
1712    {
1713  6 shortName = shortName
1714    .substring(shortName.lastIndexOf(File.separatorChar) + 1);
1715    }
1716    // TODO deal with stdout=true
1717  8 lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file,
1718    shortName);
1719   
1720  8 Console.debug("lastSaveSuccessful=" + lastSaveSuccessful);
1721  8 if (lastSaveSuccessful)
1722    {
1723  8 this.getViewport().setSavedUpToDate(true);
1724    }
1725   
1726  8 statusBar.setText(MessageManager.formatMessage(
1727    "label.successfully_saved_to_file_in_format", new Object[]
1728    { fileName, format }));
1729   
1730  8 return;
1731    }
1732   
1733  120 AlignExportSettingsI options = new AlignExportSettingsAdapter(false);
1734  120 Runnable cancelAction = () -> {
1735  0 lastSaveSuccessful = false;
1736    };
1737  120 Runnable outputAction = () -> {
1738    // todo defer this to inside formatSequences (or later)
1739  120 AlignmentExportData exportData = viewport.getAlignExportData(options);
1740  120 String output = new FormatAdapter(alignPanel, options)
1741    .formatSequences(format, exportData.getAlignment(),
1742    exportData.getOmitHidden(),
1743    exportData.getStartEndPostions(),
1744    viewport.getAlignment().getHiddenColumns());
1745  120 if (output == null)
1746    {
1747  0 lastSaveSuccessful = false;
1748    }
1749    else
1750    {
1751    // create backupfiles object and get new temp filename destination
1752  120 boolean doBackup = forceBackup
1753    || (BackupFiles.getEnabled() && !stdout);
1754  120 BackupFiles backupfiles = null;
1755  120 if (doBackup)
1756    {
1757  92 Console.trace("ALIGNFRAME making backupfiles object for " + file);
1758  92 backupfiles = new BackupFiles(file);
1759    }
1760  120 try
1761    {
1762  120 String tempFilePath = doBackup ? backupfiles.getTempFilePath()
1763    : file;
1764  120 Console.trace("ALIGNFRAME setting PrintWriter");
1765  120 PrintWriter out = stdout
1766    ? new PrintWriter(new OutputStreamWriter(System.out))
1767    : new PrintWriter(new FileWriter(tempFilePath));
1768   
1769  120 if (backupfiles != null)
1770    {
1771  92 Console.trace("ALIGNFRAME about to write to temp file "
1772    + backupfiles.getTempFilePath());
1773    }
1774   
1775  120 out.print(output);
1776  120 out.flush();
1777  120 if (!stdout)
1778    {
1779  108 Console.trace("ALIGNFRAME about to close file");
1780  108 out.close();
1781  108 Console.trace("ALIGNFRAME closed file");
1782    }
1783  120 AlignFrame.this.setTitle(stdout ? "STDOUT" : file);
1784  120 if (stdout)
1785    {
1786  12 statusBar.setText(MessageManager.formatMessage(
1787    "label.successfully_printed_to_stdout_in_format",
1788    new Object[]
1789    { format.getName() }));
1790    }
1791    else
1792    {
1793  108 statusBar.setText(MessageManager.formatMessage(
1794    "label.successfully_saved_to_file_in_format",
1795    new Object[]
1796    { fileName, format.getName() }));
1797    }
1798  120 lastSaveSuccessful = true;
1799    } catch (IOException e)
1800    {
1801  0 lastSaveSuccessful = false;
1802  0 Console.error(
1803    "ALIGNFRAME Something happened writing the temp file");
1804  0 Console.error(e.getMessage());
1805  0 Console.debug(Cache.getStackTraceString(e));
1806    } catch (Exception ex)
1807    {
1808  0 lastSaveSuccessful = false;
1809  0 Console.error(
1810    "ALIGNFRAME Something unexpected happened writing the temp file");
1811  0 Console.error(ex.getMessage());
1812  0 Console.debug(Cache.getStackTraceString(ex));
1813    }
1814   
1815  120 if (doBackup)
1816    {
1817  92 backupfiles.setWriteSuccess(lastSaveSuccessful);
1818  92 Console.debug("ALIGNFRAME writing temp file was "
1819  92 + (lastSaveSuccessful ? "" : "NOT ") + "successful");
1820    // do the backup file roll and rename the temp file to actual file
1821  92 Console.trace("ALIGNFRAME about to rollBackupsAndRenameTempFile");
1822  92 lastSaveSuccessful = backupfiles.rollBackupsAndRenameTempFile();
1823  92 Console.debug("ALIGNFRAME performed rollBackupsAndRenameTempFile "
1824  92 + (lastSaveSuccessful ? "" : "un") + "successfully");
1825    }
1826   
1827  120 Console.debug("lastSaveSuccessful=" + lastSaveSuccessful);
1828  120 if (lastSaveSuccessful)
1829    {
1830  120 AlignFrame.this.getViewport().setSavedUpToDate(true);
1831    }
1832    }
1833    };
1834   
1835    /*
1836    * show dialog with export options if applicable; else just do it
1837    */
1838  120 if (AlignExportOptions.isNeeded(viewport, format))
1839    {
1840  0 AlignExportOptions choices = new AlignExportOptions(
1841    alignPanel.getAlignViewport(), format, options);
1842  0 choices.setResponseAction(0, outputAction);
1843  0 choices.setResponseAction(1, cancelAction);
1844  0 choices.showDialog();
1845    }
1846    else
1847    {
1848  120 try
1849    {
1850  120 outputAction.run();
1851    } catch (Exception e)
1852    {
1853    // TODO Auto-generated catch block
1854  0 e.printStackTrace();
1855    }
1856    }
1857    }
1858   
1859    /**
1860    * Outputs the alignment to textbox in the requested format, if necessary
1861    * first prompting the user for whether to include hidden regions or
1862    * non-sequence data
1863    *
1864    * @param fileFormatName
1865    */
 
1866  0 toggle @Override
1867    protected void outputText_actionPerformed(String fileFormatName)
1868    {
1869  0 FileFormatI fileFormat = FileFormats.getInstance()
1870    .forName(fileFormatName);
1871  0 AlignExportSettingsI options = new AlignExportSettingsAdapter(false);
1872  0 Runnable outputAction = () -> {
1873    // todo defer this to inside formatSequences (or later)
1874  0 AlignmentExportData exportData = viewport.getAlignExportData(options);
1875  0 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1876  0 cap.setForInput(null);
1877  0 try
1878    {
1879  0 FileFormatI format = fileFormat;
1880  0 cap.setText(new FormatAdapter(alignPanel, options).formatSequences(
1881    format, exportData.getAlignment(),
1882    exportData.getOmitHidden(),
1883    exportData.getStartEndPostions(),
1884    viewport.getAlignment().getHiddenColumns()));
1885  0 Desktop.addInternalFrame(cap, MessageManager.formatMessage(
1886    "label.alignment_output_command", new Object[]
1887    { fileFormat.getName() }), 600, 500);
1888    } catch (OutOfMemoryError oom)
1889    {
1890  0 new OOMWarning("Outputting alignment as " + fileFormat.getName(),
1891    oom);
1892  0 cap.dispose();
1893    }
1894    };
1895   
1896    /*
1897    * show dialog with export options if applicable; else just do it
1898    */
1899  0 if (AlignExportOptions.isNeeded(viewport, fileFormat))
1900    {
1901  0 AlignExportOptions choices = new AlignExportOptions(
1902    alignPanel.getAlignViewport(), fileFormat, options);
1903  0 choices.setResponseAction(0, outputAction);
1904  0 choices.showDialog();
1905    }
1906    else
1907    {
1908  0 try
1909    {
1910  0 outputAction.run();
1911    } catch (Exception e)
1912    {
1913  0 e.printStackTrace();
1914    }
1915    }
1916    }
1917   
1918    /**
1919    * DOCUMENT ME!
1920    *
1921    * @param e
1922    * DOCUMENT ME!
1923    */
 
1924  0 toggle @Override
1925    protected void htmlMenuItem_actionPerformed(ActionEvent e)
1926    {
1927  0 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(alignPanel);
1928  0 try
1929    {
1930  0 htmlSVG.exportHTML(null);
1931    } catch (ImageOutputException x)
1932    {
1933    // report problem to console and raise dialog
1934    }
1935    }
1936   
 
1937  0 toggle @Override
1938    public void bioJSMenuItem_actionPerformed(ActionEvent e)
1939    {
1940  0 BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel);
1941  0 try
1942    {
1943  0 bjs.exportHTML(null);
1944    } catch (ImageOutputException x)
1945    {
1946    // report problem to console and raise dialog
1947    }
1948    }
1949   
1950    // ??
 
1951  0 toggle public void createImageMap(File file, String image)
1952    {
1953  0 try
1954    {
1955  0 alignPanel.makePNGImageMap(file, image);
1956    } catch (ImageOutputException x)
1957    {
1958    // report problem to console and raise dialog
1959    }
1960    }
1961   
 
1962  0 toggle @Override
1963    public void createPNG_actionPerformed(ActionEvent e)
1964    {
1965  0 try
1966    {
1967  0 createPNG(null);
1968    } catch (ImageOutputException ioex)
1969    {
1970    // raise dialog, and report via console
1971    }
1972    }
1973   
 
1974  0 toggle @Override
1975    public void createEPS_actionPerformed(ActionEvent e)
1976    {
1977  0 try
1978    {
1979  0 createEPS(null);
1980    } catch (ImageOutputException ioex)
1981    {
1982    // raise dialog, and report via console
1983    }
1984   
1985    }
1986   
 
1987  0 toggle @Override
1988    public void createSVG_actionPerformed(ActionEvent e)
1989    {
1990  0 try
1991    {
1992  0 createSVG(null);
1993    } catch (ImageOutputException ioex)
1994    {
1995    // raise dialog, and report via console
1996    }
1997   
1998    }
1999   
2000    /**
2001    * Creates a PNG image of the alignment and writes it to the given file. If
2002    * the file is null, the user is prompted to choose a file.
2003    *
2004    * @param f
2005    */
 
2006  1 toggle public void createPNG(File f) throws ImageOutputException
2007    {
2008  1 createPNG(f, null, BitmapImageSizing.defaultBitmapImageSizing());
2009    }
2010   
 
2011  17 toggle public void createPNG(File f, String renderer, BitmapImageSizing userBis)
2012    throws ImageOutputException
2013    {
2014  17 alignPanel.makeAlignmentImage(TYPE.PNG, f, renderer, userBis);
2015    }
2016   
2017    /**
2018    * Creates an EPS image of the alignment and writes it to the given file. If
2019    * the file is null, the user is prompted to choose a file.
2020    *
2021    * @param f
2022    */
 
2023  5 toggle public void createEPS(File f) throws ImageOutputException
2024    {
2025  5 createEPS(f, null);
2026    }
2027   
 
2028  10 toggle public void createEPS(File f, String renderer) throws ImageOutputException
2029    {
2030  10 alignPanel.makeAlignmentImage(TYPE.EPS, f, renderer);
2031    }
2032   
2033    /**
2034    * Creates an SVG image of the alignment and writes it to the given file. If
2035    * the file is null, the user is prompted to choose a file.
2036    *
2037    * @param f
2038    */
 
2039  1 toggle public void createSVG(File f) throws ImageOutputException
2040    {
2041  1 createSVG(f, null);
2042    }
2043   
 
2044  2 toggle public void createSVG(File f, String renderer) throws ImageOutputException
2045    {
2046  2 alignPanel.makeAlignmentImage(TYPE.SVG, f, renderer);
2047    }
2048   
 
2049  0 toggle @Override
2050    public void pageSetup_actionPerformed(ActionEvent e)
2051    {
2052  0 PrinterJob printJob = PrinterJob.getPrinterJob();
2053  0 PrintThread.pf = printJob.pageDialog(printJob.defaultPage());
2054    }
2055   
2056    /**
2057    * DOCUMENT ME!
2058    *
2059    * @param e
2060    * DOCUMENT ME!
2061    */
 
2062  0 toggle @Override
2063    public void printMenuItem_actionPerformed(ActionEvent e)
2064    {
2065    // Putting in a thread avoids Swing painting problems
2066  0 PrintThread thread = new PrintThread(alignPanel);
2067  0 thread.start();
2068    }
2069   
 
2070  0 toggle @Override
2071    public void exportFeatures_actionPerformed(ActionEvent e)
2072    {
2073  0 new AnnotationExporter(alignPanel).exportFeatures();
2074    }
2075   
 
2076  0 toggle @Override
2077    public void exportAnnotations_actionPerformed(ActionEvent e)
2078    {
2079  0 new AnnotationExporter(alignPanel).exportAnnotations();
2080    }
2081   
 
2082  0 toggle @Override
2083    public void associatedData_actionPerformed(ActionEvent e)
2084    throws IOException, InterruptedException
2085    {
2086  0 final JalviewFileChooser chooser = new JalviewFileChooser(
2087    Cache.getProperty("LAST_DIRECTORY"));
2088  0 chooser.setFileView(new JalviewFileView());
2089  0 String tooltip = MessageManager
2090    .getString("label.load_jalview_annotations");
2091  0 chooser.setDialogTitle(tooltip);
2092  0 chooser.setToolTipText(tooltip);
2093  0 chooser.setResponseHandler(0, () -> {
2094  0 String choice = chooser.getSelectedFile().getPath();
2095  0 Cache.setProperty("LAST_DIRECTORY", choice);
2096  0 loadJalviewDataFile(chooser.getSelectedFile(), null, null, null);
2097    });
2098   
2099  0 chooser.showOpenDialog(this);
2100    }
2101   
2102    /**
2103    * Close the current view or all views in the alignment frame. If the frame
2104    * only contains one view then the alignment will be removed from memory.
2105    *
2106    * @param closeAllTabs
2107    */
 
2108  452 toggle @Override
2109    public void closeMenuItem_actionPerformed(boolean closeAllTabs)
2110    {
2111  452 if (alignPanels != null && alignPanels.size() < 2)
2112    {
2113  430 closeAllTabs = true;
2114    }
2115   
2116  452 Desktop.closeModal(this);
2117   
2118  452 try
2119    {
2120  452 if (alignPanels != null)
2121    {
2122  452 if (closeAllTabs)
2123    {
2124  451 if (this.isClosed())
2125    {
2126    // really close all the windows - otherwise wait till
2127    // setClosed(true) is called
2128  637 for (int i = 0; i < alignPanels.size(); i++)
2129    {
2130  316 AlignmentPanel ap = alignPanels.get(i);
2131  316 ap.closePanel();
2132    }
2133    }
2134    }
2135    else
2136    {
2137  1 closeView(alignPanel);
2138    }
2139    }
2140  447 if (closeAllTabs)
2141    {
2142  446 if (featureSettings != null && featureSettings.isOpen())
2143    {
2144  0 featureSettings.close();
2145  0 featureSettings = null;
2146    }
2147   
2148    /*
2149    * this will raise an INTERNAL_FRAME_CLOSED event and this method will be called
2150    * recursively, with the frame now in 'closed' state
2151    */
2152  446 this.setClosed(true);
2153    }
2154    } catch (Exception ex)
2155    {
2156  5 ex.printStackTrace();
2157    }
2158    }
2159   
2160    /**
2161    * Close the specified panel and close up tabs appropriately.
2162    *
2163    * @param panelToClose
2164    */
 
2165  1 toggle public void closeView(AlignmentPanel panelToClose)
2166    {
2167  1 int index = tabbedPane.getSelectedIndex();
2168  1 int closedindex = tabbedPane.indexOfComponent(panelToClose);
2169  1 alignPanels.remove(panelToClose);
2170  1 panelToClose.closePanel();
2171  1 panelToClose = null;
2172   
2173  1 tabbedPane.removeTabAt(closedindex);
2174  1 tabbedPane.validate();
2175   
2176  1 if (index > closedindex || index == tabbedPane.getTabCount())
2177    {
2178    // modify currently selected tab index if necessary.
2179  1 index--;
2180    }
2181   
2182  1 this.tabSelectionChanged(index);
2183    }
2184   
2185    /**
2186    * DOCUMENT ME!
2187    */
 
2188  1650 toggle void updateEditMenuBar()
2189    {
2190   
2191  1650 if (viewport.getHistoryList().size() > 0)
2192    {
2193  2 undoMenuItem.setEnabled(true);
2194  2 CommandI command = viewport.getHistoryList().peek();
2195  2 undoMenuItem.setText(MessageManager
2196    .formatMessage("label.undo_command", new Object[]
2197    { command.getDescription() }));
2198    }
2199    else
2200    {
2201  1648 undoMenuItem.setEnabled(false);
2202  1648 undoMenuItem.setText(MessageManager.getString("action.undo"));
2203    }
2204   
2205  1650 if (viewport.getRedoList().size() > 0)
2206    {
2207  0 redoMenuItem.setEnabled(true);
2208   
2209  0 CommandI command = viewport.getRedoList().peek();
2210  0 redoMenuItem.setText(MessageManager
2211    .formatMessage("label.redo_command", new Object[]
2212    { command.getDescription() }));
2213    }
2214    else
2215    {
2216  1650 redoMenuItem.setEnabled(false);
2217  1650 redoMenuItem.setText(MessageManager.getString("action.redo"));
2218    }
2219    }
2220   
 
2221  1 toggle @Override
2222    public void addHistoryItem(CommandI command)
2223    {
2224  1 if (command.getSize() > 0)
2225    {
2226  1 viewport.addToHistoryList(command);
2227  1 viewport.clearRedoList();
2228  1 updateEditMenuBar();
2229  1 viewport.updateHiddenColumns();
2230    // viewport.hasHiddenColumns = (viewport.getColumnSelection() != null
2231    // && viewport.getColumnSelection().getHiddenColumns() != null &&
2232    // viewport.getColumnSelection()
2233    // .getHiddenColumns().size() > 0);
2234    }
2235    }
2236   
2237    /**
2238    *
2239    * @return alignment objects for all views
2240    */
 
2241  0 toggle public AlignmentI[] getViewAlignments()
2242    {
2243  0 if (alignPanels != null)
2244    {
2245  0 AlignmentI[] als = new AlignmentI[alignPanels.size()];
2246  0 int i = 0;
2247  0 for (AlignmentPanel ap : alignPanels)
2248    {
2249  0 als[i++] = ap.av.getAlignment();
2250    }
2251  0 return als;
2252    }
2253  0 if (viewport != null)
2254    {
2255  0 return new AlignmentI[] { viewport.getAlignment() };
2256    }
2257  0 return null;
2258    }
2259   
2260    /**
2261    * DOCUMENT ME!
2262    *
2263    * @param e
2264    * DOCUMENT ME!
2265    */
 
2266  0 toggle @Override
2267    protected void undoMenuItem_actionPerformed(ActionEvent e)
2268    {
2269  0 if (viewport.getHistoryList().isEmpty())
2270    {
2271  0 return;
2272    }
2273  0 CommandI command = viewport.getHistoryList().pop();
2274  0 viewport.addToRedoList(command);
2275  0 command.undoCommand(getViewAlignments());
2276   
2277  0 AlignmentViewport originalSource = getOriginatingSource(command);
2278  0 updateEditMenuBar();
2279   
2280  0 if (originalSource != null)
2281    {
2282  0 if (originalSource != viewport)
2283    {
2284  0 Console.warn(
2285    "Implementation worry: mismatch of viewport origin for undo");
2286    }
2287  0 originalSource.updateHiddenColumns();
2288    // originalSource.hasHiddenColumns = (viewport.getColumnSelection() !=
2289    // null
2290    // && viewport.getColumnSelection().getHiddenColumns() != null &&
2291    // viewport.getColumnSelection()
2292    // .getHiddenColumns().size() > 0);
2293  0 originalSource.notifyAlignment();
2294    }
2295    }
2296   
2297    /**
2298    * DOCUMENT ME!
2299    *
2300    * @param e
2301    * DOCUMENT ME!
2302    */
 
2303  0 toggle @Override
2304    protected void redoMenuItem_actionPerformed(ActionEvent e)
2305    {
2306  0 if (viewport.getRedoList().size() < 1)
2307    {
2308  0 return;
2309    }
2310   
2311  0 CommandI command = viewport.getRedoList().pop();
2312  0 viewport.addToHistoryList(command);
2313  0 command.doCommand(getViewAlignments());
2314   
2315  0 AlignmentViewport originalSource = getOriginatingSource(command);
2316  0 updateEditMenuBar();
2317   
2318  0 if (originalSource != null)
2319    {
2320   
2321  0 if (originalSource != viewport)
2322    {
2323  0 Console.warn(
2324    "Implementation worry: mismatch of viewport origin for redo");
2325    }
2326  0 originalSource.updateHiddenColumns();
2327    // originalSource.hasHiddenColumns = (viewport.getColumnSelection() !=
2328    // null
2329    // && viewport.getColumnSelection().getHiddenColumns() != null &&
2330    // viewport.getColumnSelection()
2331    // .getHiddenColumns().size() > 0);
2332  0 originalSource.notifyAlignment();
2333    }
2334    }
2335   
 
2336  0 toggle AlignmentViewport getOriginatingSource(CommandI command)
2337    {
2338  0 AlignmentViewport originalSource = null;
2339    // For sequence removal and addition, we need to fire
2340    // the property change event FROM the viewport where the
2341    // original alignment was altered
2342  0 AlignmentI al = null;
2343  0 if (command instanceof EditCommand)
2344    {
2345  0 EditCommand editCommand = (EditCommand) command;
2346  0 al = editCommand.getAlignment();
2347  0 List<Component> comps = PaintRefresher.components
2348    .get(viewport.getSequenceSetId());
2349   
2350  0 for (Component comp : comps)
2351    {
2352  0 if (comp instanceof AlignmentPanel)
2353    {
2354  0 if (al == ((AlignmentPanel) comp).av.getAlignment())
2355    {
2356  0 originalSource = ((AlignmentPanel) comp).av;
2357  0 break;
2358    }
2359    }
2360    }
2361    }
2362   
2363  0 if (originalSource == null)
2364    {
2365    // The original view is closed, we must validate
2366    // the current view against the closed view first
2367  0 if (al != null)
2368    {
2369  0 PaintRefresher.validateSequences(al, viewport.getAlignment());
2370    }
2371   
2372  0 originalSource = viewport;
2373    }
2374   
2375  0 return originalSource;
2376    }
2377   
2378    /**
2379    * Calls AlignmentI.moveSelectedSequencesByOne with current sequence selection
2380    * or the sequence under cursor in keyboard mode
2381    *
2382    * @param up
2383    * or down (if !up)
2384    */
 
2385  0 toggle public void moveSelectedSequences(boolean up)
2386    {
2387  0 SequenceGroup sg = viewport.getSelectionGroup();
2388   
2389  0 if (sg == null)
2390    {
2391  0 if (viewport.cursorMode)
2392    {
2393  0 sg = new SequenceGroup();
2394  0 sg.addSequence(viewport.getAlignment().getSequenceAt(
2395    alignPanel.getSeqPanel().seqCanvas.cursorY), false);
2396    }
2397    else
2398    {
2399  0 return;
2400    }
2401    }
2402   
2403  0 if (sg.getSize() < 1)
2404    {
2405  0 return;
2406    }
2407   
2408    // TODO: JAL-3733 - add an event to the undo buffer for this !
2409   
2410  0 viewport.getAlignment().moveSelectedSequencesByOne(sg,
2411    viewport.getHiddenRepSequences(), up);
2412  0 alignPanel.paintAlignment(true, false);
2413    }
2414   
 
2415  0 toggle synchronized void slideSequences(boolean right, int size)
2416    {
2417  0 List<SequenceI> sg = new ArrayList<>();
2418  0 if (viewport.cursorMode)
2419    {
2420  0 sg.add(viewport.getAlignment()
2421    .getSequenceAt(alignPanel.getSeqPanel().seqCanvas.cursorY));
2422    }
2423  0 else if (viewport.getSelectionGroup() != null
2424    && viewport.getSelectionGroup().getSize() != viewport
2425    .getAlignment().getHeight())
2426    {
2427  0 sg = viewport.getSelectionGroup()
2428    .getSequences(viewport.getHiddenRepSequences());
2429    }
2430   
2431  0 if (sg.size() < 1)
2432    {
2433  0 return;
2434    }
2435   
2436  0 List<SequenceI> invertGroup = new ArrayList<>();
2437   
2438  0 for (SequenceI seq : viewport.getAlignment().getSequences())
2439    {
2440  0 if (!sg.contains(seq))
2441    {
2442  0 invertGroup.add(seq);
2443    }
2444    }
2445   
2446  0 SequenceI[] seqs1 = sg.toArray(new SequenceI[0]);
2447   
2448  0 SequenceI[] seqs2 = new SequenceI[invertGroup.size()];
2449  0 for (int i = 0; i < invertGroup.size(); i++)
2450    {
2451  0 seqs2[i] = invertGroup.get(i);
2452    }
2453   
2454  0 SlideSequencesCommand ssc;
2455  0 if (right)
2456    {
2457  0 ssc = new SlideSequencesCommand("Slide Sequences", seqs2, seqs1, size,
2458    viewport.getGapCharacter());
2459    }
2460    else
2461    {
2462  0 ssc = new SlideSequencesCommand("Slide Sequences", seqs1, seqs2, size,
2463    viewport.getGapCharacter());
2464    }
2465   
2466  0 int groupAdjustment = 0;
2467  0 if (ssc.getGapsInsertedBegin() && right)
2468    {
2469  0 if (viewport.cursorMode)
2470    {
2471  0 alignPanel.getSeqPanel().moveCursor(size, 0);
2472    }
2473    else
2474    {
2475  0 groupAdjustment = size;
2476    }
2477    }
2478  0 else if (!ssc.getGapsInsertedBegin() && !right)
2479    {
2480  0 if (viewport.cursorMode)
2481    {
2482  0 alignPanel.getSeqPanel().moveCursor(-size, 0);
2483    }
2484    else
2485    {
2486  0 groupAdjustment = -size;
2487    }
2488    }
2489   
2490  0 if (groupAdjustment != 0)
2491    {
2492  0 viewport.getSelectionGroup().setStartRes(
2493    viewport.getSelectionGroup().getStartRes() + groupAdjustment);
2494  0 viewport.getSelectionGroup().setEndRes(
2495    viewport.getSelectionGroup().getEndRes() + groupAdjustment);
2496    }
2497   
2498    /*
2499    * just extend the last slide command if compatible; but not if in SplitFrame
2500    * mode (to ensure all edits are broadcast - JAL-1802)
2501    */
2502  0 boolean appendHistoryItem = false;
2503  0 Deque<CommandI> historyList = viewport.getHistoryList();
2504  0 boolean inSplitFrame = getSplitViewContainer() != null;
2505  0 if (!inSplitFrame && historyList != null && historyList.size() > 0
2506    && historyList.peek() instanceof SlideSequencesCommand)
2507    {
2508  0 appendHistoryItem = ssc.appendSlideCommand(
2509    (SlideSequencesCommand) historyList.peek());
2510    }
2511   
2512  0 if (!appendHistoryItem)
2513    {
2514  0 addHistoryItem(ssc);
2515    }
2516   
2517  0 repaint();
2518    }
2519   
2520    /**
2521    * DOCUMENT ME!
2522    *
2523    * @param e
2524    * DOCUMENT ME!
2525    */
 
2526  1 toggle @Override
2527    protected void copy_actionPerformed()
2528    {
2529  1 if (viewport.getSelectionGroup() == null)
2530    {
2531  0 return;
2532    }
2533    // TODO: preserve the ordering of displayed alignment annotation in any
2534    // internal paste (particularly sequence associated annotation)
2535  1 SequenceI[] seqs = viewport.getSelectionAsNewSequence();
2536  1 String[] omitHidden = null;
2537   
2538  1 if (viewport.hasHiddenColumns())
2539    {
2540  0 omitHidden = viewport.getViewAsString(true);
2541    }
2542   
2543  1 String output = new FormatAdapter().formatSequences(FileFormat.Fasta,
2544    seqs, omitHidden, null);
2545   
2546  1 StringSelection ss = new StringSelection(output);
2547   
2548  1 Desktop d = Desktop.getInstance();
2549  1 try
2550    {
2551  1 d.internalCopy = true;
2552    // Its really worth setting the clipboard contents
2553    // to empty before setting the large StringSelection!!
2554  1 Toolkit.getDefaultToolkit().getSystemClipboard()
2555    .setContents(new StringSelection(""), null);
2556   
2557  1 Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, d);
2558    } catch (OutOfMemoryError er)
2559    {
2560  0 new OOMWarning("copying region", er);
2561  0 return;
2562    }
2563   
2564  1 HiddenColumns hiddenColumns = null;
2565  1 if (viewport.hasHiddenColumns())
2566    {
2567  0 int hiddenOffset = viewport.getSelectionGroup().getStartRes();
2568  0 int hiddenCutoff = viewport.getSelectionGroup().getEndRes();
2569   
2570    // create new HiddenColumns object with copy of hidden regions
2571    // between startRes and endRes, offset by startRes
2572  0 hiddenColumns = new HiddenColumns(
2573    viewport.getAlignment().getHiddenColumns(), hiddenOffset,
2574    hiddenCutoff, hiddenOffset);
2575    }
2576   
2577  1 d.jalviewClipboard = new Object[] { seqs,
2578    viewport.getAlignment().getDataset(), hiddenColumns };
2579  1 setStatus(MessageManager.formatMessage(
2580    "label.copied_sequences_to_clipboard", new Object[]
2581    { Integer.valueOf(seqs.length).toString() }));
2582    }
2583   
2584    /**
2585    * DOCUMENT ME!
2586    *
2587    * @param e
2588    * DOCUMENT ME!
2589    * @throws InterruptedException
2590    * @throws IOException
2591    */
 
2592  0 toggle @Override
2593    protected void pasteNew_actionPerformed(ActionEvent e)
2594    throws IOException, InterruptedException
2595    {
2596  0 paste(true);
2597    }
2598   
2599    /**
2600    * DOCUMENT ME!
2601    *
2602    * @param e
2603    * DOCUMENT ME!
2604    * @throws InterruptedException
2605    * @throws IOException
2606    */
 
2607  0 toggle @Override
2608    protected void pasteThis_actionPerformed(ActionEvent e)
2609    throws IOException, InterruptedException
2610    {
2611  0 paste(false);
2612    }
2613   
2614    /**
2615    * Paste contents of Jalview clipboard
2616    *
2617    * @param newAlignment
2618    * true to paste to a new alignment, otherwise add to this.
2619    * @throws InterruptedException
2620    * @throws IOException
2621    */
 
2622  0 toggle void paste(boolean newAlignment) throws IOException, InterruptedException
2623    {
2624  0 boolean externalPaste = true;
2625  0 try
2626    {
2627  0 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
2628  0 Transferable contents = c.getContents(this);
2629   
2630  0 if (contents == null)
2631    {
2632  0 return;
2633    }
2634   
2635  0 String str;
2636  0 FileFormatI format;
2637  0 try
2638    {
2639  0 str = (String) contents.getTransferData(DataFlavor.stringFlavor);
2640  0 if (str.length() < 1)
2641    {
2642  0 return;
2643    }
2644   
2645  0 format = new IdentifyFile().identify(str, DataSourceType.PASTE);
2646   
2647    } catch (OutOfMemoryError er)
2648    {
2649  0 new OOMWarning("Out of memory pasting sequences!!", er);
2650  0 return;
2651    }
2652   
2653  0 SequenceI[] sequences;
2654  0 boolean annotationAdded = false;
2655  0 AlignmentI alignment = null;
2656   
2657  0 Desktop d = Desktop.getInstance();
2658   
2659  0 if (d.jalviewClipboard != null)
2660    {
2661    // The clipboard was filled from within Jalview, we must use the
2662    // sequences
2663    // And dataset from the copied alignment
2664  0 SequenceI[] newseq = (SequenceI[]) d.jalviewClipboard[0];
2665    // be doubly sure that we create *new* sequence objects.
2666  0 sequences = new SequenceI[newseq.length];
2667  0 for (int i = 0; i < newseq.length; i++)
2668    {
2669  0 sequences[i] = new Sequence(newseq[i]);
2670    }
2671  0 alignment = new Alignment(sequences);
2672  0 externalPaste = false;
2673    }
2674    else
2675    {
2676    // parse the clipboard as an alignment.
2677  0 alignment = new FormatAdapter().readFile(str, DataSourceType.PASTE,
2678    format);
2679  0 sequences = alignment.getSequencesArray();
2680    }
2681   
2682  0 int alwidth = 0;
2683  0 ArrayList<Integer> newGraphGroups = new ArrayList<>();
2684  0 int fgroup = -1;
2685   
2686  0 if (newAlignment)
2687    {
2688   
2689  0 if (d.jalviewClipboard != null)
2690    {
2691    // dataset is inherited
2692  0 alignment.setDataset((Alignment) d.jalviewClipboard[1]);
2693    }
2694    else
2695    {
2696    // new dataset is constructed
2697  0 alignment.setDataset(null);
2698    }
2699  0 alwidth = alignment.getWidth() + 1;
2700    }
2701    else
2702    {
2703  0 AlignmentI pastedal = alignment; // preserve pasted alignment object
2704    // Add pasted sequences and dataset into existing alignment.
2705  0 alignment = viewport.getAlignment();
2706  0 alwidth = alignment.getWidth() + 1;
2707    // decide if we need to import sequences from an existing dataset
2708  0 boolean importDs = d.jalviewClipboard != null
2709    && d.jalviewClipboard[1] != alignment.getDataset();
2710    // importDs==true instructs us to copy over new dataset sequences from
2711    // an existing alignment
2712  0 Vector<SequenceI> newDs = (importDs) ? new Vector<>() : null; // used to
2713    // create
2714    // minimum dataset set
2715   
2716  0 for (int i = 0; i < sequences.length; i++)
2717    {
2718  0 if (importDs)
2719    {
2720  0 newDs.addElement(null);
2721    }
2722  0 SequenceI ds = sequences[i].getDatasetSequence(); // null for a simple
2723    // paste
2724  0 if (importDs && ds != null)
2725    {
2726  0 if (!newDs.contains(ds))
2727    {
2728  0 newDs.setElementAt(ds, i);
2729  0 ds = new Sequence(ds);
2730    // update with new dataset sequence
2731  0 sequences[i].setDatasetSequence(ds);
2732    }
2733    else
2734    {
2735  0 ds = sequences[newDs.indexOf(ds)].getDatasetSequence();
2736    }
2737    }
2738    else
2739    {
2740    // copy and derive new dataset sequence
2741  0 sequences[i] = sequences[i].deriveSequence();
2742  0 alignment.getDataset()
2743    .addSequence(sequences[i].getDatasetSequence());
2744    // TODO: avoid creation of duplicate dataset sequences with a
2745    // 'contains' method using SequenceI.equals()/SequenceI.contains()
2746    }
2747  0 alignment.addSequence(sequences[i]); // merges dataset
2748    }
2749  0 if (newDs != null)
2750    {
2751  0 newDs.clear(); // tidy up
2752    }
2753  0 if (alignment.getAlignmentAnnotation() != null)
2754    {
2755  0 for (AlignmentAnnotation alan : alignment
2756    .getAlignmentAnnotation())
2757    {
2758  0 if (alan.graphGroup > fgroup)
2759    {
2760  0 fgroup = alan.graphGroup;
2761    }
2762    }
2763    }
2764  0 if (pastedal.getAlignmentAnnotation() != null)
2765    {
2766    // Add any annotation attached to alignment.
2767  0 AlignmentAnnotation[] alann = pastedal.getAlignmentAnnotation();
2768  0 for (int i = 0; i < alann.length; i++)
2769    {
2770  0 annotationAdded = true;
2771  0 if (alann[i].sequenceRef == null && !alann[i].autoCalculated)
2772    {
2773  0 AlignmentAnnotation newann = new AlignmentAnnotation(
2774    alann[i]);
2775  0 if (newann.graphGroup > -1)
2776    {
2777  0 if (newGraphGroups.size() <= newann.graphGroup
2778    || newGraphGroups.get(newann.graphGroup) == null)
2779    {
2780  0 for (int q = newGraphGroups
2781  0 .size(); q <= newann.graphGroup; q++)
2782    {
2783  0 newGraphGroups.add(q, null);
2784    }
2785  0 newGraphGroups.set(newann.graphGroup,
2786    Integer.valueOf(++fgroup));
2787    }
2788  0 newann.graphGroup = newGraphGroups.get(newann.graphGroup)
2789    .intValue();
2790    }
2791   
2792  0 newann.padAnnotation(alwidth);
2793  0 alignment.addAnnotation(newann);
2794    }
2795    }
2796    }
2797    }
2798  0 if (!newAlignment)
2799    {
2800    // /////
2801    // ADD HISTORY ITEM
2802    //
2803  0 addHistoryItem(new EditCommand(
2804    MessageManager.getString("label.add_sequences"),
2805    Action.PASTE, sequences, 0, alignment.getWidth(),
2806    alignment));
2807    }
2808    // Add any annotations attached to sequences
2809  0 for (int i = 0; i < sequences.length; i++)
2810    {
2811  0 if (sequences[i].getAnnotation() != null)
2812    {
2813  0 AlignmentAnnotation newann;
2814  0 for (int a = 0; a < sequences[i].getAnnotation().length; a++)
2815    {
2816  0 annotationAdded = true;
2817  0 newann = sequences[i].getAnnotation()[a];
2818  0 newann.adjustForAlignment();
2819  0 newann.padAnnotation(alwidth);
2820  0 if (newann.graphGroup > -1)
2821    {
2822  0 if (newann.graphGroup > -1)
2823    {
2824  0 if (newGraphGroups.size() <= newann.graphGroup
2825    || newGraphGroups.get(newann.graphGroup) == null)
2826    {
2827  0 for (int q = newGraphGroups
2828  0 .size(); q <= newann.graphGroup; q++)
2829    {
2830  0 newGraphGroups.add(q, null);
2831    }
2832  0 newGraphGroups.set(newann.graphGroup,
2833    Integer.valueOf(++fgroup));
2834    }
2835  0 newann.graphGroup = newGraphGroups.get(newann.graphGroup)
2836    .intValue();
2837    }
2838    }
2839    // annotation was duplicated earlier
2840  0 alignment.addAnnotation(sequences[i].getAnnotation()[a]);
2841    // take care of contact matrix too
2842  0 ContactMatrixI cm = sequences[i]
2843    .getContactMatrixFor(sequences[i].getAnnotation()[a]);
2844  0 if (cm != null)
2845    {
2846  0 alignment.addContactListFor(sequences[i].getAnnotation()[a],
2847    cm);
2848    }
2849   
2850  0 alignment.setAnnotationIndex(sequences[i].getAnnotation()[a],
2851    a);
2852    }
2853    }
2854    }
2855  0 if (!newAlignment)
2856    {
2857   
2858    // propagate alignment changed.
2859  0 viewport.getRanges().setEndSeq(alignment.getHeight() - 1);
2860  0 if (annotationAdded)
2861    {
2862    // Duplicate sequence annotation in all views.
2863  0 AlignmentI[] alview = this.getViewAlignments();
2864  0 for (int i = 0; i < sequences.length; i++)
2865    {
2866  0 AlignmentAnnotation sann[] = sequences[i].getAnnotation();
2867  0 if (sann == null)
2868    {
2869  0 continue;
2870    }
2871  0 for (int avnum = 0; avnum < alview.length; avnum++)
2872    {
2873  0 if (alview[avnum] != alignment)
2874    {
2875    // duplicate in a view other than the one with input focus
2876  0 int avwidth = alview[avnum].getWidth() + 1;
2877    // this relies on sann being preserved after we
2878    // modify the sequence's annotation array for each duplication
2879  0 for (int a = 0; a < sann.length; a++)
2880    {
2881  0 AlignmentAnnotation newann = new AlignmentAnnotation(
2882    sann[a]);
2883  0 sequences[i].addAlignmentAnnotation(newann);
2884  0 newann.padAnnotation(avwidth);
2885  0 alview[avnum].addAnnotation(newann); // annotation was
2886    // duplicated earlier
2887    // TODO JAL-1145 graphGroups are not updated for sequence
2888    // annotation added to several views. This may cause
2889    // strangeness
2890  0 alview[avnum].setAnnotationIndex(newann, a);
2891    }
2892    }
2893    }
2894    }
2895  0 buildSortByAnnotationScoresMenu();
2896    }
2897  0 viewport.notifyAlignment();
2898  0 if (alignPanels != null)
2899    {
2900  0 for (AlignmentPanel ap : alignPanels)
2901    {
2902  0 ap.validateAnnotationDimensions(false);
2903    }
2904    }
2905    else
2906    {
2907  0 alignPanel.validateAnnotationDimensions(false);
2908    }
2909   
2910    }
2911    else
2912    {
2913  0 AlignFrame af = new AlignFrame(alignment, DEFAULT_WIDTH,
2914    DEFAULT_HEIGHT);
2915  0 String newtitle = new String("Copied sequences");
2916   
2917  0 if (d.jalviewClipboard != null && d.jalviewClipboard[2] != null)
2918    {
2919  0 HiddenColumns hc = (HiddenColumns) d.jalviewClipboard[2];
2920  0 af.viewport.setHiddenColumns(hc);
2921    }
2922   
2923    // >>>This is a fix for the moment, until a better solution is
2924    // found!!<<<
2925  0 af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
2926    .transferSettings(alignPanel.getSeqPanel().seqCanvas
2927    .getFeatureRenderer());
2928   
2929    // TODO: maintain provenance of an alignment, rather than just make the
2930    // title a concatenation of operations.
2931  0 if (!externalPaste)
2932    {
2933  0 if (title.startsWith("Copied sequences"))
2934    {
2935  0 newtitle = title;
2936    }
2937    else
2938    {
2939  0 newtitle = newtitle.concat("- from " + title);
2940    }
2941    }
2942    else
2943    {
2944  0 newtitle = new String("Pasted sequences");
2945    }
2946   
2947  0 Desktop.addInternalFrame(af, newtitle, DEFAULT_WIDTH,
2948    DEFAULT_HEIGHT);
2949   
2950    }
2951   
2952    } catch (Exception ex)
2953    {
2954  0 ex.printStackTrace();
2955  0 jalview.bin.Console.outPrintln("Exception whilst pasting: " + ex);
2956    // could be anything being pasted in here
2957    }
2958   
2959    }
2960   
 
2961  0 toggle @Override
2962    protected void expand_newalign(ActionEvent e)
2963    {
2964  0 try
2965    {
2966  0 AlignmentI alignment = AlignmentUtils
2967    .expandContext(getViewport().getAlignment(), -1);
2968  0 AlignFrame af = new AlignFrame(alignment, DEFAULT_WIDTH,
2969    DEFAULT_HEIGHT);
2970  0 String newtitle = new String("Flanking alignment");
2971   
2972  0 Desktop d = Desktop.getInstance();
2973  0 if (d.jalviewClipboard != null && d.jalviewClipboard[2] != null)
2974    {
2975  0 HiddenColumns hc = (HiddenColumns) d.jalviewClipboard[2];
2976  0 af.viewport.setHiddenColumns(hc);
2977    }
2978   
2979    // >>>This is a fix for the moment, until a better solution is
2980    // found!!<<<
2981  0 af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
2982    .transferSettings(alignPanel.getSeqPanel().seqCanvas
2983    .getFeatureRenderer());
2984   
2985    // TODO: maintain provenance of an alignment, rather than just make the
2986    // title a concatenation of operations.
2987    {
2988  0 if (title.startsWith("Copied sequences"))
2989    {
2990  0 newtitle = title;
2991    }
2992    else
2993    {
2994  0 newtitle = newtitle.concat("- from " + title);
2995    }
2996    }
2997   
2998  0 Desktop.addInternalFrame(af, newtitle, DEFAULT_WIDTH, DEFAULT_HEIGHT);
2999   
3000    } catch (Exception ex)
3001    {
3002  0 ex.printStackTrace();
3003  0 jalview.bin.Console.outPrintln("Exception whilst pasting: " + ex);
3004    // could be anything being pasted in here
3005    } catch (OutOfMemoryError oom)
3006    {
3007  0 new OOMWarning("Viewing flanking region of alignment", oom);
3008    }
3009    }
3010   
3011    /**
3012    * Action Cut (delete and copy) the selected region
3013    */
 
3014  0 toggle @Override
3015    protected void cut_actionPerformed()
3016    {
3017  0 copy_actionPerformed();
3018  0 delete_actionPerformed();
3019    }
3020   
3021    /**
3022    * Performs menu option to Delete the currently selected region
3023    */
 
3024  0 toggle @Override
3025    protected void delete_actionPerformed()
3026    {
3027   
3028  0 SequenceGroup sg = viewport.getSelectionGroup();
3029  0 if (sg == null)
3030    {
3031  0 return;
3032    }
3033   
3034  0 Runnable okAction = () -> {
3035  0 SequenceI[] cut = sg.getSequences()
3036    .toArray(new SequenceI[sg.getSize()]);
3037   
3038  0 addHistoryItem(new EditCommand(
3039    MessageManager.getString("label.cut_sequences"), Action.CUT,
3040    cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
3041    viewport.getAlignment()));
3042   
3043  0 viewport.setSelectionGroup(null);
3044  0 viewport.sendSelection();
3045  0 viewport.getAlignment().deleteGroup(sg);
3046   
3047  0 viewport.notifyAlignment();
3048  0 if (viewport.getAlignment().getHeight() < 1)
3049    {
3050  0 try
3051    {
3052  0 AlignFrame.this.setClosed(true);
3053    } catch (Exception ex)
3054    {
3055    }
3056    }
3057    else
3058    {
3059  0 updateAll(null);
3060    }
3061    };
3062   
3063    /*
3064    * If the cut affects all sequences, prompt for confirmation
3065    */
3066  0 boolean wholeHeight = sg.getSize() == viewport.getAlignment()
3067    .getHeight();
3068  0 boolean wholeWidth = (((sg.getEndRes() - sg.getStartRes())
3069    + 1) == viewport.getAlignment().getWidth()) ? true : false;
3070  0 if (wholeHeight && wholeWidth)
3071    {
3072  0 JvOptionPane dialog = JvOptionPane
3073    .newOptionDialog(Desktop.getDesktopPane());
3074  0 dialog.setResponseHandler(0, okAction); // 0 = OK_OPTION
3075  0 Object[] options = new Object[] {
3076    MessageManager.getString("action.ok"),
3077    MessageManager.getString("action.cancel") };
3078  0 dialog.showDialog(MessageManager.getString("warn.delete_all"),
3079    MessageManager.getString("label.delete_all"),
3080    JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null,
3081    options, options[0]);
3082    }
3083    else
3084    {
3085  0 try
3086    {
3087  0 okAction.run();
3088    } catch (Exception e)
3089    {
3090  0 e.printStackTrace();
3091    }
3092    }
3093    }
3094   
3095    /**
3096    * DOCUMENT ME!
3097    *
3098    * @param e
3099    * DOCUMENT ME!
3100    */
 
3101  0 toggle @Override
3102    protected void deleteGroups_actionPerformed(ActionEvent e)
3103    {
3104  0 if (avc.deleteGroups())
3105    {
3106  0 updateAll(viewport.getSequenceSetId());
3107    }
3108    }
3109   
 
3110  0 toggle private void updateAll(String id)
3111    {
3112  0 if (id == null)
3113    {
3114    // this will force a non-fast repaint of both the IdPanel and SeqPanel
3115  0 alignPanel.getIdPanel().getIdCanvas().setNoFastPaint();
3116  0 alignPanel.getSeqPanel().seqCanvas.setNoFastPaint();
3117  0 alignPanel.repaint();
3118    }
3119    else
3120    {
3121    // original version
3122  0 PaintRefresher.Refresh(this, id);
3123  0 alignPanel.paintAlignment(true, true);
3124    }
3125  0 alignPanel.updateAnnotation();
3126    }
3127   
3128    /**
3129    * DOCUMENT ME!
3130    *
3131    * @param e
3132    * DOCUMENT ME!
3133    */
 
3134  6 toggle @Override
3135    public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)
3136    {
3137  6 alignPanel.selectAllSequences();
3138    }
3139   
3140    /**
3141    * DOCUMENT ME!
3142    *
3143    * @param e
3144    * DOCUMENT ME!
3145    */
 
3146  2 toggle @Override
3147    public void deselectAllSequenceMenuItem_actionPerformed(ActionEvent e)
3148    {
3149  2 alignPanel.deselectAllSequences();
3150    }
3151   
3152    /**
3153    * DOCUMENT ME!
3154    *
3155    * @param e
3156    * DOCUMENT ME!
3157    */
 
3158  0 toggle @Override
3159    public void invertSequenceMenuItem_actionPerformed(ActionEvent e)
3160    {
3161  0 SequenceGroup sg = viewport.getSelectionGroup();
3162   
3163  0 if (sg == null)
3164    {
3165  0 alignPanel.selectAllSequences();
3166   
3167  0 return;
3168    }
3169   
3170  0 for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
3171    {
3172  0 sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
3173    }
3174    // JAL-2034 - should delegate to
3175    // alignPanel to decide if overview needs
3176    // updating.
3177   
3178  0 alignPanel.paintAlignment(true, false);
3179  0 PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
3180  0 viewport.sendSelection();
3181    }
3182   
 
3183  0 toggle @Override
3184    public void invertColSel_actionPerformed(ActionEvent e)
3185    {
3186  0 viewport.invertColumnSelection();
3187  0 alignPanel.paintAlignment(true, false);
3188  0 PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
3189  0 viewport.sendSelection();
3190    }
3191   
3192    /**
3193    * DOCUMENT ME!
3194    *
3195    * @param e
3196    * DOCUMENT ME!
3197    */
 
3198  0 toggle @Override
3199    public void remove2LeftMenuItem_actionPerformed(ActionEvent e)
3200    {
3201  0 trimAlignment(true);
3202    }
3203   
3204    /**
3205    * DOCUMENT ME!
3206    *
3207    * @param e
3208    * DOCUMENT ME!
3209    */
 
3210  0 toggle @Override
3211    public void remove2RightMenuItem_actionPerformed(ActionEvent e)
3212    {
3213  0 trimAlignment(false);
3214    }
3215   
 
3216  0 toggle void trimAlignment(boolean trimLeft)
3217    {
3218  0 ColumnSelection colSel = viewport.getColumnSelection();
3219  0 int column;
3220   
3221  0 if (!colSel.isEmpty())
3222    {
3223  0 if (trimLeft)
3224    {
3225  0 column = colSel.getMin();
3226    }
3227    else
3228    {
3229  0 column = colSel.getMax();
3230    }
3231   
3232  0 SequenceI[] seqs;
3233  0 if (viewport.getSelectionGroup() != null)
3234    {
3235  0 seqs = viewport.getSelectionGroup()
3236    .getSequencesAsArray(viewport.getHiddenRepSequences());
3237    }
3238    else
3239    {
3240  0 seqs = viewport.getAlignment().getSequencesArray();
3241    }
3242   
3243  0 TrimRegionCommand trimRegion;
3244  0 if (trimLeft)
3245    {
3246  0 trimRegion = new TrimRegionCommand("Remove Left", true, seqs,
3247    column, viewport.getAlignment());
3248  0 viewport.getRanges().setStartRes(0);
3249    }
3250    else
3251    {
3252  0 trimRegion = new TrimRegionCommand("Remove Right", false, seqs,
3253    column, viewport.getAlignment());
3254    }
3255   
3256  0 setStatus(MessageManager.formatMessage("label.removed_columns",
3257    new String[]
3258    { Integer.valueOf(trimRegion.getSize()).toString() }));
3259   
3260  0 addHistoryItem(trimRegion);
3261   
3262  0 for (SequenceGroup sg : viewport.getAlignment().getGroups())
3263    {
3264  0 if ((trimLeft && !sg.adjustForRemoveLeft(column))
3265    || (!trimLeft && !sg.adjustForRemoveRight(column)))
3266    {
3267  0 viewport.getAlignment().deleteGroup(sg);
3268    }
3269    }
3270   
3271  0 viewport.notifyAlignment();
3272    }
3273    }
3274   
3275    /**
3276    * DOCUMENT ME!
3277    *
3278    * @param e
3279    * DOCUMENT ME!
3280    */
 
3281  0 toggle @Override
3282    public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e)
3283    {
3284  0 int start = 0, end = viewport.getAlignment().getWidth() - 1;
3285   
3286  0 SequenceI[] seqs;
3287  0 if (viewport.getSelectionGroup() != null)
3288    {
3289  0 seqs = viewport.getSelectionGroup()
3290    .getSequencesAsArray(viewport.getHiddenRepSequences());
3291  0 start = viewport.getSelectionGroup().getStartRes();
3292  0 end = viewport.getSelectionGroup().getEndRes();
3293    }
3294    else
3295    {
3296  0 seqs = viewport.getAlignment().getSequencesArray();
3297    }
3298   
3299  0 RemoveGapColCommand removeGapCols = new RemoveGapColCommand(
3300    "Remove Gapped Columns", seqs, start, end,
3301    viewport.getAlignment());
3302   
3303  0 addHistoryItem(removeGapCols);
3304   
3305  0 setStatus(MessageManager.formatMessage("label.removed_empty_columns",
3306    new Object[]
3307    { Integer.valueOf(removeGapCols.getSize()).toString() }));
3308   
3309    // This is to maintain viewport position on first residue
3310    // of first sequence
3311  0 SequenceI seq = viewport.getAlignment().getSequenceAt(0);
3312  0 ViewportRanges ranges = viewport.getRanges();
3313  0 int startRes = seq.findPosition(ranges.getStartRes());
3314    // ShiftList shifts;
3315    // viewport.getAlignment().removeGaps(shifts=new ShiftList());
3316    // edit.alColumnChanges=shifts.getInverse();
3317    // if (viewport.hasHiddenColumns)
3318    // viewport.getColumnSelection().compensateForEdits(shifts);
3319  0 ranges.setStartRes(seq.findIndex(startRes) - 1);
3320  0 viewport.notifyAlignment();
3321   
3322    }
3323   
3324    /**
3325    * DOCUMENT ME!
3326    *
3327    * @param e
3328    * DOCUMENT ME!
3329    */
 
3330  0 toggle @Override
3331    public void removeAllGapsMenuItem_actionPerformed(ActionEvent e)
3332    {
3333  0 int start = 0, end = viewport.getAlignment().getWidth() - 1;
3334   
3335  0 SequenceI[] seqs;
3336  0 if (viewport.getSelectionGroup() != null)
3337    {
3338  0 seqs = viewport.getSelectionGroup()
3339    .getSequencesAsArray(viewport.getHiddenRepSequences());
3340  0 start = viewport.getSelectionGroup().getStartRes();
3341  0 end = viewport.getSelectionGroup().getEndRes();
3342    }
3343    else
3344    {
3345  0 seqs = viewport.getAlignment().getSequencesArray();
3346    }
3347   
3348    // This is to maintain viewport position on first residue
3349    // of first sequence
3350  0 SequenceI seq = viewport.getAlignment().getSequenceAt(0);
3351  0 int startRes = seq.findPosition(viewport.getRanges().getStartRes());
3352   
3353  0 addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
3354    viewport.getAlignment()));
3355   
3356  0 viewport.getRanges().setStartRes(seq.findIndex(startRes) - 1);
3357   
3358  0 viewport.notifyAlignment();
3359   
3360    }
3361   
3362    /**
3363    * DOCUMENT ME!
3364    *
3365    * @param e
3366    * DOCUMENT ME!
3367    */
 
3368  0 toggle @Override
3369    public void padGapsMenuitem_actionPerformed(ActionEvent e)
3370    {
3371  0 viewport.setPadGaps(padGapsMenuitem.isSelected());
3372  0 viewport.notifyAlignment();
3373    }
3374   
3375    /**
3376    * Opens a Finder dialog
3377    *
3378    * @param e
3379    */
 
3380  0 toggle @Override
3381    public void findMenuItem_actionPerformed(ActionEvent e)
3382    {
3383  0 new Finder(alignPanel, false, null);
3384    }
3385   
3386    /**
3387    * Create a new view of the current alignment.
3388    */
 
3389  7 toggle @Override
3390    public void newView_actionPerformed(ActionEvent e)
3391    {
3392  7 newView(null, true);
3393    }
3394   
3395    /**
3396    * Creates and shows a new view of the current alignment.
3397    *
3398    * @param viewTitle
3399    * title of newly created view; if null, one will be generated
3400    * @param copyAnnotation
3401    * if true then duplicate all annnotation, groups and settings
3402    * @return new alignment panel, already displayed.
3403    */
 
3404  10 toggle public AlignmentPanel newView(String viewTitle, boolean copyAnnotation)
3405    {
3406    /*
3407    * Create a new AlignmentPanel (with its own, new Viewport)
3408    */
3409  10 AlignmentPanel newap = new jalview.project.Jalview2XML()
3410    .copyAlignPanel(alignPanel);
3411  10 if (!copyAnnotation)
3412    {
3413    /*
3414    * remove all groups and annotation except for the automatic stuff
3415    */
3416  0 newap.av.getAlignment().deleteAllGroups();
3417  0 newap.av.getAlignment().deleteAllAnnotations(false);
3418    }
3419   
3420  10 newap.av.setGatherViewsHere(false);
3421   
3422  10 if (viewport.getViewName() == null)
3423    {
3424  9 viewport.setViewName(
3425    MessageManager.getString("label.view_name_original"));
3426    }
3427   
3428    /*
3429    * Views share the same edits undo and redo stacks
3430    */
3431  10 newap.av.setHistoryList(viewport.getHistoryList());
3432  10 newap.av.setRedoList(viewport.getRedoList());
3433   
3434    /*
3435    * copy any visualisation settings that are not saved in the project
3436    */
3437  10 newap.av.setColourAppliesToAllGroups(
3438    viewport.getColourAppliesToAllGroups());
3439   
3440    /*
3441    * Views share the same mappings; need to deregister any new mappings created by
3442    * copyAlignPanel, and register the new reference to the shared mappings
3443    */
3444  10 newap.av.replaceMappings(viewport.getAlignment());
3445   
3446    /*
3447    * start up cDNA consensus (if applicable) now mappings are in place
3448    */
3449  10 if (newap.av.initComplementConsensus())
3450    {
3451  0 newap.refresh(true); // adjust layout of annotations
3452    }
3453   
3454  10 newap.av.setViewName(getNewViewName(viewTitle));
3455   
3456  10 addAlignmentPanel(newap, true);
3457  10 newap.alignmentChanged();
3458   
3459  10 if (alignPanels.size() == 2)
3460    {
3461  9 viewport.setGatherViewsHere(true);
3462    }
3463  10 tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
3464   
3465  10 return newap;
3466    }
3467   
3468    /**
3469    * Make a new name for the view, ensuring it is unique within the current
3470    * sequenceSetId. (This used to be essential for Jalview Project archives, but
3471    * these now use viewId. Unique view names are still desirable for usability.)
3472    *
3473    * @param viewTitle
3474    * @return
3475    */
 
3476  10 toggle protected String getNewViewName(String viewTitle)
3477    {
3478  10 int index = Desktop.getViewCount(viewport.getSequenceSetId());
3479  10 boolean addFirstIndex = false;
3480  10 if (viewTitle == null || viewTitle.trim().length() == 0)
3481    {
3482  7 viewTitle = MessageManager.getString("action.view");
3483  7 addFirstIndex = true;
3484    }
3485    else
3486    {
3487  3 index = 1;// we count from 1 if given a specific name
3488    }
3489  10 String newViewName = viewTitle + ((addFirstIndex) ? " " + index : "");
3490   
3491  10 List<Component> comps = PaintRefresher.components
3492    .get(viewport.getSequenceSetId());
3493   
3494  10 List<String> existingNames = getExistingViewNames(comps);
3495   
3496  10 while (existingNames.contains(newViewName))
3497    {
3498  0 newViewName = viewTitle + " " + (++index);
3499    }
3500  10 return newViewName;
3501    }
3502   
3503    /**
3504    * Returns a list of distinct view names found in the given list of
3505    * components. View names are held on the viewport of an AlignmentPanel.
3506    *
3507    * @param comps
3508    * @return
3509    */
 
3510  10 toggle protected List<String> getExistingViewNames(List<Component> comps)
3511    {
3512  10 List<String> existingNames = new ArrayList<>();
3513  10 for (Component comp : comps)
3514    {
3515  63 if (comp instanceof AlignmentPanel)
3516    {
3517  21 AlignmentPanel ap = (AlignmentPanel) comp;
3518  21 if (!existingNames.contains(ap.av.getViewName()))
3519    {
3520  20 existingNames.add(ap.av.getViewName());
3521    }
3522    }
3523    }
3524  10 return existingNames;
3525    }
3526   
3527    /**
3528    * Explode tabbed views into separate windows.
3529    */
 
3530  0 toggle @Override
3531    public void expandViews_actionPerformed(ActionEvent e)
3532    {
3533  0 Desktop.explodeViews(this);
3534    }
3535   
3536    /**
3537    * Gather views in separate windows back into a tabbed presentation.
3538    */
 
3539  0 toggle @Override
3540    public void gatherViews_actionPerformed(ActionEvent e)
3541    {
3542  0 Desktop.getInstance().gatherViews(this);
3543    }
3544   
3545    /**
3546    * DOCUMENT ME!
3547    *
3548    * @param e
3549    * DOCUMENT ME!
3550    */
 
3551  0 toggle @Override
3552    public void font_actionPerformed(ActionEvent e)
3553    {
3554  0 new FontChooser(alignPanel);
3555    }
3556   
3557    /**
3558    * DOCUMENT ME!
3559    *
3560    * @param e
3561    * DOCUMENT ME!
3562    */
 
3563  0 toggle @Override
3564    protected void seqLimit_actionPerformed(ActionEvent e)
3565    {
3566  0 viewport.setShowJVSuffix(seqLimits.isSelected());
3567   
3568  0 alignPanel.getIdPanel().getIdCanvas()
3569    .setPreferredSize(alignPanel.calculateIdWidth());
3570  0 alignPanel.paintAlignment(true, false);
3571    }
3572   
 
3573  0 toggle @Override
3574    public void idRightAlign_actionPerformed(ActionEvent e)
3575    {
3576  0 viewport.setRightAlignIds(idRightAlign.isSelected());
3577  0 alignPanel.paintAlignment(false, false);
3578    }
3579   
 
3580  0 toggle @Override
3581    public void centreColumnLabels_actionPerformed(ActionEvent e)
3582    {
3583  0 viewport.setCentreColumnLabels(centreColumnLabelsMenuItem.getState());
3584  0 alignPanel.paintAlignment(false, false);
3585    }
3586   
3587    /*
3588    * (non-Javadoc)
3589    *
3590    * @see jalview.jbgui.GAlignFrame#followHighlight_actionPerformed()
3591    */
 
3592  0 toggle @Override
3593    protected void followHighlight_actionPerformed()
3594    {
3595    /*
3596    * Set the 'follow' flag on the Viewport (and scroll to position if now true).
3597    */
3598  0 final boolean state = this.followHighlightMenuItem.getState();
3599  0 viewport.setFollowHighlight(state);
3600  0 if (state)
3601    {
3602  0 alignPanel.scrollToPosition(viewport.getSearchResults());
3603    }
3604    }
3605   
3606    /**
3607    * DOCUMENT ME!
3608    *
3609    * @param e
3610    * DOCUMENT ME!
3611    */
 
3612  0 toggle @Override
3613    protected void colourTextMenuItem_actionPerformed(ActionEvent e)
3614    {
3615  0 viewport.setColourText(colourTextMenuItem.isSelected());
3616  0 alignPanel.paintAlignment(false, false);
3617    }
3618   
3619    /**
3620    * DOCUMENT ME!
3621    *
3622    * @param e
3623    * DOCUMENT ME!
3624    */
 
3625  7 toggle @Override
3626    public void wrapMenuItem_actionPerformed(ActionEvent e)
3627    {
3628  7 setWrapFormat(wrapMenuItem.isSelected(), false);
3629    }
3630   
 
3631  8 toggle public void setWrapFormat(boolean b, boolean setMenuItem)
3632    {
3633  8 scaleAbove.setVisible(b);
3634  8 scaleLeft.setVisible(b);
3635  8 scaleRight.setVisible(b);
3636  8 viewport.setWrapAlignment(b);
3637  8 alignPanel.updateLayout();
3638  8 if (setMenuItem)
3639    {
3640  0 wrapMenuItem.setSelected(b);
3641    }
3642    }
3643   
 
3644  0 toggle @Override
3645    public void showAllSeqs_actionPerformed(ActionEvent e)
3646    {
3647  0 viewport.showAllHiddenSeqs();
3648    }
3649   
 
3650  0 toggle @Override
3651    public void showAllColumns_actionPerformed(ActionEvent e)
3652    {
3653  0 viewport.showAllHiddenColumns();
3654  0 alignPanel.paintAlignment(true, true);
3655  0 viewport.sendSelection();
3656    }
3657   
 
3658  0 toggle @Override
3659    public void hideSelSequences_actionPerformed(ActionEvent e)
3660    {
3661  0 viewport.hideAllSelectedSeqs();
3662    }
3663   
3664    /**
3665    * called by key handler and the hide all/show all menu items
3666    *
3667    * @param toggleSeqs
3668    * @param toggleCols
3669    */
 
3670  0 toggle protected void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
3671    {
3672   
3673  0 boolean hide = false;
3674  0 SequenceGroup sg = viewport.getSelectionGroup();
3675  0 if (!toggleSeqs && !toggleCols)
3676    {
3677    // Hide everything by the current selection - this is a hack - we do the
3678    // invert and then hide
3679    // first check that there will be visible columns after the invert.
3680  0 if (viewport.hasSelectedColumns() || (sg != null && sg.getSize() > 0
3681    && sg.getStartRes() <= sg.getEndRes()))
3682    {
3683    // now invert the sequence set, if required - empty selection implies
3684    // that no hiding is required.
3685  0 if (sg != null)
3686    {
3687  0 invertSequenceMenuItem_actionPerformed(null);
3688  0 sg = viewport.getSelectionGroup();
3689  0 toggleSeqs = true;
3690   
3691    }
3692  0 viewport.expandColSelection(sg, true);
3693    // finally invert the column selection and get the new sequence
3694    // selection.
3695  0 invertColSel_actionPerformed(null);
3696  0 toggleCols = true;
3697    }
3698    }
3699   
3700  0 if (toggleSeqs)
3701    {
3702  0 if (sg != null && sg.getSize() != viewport.getAlignment().getHeight())
3703    {
3704  0 hideSelSequences_actionPerformed(null);
3705  0 hide = true;
3706    }
3707  0 else if (!(toggleCols && viewport.hasSelectedColumns()))
3708    {
3709  0 showAllSeqs_actionPerformed(null);
3710    }
3711    }
3712   
3713  0 if (toggleCols)
3714    {
3715  0 if (viewport.hasSelectedColumns())
3716    {
3717  0 hideSelColumns_actionPerformed(null);
3718  0 if (!toggleSeqs)
3719    {
3720  0 viewport.setSelectionGroup(sg);
3721    }
3722    }
3723  0 else if (!hide)
3724    {
3725  0 showAllColumns_actionPerformed(null);
3726    }
3727    }
3728    }
3729   
3730    /*
3731    * (non-Javadoc)
3732    *
3733    * @see jalview.jbgui.GAlignFrame#hideAllButSelection_actionPerformed(java.awt.
3734    * event.ActionEvent)
3735    */
 
3736  0 toggle @Override
3737    public void hideAllButSelection_actionPerformed(ActionEvent e)
3738    {
3739  0 toggleHiddenRegions(false, false);
3740  0 viewport.sendSelection();
3741    }
3742   
3743    /*
3744    * (non-Javadoc)
3745    *
3746    * @see
3747    * jalview.jbgui.GAlignFrame#hideAllSelection_actionPerformed(java.awt.event
3748    * .ActionEvent)
3749    */
 
3750  0 toggle @Override
3751    public void hideAllSelection_actionPerformed(ActionEvent e)
3752    {
3753  0 SequenceGroup sg = viewport.getSelectionGroup();
3754  0 viewport.expandColSelection(sg, false);
3755  0 viewport.hideAllSelectedSeqs();
3756  0 viewport.hideSelectedColumns();
3757  0 alignPanel.updateLayout();
3758  0 alignPanel.paintAlignment(true, true);
3759  0 viewport.sendSelection();
3760    }
3761   
3762    /*
3763    * (non-Javadoc)
3764    *
3765    * @see jalview.jbgui.GAlignFrame#showAllhidden_actionPerformed(java.awt.event.
3766    * ActionEvent)
3767    */
 
3768  0 toggle @Override
3769    public void showAllhidden_actionPerformed(ActionEvent e)
3770    {
3771  0 viewport.showAllHiddenColumns();
3772  0 viewport.showAllHiddenSeqs();
3773  0 alignPanel.paintAlignment(true, true);
3774  0 viewport.sendSelection();
3775    }
3776   
 
3777  2 toggle @Override
3778    public void hideSelColumns_actionPerformed(ActionEvent e)
3779    {
3780  2 viewport.hideSelectedColumns();
3781  2 alignPanel.updateLayout();
3782  2 alignPanel.paintAlignment(true, true);
3783  2 viewport.sendSelection();
3784    }
3785   
 
3786  0 toggle @Override
3787    public void hiddenMarkers_actionPerformed(ActionEvent e)
3788    {
3789  0 viewport.setShowHiddenMarkers(hiddenMarkers.isSelected());
3790  0 repaint();
3791    }
3792   
3793    /**
3794    * DOCUMENT ME!
3795    *
3796    * @param e
3797    * DOCUMENT ME!
3798    */
 
3799  0 toggle @Override
3800    protected void scaleAbove_actionPerformed(ActionEvent e)
3801    {
3802  0 viewport.setScaleAboveWrapped(scaleAbove.isSelected());
3803  0 alignPanel.updateLayout();
3804  0 alignPanel.paintAlignment(true, false);
3805    }
3806   
3807    /**
3808    * DOCUMENT ME!
3809    *
3810    * @param e
3811    * DOCUMENT ME!
3812    */
 
3813  0 toggle @Override
3814    protected void scaleLeft_actionPerformed(ActionEvent e)
3815    {
3816  0 viewport.setScaleLeftWrapped(scaleLeft.isSelected());
3817  0 alignPanel.updateLayout();
3818  0 alignPanel.paintAlignment(true, false);
3819    }
3820   
3821    /**
3822    * DOCUMENT ME!
3823    *
3824    * @param e
3825    * DOCUMENT ME!
3826    */
 
3827  0 toggle @Override
3828    protected void scaleRight_actionPerformed(ActionEvent e)
3829    {
3830  0 viewport.setScaleRightWrapped(scaleRight.isSelected());
3831  0 alignPanel.updateLayout();
3832  0 alignPanel.paintAlignment(true, false);
3833    }
3834   
3835    /**
3836    * DOCUMENT ME!
3837    *
3838    * @param e
3839    * DOCUMENT ME!
3840    */
 
3841  0 toggle @Override
3842    public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
3843    {
3844  0 viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
3845  0 alignPanel.paintAlignment(false, false);
3846    }
3847   
3848    /**
3849    * DOCUMENT ME!
3850    *
3851    * @param e
3852    * DOCUMENT ME!
3853    */
 
3854  0 toggle @Override
3855    public void viewTextMenuItem_actionPerformed(ActionEvent e)
3856    {
3857  0 viewport.setShowText(viewTextMenuItem.isSelected());
3858  0 alignPanel.paintAlignment(false, false);
3859    }
3860   
3861    /**
3862    * DOCUMENT ME!
3863    *
3864    * @param e
3865    * DOCUMENT ME!
3866    */
 
3867  0 toggle @Override
3868    protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
3869    {
3870  0 viewport.setRenderGaps(renderGapsMenuItem.isSelected());
3871  0 alignPanel.paintAlignment(false, false);
3872    }
3873   
3874    public FeatureSettings featureSettings;
3875   
 
3876  4 toggle @Override
3877    public FeatureSettingsControllerI getFeatureSettingsUI()
3878    {
3879  4 return featureSettings;
3880    }
3881   
 
3882  0 toggle @Override
3883    public void featureSettings_actionPerformed(ActionEvent e)
3884    {
3885  0 showFeatureSettingsUI();
3886    }
3887   
 
3888  0 toggle @Override
3889    public FeatureSettingsControllerI showFeatureSettingsUI()
3890    {
3891  0 if (featureSettings != null)
3892    {
3893  0 featureSettings.closeOldSettings();
3894  0 featureSettings = null;
3895    }
3896  0 if (!showSeqFeatures.isSelected())
3897    {
3898    // make sure features are actually displayed
3899  0 showSeqFeatures.setSelected(true);
3900  0 showSeqFeatures_actionPerformed(null);
3901    }
3902  0 featureSettings = new FeatureSettings(this);
3903  0 return featureSettings;
3904    }
3905   
3906    /**
3907    * Set or clear 'Show Sequence Features'
3908    *
3909    * @param evt
3910    * DOCUMENT ME!
3911    */
 
3912  0 toggle @Override
3913    public void showSeqFeatures_actionPerformed(ActionEvent evt)
3914    {
3915  0 viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
3916  0 alignPanel.paintAlignment(true, true);
3917    }
3918   
3919    /**
3920    * Action on toggle of the 'Show annotations' menu item. This shows or hides
3921    * the annotations panel as a whole.
3922    *
3923    * The options to show/hide all annotations should be enabled when the panel
3924    * is shown, and disabled when the panel is hidden.
3925    *
3926    * @param e
3927    */
 
3928  0 toggle @Override
3929    public void annotationPanelMenuItem_actionPerformed(ActionEvent e)
3930    {
3931  0 final boolean setVisible = annotationPanelMenuItem.isSelected();
3932  0 viewport.setShowAnnotation(setVisible);
3933  0 syncAnnotationMenuItems(setVisible);
3934  0 alignPanel.updateLayout();
3935  0 repaint();
3936  0 SwingUtilities.invokeLater(new Runnable()
3937    {
3938   
 
3939  0 toggle @Override
3940    public void run()
3941    {
3942  0 alignPanel.updateScrollBarsFromRanges();
3943    }
3944   
3945    });
3946    }
3947   
 
3948  729 toggle private void syncAnnotationMenuItems(boolean setVisible)
3949    {
3950  729 showAllSeqAnnotations.setEnabled(setVisible);
3951  729 hideAllSeqAnnotations.setEnabled(setVisible);
3952  729 showAllAlAnnotations.setEnabled(setVisible);
3953  729 hideAllAlAnnotations.setEnabled(setVisible);
3954    }
3955   
 
3956  0 toggle @Override
3957    public void alignmentProperties()
3958    {
3959  0 JComponent pane;
3960  0 StringBuffer contents = new AlignmentProperties(viewport.getAlignment())
3961   
3962    .formatAsHtml();
3963  0 String content = MessageManager.formatMessage("label.html_content",
3964    new Object[]
3965    { contents.toString() });
3966  0 contents = null;
3967   
3968  0 if (Platform.isJS())
3969    {
3970  0 JLabel textLabel = new JLabel();
3971  0 textLabel.setText(content);
3972  0 textLabel.setBackground(Color.WHITE);
3973   
3974  0 pane = new JPanel(new BorderLayout());
3975  0 pane.setOpaque(true);
3976  0 pane.setBackground(Color.WHITE);
3977  0 pane.add(textLabel, BorderLayout.NORTH);
3978    }
3979    else
3980    /**
3981    * Java only
3982    *
3983    * @j2sIgnore
3984    */
3985    {
3986  0 JEditorPane editPane = new JEditorPane("text/html", "");
3987  0 editPane.setEditable(false);
3988  0 editPane.setText(content);
3989  0 pane = editPane;
3990    }
3991   
3992  0 JInternalFrame frame = new JInternalFrame();
3993  0 frame.setFrameIcon(null);
3994  0 frame.getContentPane().add(new JScrollPane(pane));
3995   
3996  0 Desktop.addInternalFrame(frame, MessageManager
3997    .formatMessage("label.alignment_properties", new Object[]
3998    { getTitle() }), 500, 400);
3999    }
4000   
4001    /**
4002    * Opens an Overview panel for the alignment, unless one is open already
4003    *
4004    * @param e
4005    */
 
4006  30 toggle @Override
4007    public void overviewMenuItem_actionPerformed(ActionEvent e)
4008    {
4009  30 boolean showHiddenRegions = Cache
4010    .getDefault(Preferences.SHOW_OV_HIDDEN_AT_START, false);
4011  30 openOverviewPanel(showHiddenRegions);
4012    }
4013   
 
4014  43 toggle public OverviewPanel openOverviewPanel(boolean showHidden)
4015    {
4016  43 if (alignPanel.overviewPanel != null)
4017    {
4018  0 return alignPanel.overviewPanel;
4019    }
4020  43 JInternalFrame frame = new JInternalFrame();
4021  43 frame.setFrameIcon(null);
4022    // BH 2019.07.26 we allow for an embedded
4023    // undecorated overview with defined size
4024  43 frame.setName(Platform.getAppID("overview"));
4025    //
4026  43 Dimension dim = Platform.getDimIfEmbedded(frame, -1, -1);
4027  43 if (dim != null && dim.width == 0)
4028    {
4029  0 dim = null; // hidden, not embedded
4030    }
4031  43 OverviewPanel overview = new OverviewPanel(alignPanel, dim, showHidden);
4032   
4033   
4034  43 frame.setContentPane(overview);
4035  43 overview.setInternalFrame(frame);
4036  43 if (dim == null)
4037    {
4038  43 dim = new Dimension();
4039    // was frame.getSize(), but that is 0,0 at this point;
4040    }
4041    else
4042    {
4043    // we are imbedding, and so we have an undecorated frame
4044    // and we can set the the frame dimensions accordingly.
4045    }
4046    // allowing for unresizable option using, style="resize:none"
4047  43 boolean resizable = (Platform.getEmbeddedAttribute(frame,
4048    "resize") != "none");
4049    // TODO JAL-4107 check overview title naming behaviour is correct in 2.12 vs
4050    // 2.11.5.0
4051  43 alignPanel.setOverviewPanel(overview);
4052  43 alignPanel.setOverviewTitle(this);
4053   
4054  43 Desktop.addInternalFrame(frame, overview.getTitle(), Desktop.FRAME_MAKE_VISIBLE, dim.width,
4055    dim.height, resizable, Desktop.FRAME_ALLOW_ANY_SIZE);
4056  43 frame.pack();
4057  43 frame.setLayer(JLayeredPane.PALETTE_LAYER);
4058  43 final AlignmentPanel thePanel = this.alignPanel;
4059   
4060  43 frame.addInternalFrameListener(
4061    new javax.swing.event.InternalFrameAdapter()
4062    {
 
4063  43 toggle @Override
4064    public void internalFrameClosed(
4065    javax.swing.event.InternalFrameEvent evt)
4066    {
4067  43 overview.dispose();
4068  43 thePanel.setOverviewPanel(null);
4069    }
4070    });
4071  43 if (getKeyListeners().length > 0)
4072    {
4073  15 frame.addKeyListener(getKeyListeners()[0]);
4074    }
4075   
4076  43 return overview;
4077    }
4078   
 
4079  0 toggle @Override
4080    public void textColour_actionPerformed()
4081    {
4082  0 new TextColourChooser().chooseColour(alignPanel, null);
4083    }
4084   
4085    /*
4086    * public void covariationColour_actionPerformed() { changeColour(new
4087    * CovariationColourScheme(viewport.getAlignment().getAlignmentAnnotation
4088    * ()[0])); }
4089    */
 
4090  0 toggle @Override
4091    public void annotationColour_actionPerformed()
4092    {
4093  0 new AnnotationColourChooser(viewport, alignPanel);
4094    }
4095   
 
4096  0 toggle @Override
4097    public void annotationColumn_actionPerformed(ActionEvent e)
4098    {
4099  0 new AnnotationColumnChooser(viewport, alignPanel);
4100    }
4101   
4102    /**
4103    * Action on the user checking or unchecking the option to apply the selected
4104    * colour scheme to all groups. If unchecked, groups may have their own
4105    * independent colour schemes.
4106    *
4107    * @param selected
4108    */
 
4109  3 toggle @Override
4110    public void applyToAllGroups_actionPerformed(boolean selected)
4111    {
4112  3 viewport.setColourAppliesToAllGroups(selected);
4113    }
4114   
4115    /**
4116    * Action on user selecting a colour from the colour menu
4117    *
4118    * @param name
4119    * the name (not the menu item label!) of the colour scheme
4120    */
 
4121  15 toggle @Override
4122    public void changeColour_actionPerformed(String name)
4123    {
4124    /*
4125    * 'User Defined' opens a panel to configure or load a user-defined colour
4126    * scheme
4127    */
4128  15 if (ResidueColourScheme.USER_DEFINED_MENU.equals(name))
4129    {
4130  0 new UserDefinedColours(alignPanel);
4131  0 return;
4132    }
4133   
4134    /*
4135    * otherwise set the chosen colour scheme (or null for 'None')
4136    */
4137  15 ColourSchemeI cs = ColourSchemes.getInstance().getColourScheme(name,
4138    viewport, viewport.getAlignment(),
4139    viewport.getHiddenRepSequences());
4140  15 changeColour(cs);
4141    }
4142   
4143    /**
4144    * Actions on setting or changing the alignment colour scheme
4145    *
4146    * @param cs
4147    */
 
4148  176 toggle @Override
4149    public void changeColour(ColourSchemeI cs)
4150    {
4151    // TODO: pull up to controller method
4152  176 ColourMenuHelper.setColourSelected(colourMenu, cs);
4153   
4154  176 viewport.setGlobalColourScheme(cs);
4155   
4156  176 alignPanel.paintAlignment(true, true);
4157    }
4158   
4159    /**
4160    * Show the PID threshold slider panel
4161    */
 
4162  6 toggle @Override
4163    protected void modifyPID_actionPerformed()
4164    {
4165  6 SliderPanel.setPIDSliderSource(alignPanel, viewport.getResidueShading(),
4166    alignPanel.getViewName());
4167  6 SliderPanel.showPIDSlider();
4168    }
4169   
4170    /**
4171    * Show the Conservation slider panel
4172    */
 
4173  6 toggle @Override
4174    protected void modifyConservation_actionPerformed()
4175    {
4176  6 SliderPanel.setConservationSlider(alignPanel,
4177    viewport.getResidueShading(), alignPanel.getViewName());
4178  6 SliderPanel.showConservationSlider();
4179    }
4180   
 
4181  0 toggle @Override
4182    protected void modifyConsensusSecondaryStructureThreshold_actionPerformed()
4183    {
4184  0 SliderPanel.setConsensusSecondaryStructureSlider(alignPanel,
4185    viewport.getResidueShading(), alignPanel.getViewName());
4186  0 SliderPanel.showConsensusSecondaryStructureSlider();
4187    }
4188   
4189    /**
4190    * Action on selecting or deselecting (Colour) By Conservation
4191    */
 
4192  8 toggle @Override
4193    public void conservationMenuItem_actionPerformed(boolean selected)
4194    {
4195  8 modifyConservation.setEnabled(selected);
4196  8 viewport.setConservationSelected(selected);
4197  8 viewport.getResidueShading().setConservationApplied(selected);
4198   
4199  8 changeColour(viewport.getGlobalColourScheme());
4200  8 if (selected)
4201    {
4202  6 modifyConservation_actionPerformed();
4203    }
4204    else
4205    {
4206  2 SliderPanel.hideConservationSlider();
4207    }
4208    }
4209   
 
4210  0 toggle @Override
4211    public void colourByConsensusSecondaryStructureMenuItem_actionPerformed(
4212    boolean selected)
4213    {
4214  0 modifyConsensusSecondaryStructureThreshold.setEnabled(selected);
4215  0 viewport.setByConsensusSecondaryStructureSelected(selected);
4216  0 viewport.getResidueShading()
4217    .setConsensusSecondaryStructureColouring(selected);
4218   
4219  0 changeColour(viewport.getGlobalColourScheme());
4220  0 if (selected)
4221    {
4222  0 modifyConsensusSecondaryStructureThreshold_actionPerformed();
4223    }
4224    else
4225    {
4226  0 SliderPanel.hideConsensusSecondaryStructureSlider();
4227    }
4228    }
4229   
4230    /**
4231    * Action on selecting or deselecting (Colour) Above PID Threshold
4232    */
 
4233  9 toggle @Override
4234    public void abovePIDThreshold_actionPerformed(boolean selected)
4235    {
4236  9 modifyPID.setEnabled(selected);
4237  9 viewport.setAbovePIDThreshold(selected);
4238  9 if (!selected)
4239    {
4240  3 viewport.getResidueShading().setThreshold(0,
4241    viewport.isIgnoreGapsConsensus());
4242    }
4243   
4244  9 changeColour(viewport.getGlobalColourScheme());
4245  9 if (selected)
4246    {
4247  6 modifyPID_actionPerformed();
4248    }
4249    else
4250    {
4251  3 SliderPanel.hidePIDSlider();
4252    }
4253    }
4254   
4255    /**
4256    * DOCUMENT ME!
4257    *
4258    * @param e
4259    * DOCUMENT ME!
4260    */
 
4261  0 toggle @Override
4262    public void sortPairwiseMenuItem_actionPerformed(ActionEvent e)
4263    {
4264  0 SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
4265  0 AlignmentSorter.sortByPID(viewport.getAlignment(),
4266    viewport.getAlignment().getSequenceAt(0));
4267  0 addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
4268    viewport.getAlignment()));
4269  0 alignPanel.paintAlignment(true, false);
4270    }
4271   
4272    /**
4273    * DOCUMENT ME!
4274    *
4275    * @param e
4276    * DOCUMENT ME!
4277    */
 
4278  0 toggle @Override
4279    public void sortIDMenuItem_actionPerformed(ActionEvent e)
4280    {
4281  0 SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
4282  0 AlignmentSorter.sortByID(viewport.getAlignment());
4283  0 addHistoryItem(
4284    new OrderCommand("ID Sort", oldOrder, viewport.getAlignment()));
4285  0 alignPanel.paintAlignment(true, false);
4286    }
4287   
 
4288  0 toggle @Override
4289    protected void sortDescriptionMenuItem_actionPerformed(ActionEvent e)
4290    {
4291  0 SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
4292  0 AlignmentSorter.sortByDescription(viewport.getAlignment());
4293  0 addHistoryItem(new OrderCommand("Description Sort", oldOrder,
4294    viewport.getAlignment()));
4295  0 alignPanel.paintAlignment(true, false);
4296    }
4297   
4298    /**
4299    * DOCUMENT ME!
4300    *
4301    * @param e
4302    * DOCUMENT ME!
4303    */
 
4304  0 toggle @Override
4305    public void sortLengthMenuItem_actionPerformed(ActionEvent e)
4306    {
4307  0 SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
4308  0 AlignmentSorter.sortByLength(viewport.getAlignment());
4309  0 addHistoryItem(new OrderCommand("Length Sort", oldOrder,
4310    viewport.getAlignment()));
4311  0 alignPanel.paintAlignment(true, false);
4312    }
4313   
4314    /**
4315    * DOCUMENT ME!
4316    *
4317    * @param e
4318    * DOCUMENT ME!
4319    */
 
4320  0 toggle @Override
4321    public void sortGroupMenuItem_actionPerformed(ActionEvent e)
4322    {
4323  0 SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
4324  0 AlignmentSorter.sortByGroup(viewport.getAlignment());
4325  0 addHistoryItem(new OrderCommand("Group Sort", oldOrder,
4326    viewport.getAlignment()));
4327   
4328  0 alignPanel.paintAlignment(true, false);
4329    }
4330   
 
4331  0 toggle @Override
4332    public void sortEValueMenuItem_actionPerformed(ActionEvent e)
4333    {
4334  0 SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
4335  0 AlignmentSorter.sortByEValue(viewport.getAlignment());
4336  0 addHistoryItem(new OrderCommand("Group Sort", oldOrder,
4337    viewport.getAlignment()));
4338  0 alignPanel.paintAlignment(true, false);
4339   
4340    }
4341   
 
4342  0 toggle @Override
4343    public void sortBitScoreMenuItem_actionPerformed(ActionEvent e)
4344    {
4345  0 SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
4346  0 AlignmentSorter.sortByBitScore(viewport.getAlignment());
4347  0 addHistoryItem(new OrderCommand("Group Sort", oldOrder,
4348    viewport.getAlignment()));
4349  0 alignPanel.paintAlignment(true, false);
4350   
4351    }
4352   
4353    /**
4354    * DOCUMENT ME!
4355    *
4356    * @param e
4357    * DOCUMENT ME!
4358    */
 
4359  0 toggle @Override
4360    public void removeRedundancyMenuItem_actionPerformed(ActionEvent e)
4361    {
4362  0 new RedundancyPanel(alignPanel, this);
4363    }
4364   
4365    /**
4366    * DOCUMENT ME!
4367    *
4368    * @param e
4369    * DOCUMENT ME!
4370    */
 
4371  0 toggle @Override
4372    public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e)
4373    {
4374  0 if ((viewport.getSelectionGroup() == null)
4375    || (viewport.getSelectionGroup().getSize() < 2))
4376    {
4377  0 JvOptionPane.showInternalMessageDialog(this,
4378    MessageManager.getString(
4379    "label.you_must_select_least_two_sequences"),
4380    MessageManager.getString("label.invalid_selection"),
4381    JvOptionPane.WARNING_MESSAGE);
4382    }
4383    else
4384    {
4385  0 new Thread(new Runnable()
4386    {
 
4387  0 toggle @Override
4388    public void run()
4389    {
4390  0 JInternalFrame frame = new JInternalFrame();
4391  0 frame.setFrameIcon(null);
4392  0 frame.setContentPane(new PairwiseAlignPanel(viewport));
4393  0 Desktop.addInternalFrame(frame,
4394    MessageManager.getString("action.pairwise_alignment"),
4395    600, 500);
4396    }
4397    }).start();
4398   
4399    }
4400    }
4401   
 
4402  0 toggle @Override
4403    public void autoCalculate_actionPerformed(ActionEvent e)
4404    {
4405  0 viewport.setAutoCalculateConsensusAndConservation(
4406    autoCalculate.isSelected());
4407  0 if (viewport.getAutoCalculateConsensusAndConservation())
4408    {
4409  0 viewport.notifyAlignment();
4410    }
4411    }
4412   
 
4413  0 toggle @Override
4414    public void sortByTreeOption_actionPerformed(ActionEvent e)
4415    {
4416  0 viewport.sortByTree = sortByTree.isSelected();
4417    }
4418   
 
4419  0 toggle @Override
4420    protected void listenToViewSelections_actionPerformed(ActionEvent e)
4421    {
4422  0 viewport.followSelection = listenToViewSelections.isSelected();
4423    }
4424   
4425    /**
4426    * Constructs a tree panel and adds it to the desktop
4427    *
4428    * @param type
4429    * tree type (NJ or AV)
4430    * @param modelName
4431    * name of score model used to compute the tree
4432    * @param options
4433    * parameters for the distance or similarity calculation
4434    */
 
4435  0 toggle void newTreePanel(String type, String modelName,
4436    SimilarityParamsI options, boolean isAnnotationBased)
4437    {
4438  0 String frameTitle = "";
4439  0 TreePanel tp;
4440   
4441  0 boolean onSelection = false;
4442  0 if (viewport.getSelectionGroup() != null
4443    && viewport.getSelectionGroup().getSize() > 0)
4444    {
4445  0 SequenceGroup sg = viewport.getSelectionGroup();
4446   
4447    /* Decide if the selection is a column region */
4448  0 for (SequenceI _s : sg.getSequences())
4449    {
4450  0 if (_s.getLength() < sg.getEndRes())
4451    {
4452  0 JvOptionPane.showMessageDialog(Desktop.getDesktopPane(),
4453    MessageManager.getString(
4454    "label.selected_region_to_tree_may_only_contain_residues_or_gaps"),
4455    MessageManager.getString(
4456    "label.sequences_selection_not_aligned"),
4457    JvOptionPane.WARNING_MESSAGE);
4458   
4459  0 return;
4460    }
4461    }
4462  0 onSelection = true;
4463    }
4464    else
4465    {
4466    // Fix for JAL-4521. For annotation based tree, min number of sequence
4467    // required for tree calculation is 1 as multiple annotations can be
4468    // present for a single sequence
4469  0 if ((viewport.getAlignment().getHeight() < 2 && !isAnnotationBased)
4470    || (viewport.getAlignment().getHeight() < 1
4471    && isAnnotationBased))
4472    {
4473  0 return;
4474    }
4475    }
4476   
4477  0 tp = new TreePanel(alignPanel, type, modelName, options);
4478   
4479  0 frameTitle = formCalculationTitle(tp.getPanelTitle(), onSelection,
4480    this.title);
4481  0 Dimension dim = Platform.getDimIfEmbedded(tp, 600, 500);
4482  0 Desktop.addInternalFrame(tp, frameTitle, dim.width, dim.height);
4483    }
4484   
4485    /**
4486    *
4487    * @param panelTitle
4488    * - calculation name
4489    * @param onSelection
4490    * - true if a selection was analysed
4491    * @param viewName
4492    * - null or current view name
4493    * @param title
4494    * - alignment frame title
4495    * @return <calculation Name> (?on region) from (?viewName of) alignment name
4496    */
 
4497  2 toggle public String formCalculationTitle(String panelTitle, boolean onSelection,
4498    String title)
4499    {
4500  2 String frameTitle = panelTitle;
4501   
4502  2 frameTitle += (onSelection ? " on region" : "");
4503   
4504  2 frameTitle += " from ";
4505   
4506  2 if (viewport.getViewName() != null)
4507    {
4508  2 frameTitle += viewport.getViewName() + " of ";
4509    }
4510   
4511  2 frameTitle += title;
4512  2 return frameTitle;
4513    }
4514   
4515    /**
4516    * DOCUMENT ME!
4517    *
4518    * @param title
4519    * DOCUMENT ME!
4520    * @param order
4521    * DOCUMENT ME!
4522    */
 
4523  0 toggle public void addSortByOrderMenuItem(String title,
4524    final AlignmentOrder order)
4525    {
4526  0 final JMenuItem item = new JMenuItem(MessageManager
4527    .formatMessage("action.by_title_param", new Object[]
4528    { title }));
4529  0 sort.add(item);
4530  0 item.addActionListener(new java.awt.event.ActionListener()
4531    {
 
4532  0 toggle @Override
4533    public void actionPerformed(ActionEvent e)
4534    {
4535  0 SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
4536   
4537    // TODO: JBPNote - have to map order entries to curent SequenceI
4538    // pointers
4539  0 AlignmentSorter.sortBy(viewport.getAlignment(), order);
4540   
4541  0 addHistoryItem(new OrderCommand(order.getName(), oldOrder,
4542    viewport.getAlignment()));
4543   
4544  0 alignPanel.paintAlignment(true, false);
4545    }
4546    });
4547    }
4548   
4549    /**
4550    * Add a new sort by annotation score menu item
4551    *
4552    * @param sort
4553    * the menu to add the option to
4554    * @param scoreLabel
4555    * the label used to retrieve scores for each sequence on the
4556    * alignment
4557    */
 
4558  4 toggle public void addSortByAnnotScoreMenuItem(JMenu sort,
4559    final String scoreLabel)
4560    {
4561  4 final JMenuItem item = new JMenuItem(scoreLabel);
4562  4 sort.add(item);
4563  4 item.addActionListener(new java.awt.event.ActionListener()
4564    {
 
4565  0 toggle @Override
4566    public void actionPerformed(ActionEvent e)
4567    {
4568  0 SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
4569  0 AlignmentSorter.sortByAnnotationScore(scoreLabel,
4570    viewport.getAlignment());// ,viewport.getSelectionGroup());
4571  0 addHistoryItem(new OrderCommand("Sort by " + scoreLabel, oldOrder,
4572    viewport.getAlignment()));
4573  0 alignPanel.paintAlignment(true, false);
4574    }
4575    });
4576    }
4577   
4578    /**
4579    * last hash for alignment's annotation array - used to minimise cost of
4580    * rebuild.
4581    */
4582    protected int _annotationScoreVectorHash;
4583   
4584    /**
4585    * search the alignment and rebuild the sort by annotation score submenu the
4586    * last alignment annotation vector hash is stored to minimize cost of
4587    * rebuilding in subsequence calls.
4588    *
4589    */
 
4590  496 toggle @Override
4591    public void buildSortByAnnotationScoresMenu()
4592    {
4593  496 if (viewport.getAlignment().getAlignmentAnnotation() == null)
4594    {
4595  0 return;
4596    }
4597   
4598  496 if (viewport.getAlignment().getAlignmentAnnotation()
4599    .hashCode() == _annotationScoreVectorHash)
4600    {
4601  1 return;
4602    }
4603   
4604  495 sortByAnnotScore.removeAll();
4605  495 Set<String> scoreSorts = new HashSet<>();
4606  495 for (SequenceI sqa : viewport.getAlignment().getSequences())
4607    {
4608  4329 AlignmentAnnotation[] anns = sqa.getAnnotation();
4609  4898 for (int i = 0; anns != null && i < anns.length; i++)
4610    {
4611  569 AlignmentAnnotation aa = anns[i];
4612  569 if (aa != null && aa.hasScore() && aa.sequenceRef != null)
4613    {
4614  152 scoreSorts.add(aa.label);
4615    }
4616    }
4617    }
4618  495 for (String label : scoreSorts)
4619    {
4620  4 addSortByAnnotScoreMenuItem(sortByAnnotScore, label);
4621    }
4622  495 sortByAnnotScore.setVisible(!scoreSorts.isEmpty());
4623   
4624  495 _annotationScoreVectorHash = viewport.getAlignment()
4625    .getAlignmentAnnotation().hashCode();
4626    }
4627   
4628    /**
4629    * Enable (or, if desired, make visible) the By Tree submenu only if it has at
4630    * least one element (or will have).
4631    *
4632    */
 
4633  0 toggle @Override
4634    protected void enableSortMenuOptions()
4635    {
4636  0 List<TreePanel> treePanels = getAllTreePanels();
4637  0 sortByTreeMenu.setEnabled(!treePanels.isEmpty());
4638    }
4639   
4640    /**
4641    * Maintain the Order by->Displayed Tree menu. Creates a new menu item for a
4642    * TreePanel with an appropriate <code>jalview.analysis.AlignmentSorter</code>
4643    * call. Listeners are added to remove the menu item when the treePanel is
4644    * closed, and adjust the tree leaf to sequence mapping when the alignment is
4645    * modified.
4646    */
 
4647  0 toggle @Override
4648    public void buildTreeSortMenu()
4649    {
4650  0 sortByTreeMenu.removeAll();
4651   
4652  0 List<TreePanel> treePanels = getAllTreePanels();
4653   
4654  0 if (treePanels.size() < 1)
4655    {
4656  0 sortByTreeMenu.setVisible(false);
4657  0 return;
4658    }
4659   
4660  0 sortByTreeMenu.setVisible(true);
4661   
4662  0 for (final TreePanel tp : treePanels)
4663    {
4664  0 final JMenuItem item = new JMenuItem(tp.getTitle());
4665  0 item.addActionListener(new java.awt.event.ActionListener()
4666    {
 
4667  0 toggle @Override
4668    public void actionPerformed(ActionEvent e)
4669    {
4670  0 tp.sortByTree_actionPerformed();
4671  0 addHistoryItem(tp.sortAlignmentIn(alignPanel));
4672   
4673    }
4674    });
4675   
4676  0 sortByTreeMenu.add(item);
4677    }
4678    }
4679   
 
4680  0 toggle @Override
4681    public void buildSortAnnotationByTreeMenu()
4682    {
4683  0 sortAnnotationByTreeMenu.removeAll();
4684   
4685  0 List<TreePanel> annotTreePanels = getAnnotTreePanels();
4686   
4687  0 if (annotTreePanels.size() < 1)
4688    {
4689  0 sortAnnotationByTreeMenu.setVisible(false);
4690  0 return;
4691    }
4692   
4693  0 sortAnnotationByTreeMenu.setVisible(true);
4694   
4695  0 for (final TreePanel tp : annotTreePanels)
4696    {
4697  0 final JMenuItem item = new JMenuItem(tp.getTitle());
4698  0 item.addActionListener(new java.awt.event.ActionListener()
4699    {
 
4700  0 toggle @Override
4701    public void actionPerformed(ActionEvent e)
4702    {
4703  0 sortAnnByLabel.setSelected(false);
4704  0 sortAnnBySequence.setSelected(false);
4705  0 setAnnotationSortOrder(SequenceAnnotationOrder.NONE);
4706  0 tp.sortAnnotationByTree_actionPerformed();
4707    }
4708    });
4709   
4710  0 sortAnnotationByTreeMenu.add(item);
4711    }
4712    }
4713   
4714    /**
4715    *
4716    * @param seqtree
4717    * when false - trees with leaves only associated with sequences are
4718    * ignored
4719    * @param anntree
4720    * when false - trees with leaves associated with annotations are
4721    * ignored
4722    * @return possibly empty list
4723    */
 
4724  0 toggle private List<TreePanel> getTreePanels(boolean seqtree, boolean anntree)
4725    {
4726  0 List<Component> comps = PaintRefresher.components
4727    .get(viewport.getSequenceSetId());
4728  0 List<TreePanel> treePanels = new ArrayList<>();
4729  0 for (Component comp : comps)
4730    {
4731  0 if (comp instanceof TreePanel)
4732    {
4733    // include according to type of tree and flags
4734  0 if ((((TreePanel) comp).isAnnotationBased()) ? anntree : seqtree)
4735    {
4736  0 treePanels.add((TreePanel) comp);
4737    }
4738    }
4739    }
4740  0 return treePanels;
4741    }
4742   
 
4743  0 toggle private List<TreePanel> getSequenceOnlyTreePanels()
4744    {
4745  0 return getTreePanels(true, false);
4746    }
4747   
 
4748  0 toggle private List<TreePanel> getAllTreePanels()
4749    {
4750  0 return getTreePanels(true, true);
4751    }
4752   
 
4753  0 toggle private List<TreePanel> getAnnotTreePanels()
4754    {
4755  0 return getTreePanels(false, true);
4756    }
4757   
 
4758  0 toggle public boolean sortBy(AlignmentOrder alorder, String undoname)
4759    {
4760  0 SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
4761  0 AlignmentSorter.sortBy(viewport.getAlignment(), alorder);
4762  0 if (undoname != null)
4763    {
4764  0 addHistoryItem(new OrderCommand(undoname, oldOrder,
4765    viewport.getAlignment()));
4766    }
4767  0 alignPanel.paintAlignment(true, false);
4768  0 return true;
4769    }
4770   
4771    /**
4772    * Work out whether the whole set of sequences or just the selected set will
4773    * be submitted for multiple alignment.
4774    *
4775    */
 
4776  0 toggle public jalview.datamodel.AlignmentView gatherSequencesForAlignment()
4777    {
4778    // Now, check we have enough sequences
4779  0 AlignmentView msa = null;
4780   
4781  0 if ((viewport.getSelectionGroup() != null)
4782    && (viewport.getSelectionGroup().getSize() > 1))
4783    {
4784    // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to
4785    // some common interface!
4786    /*
4787    * SequenceGroup seqs = viewport.getSelectionGroup(); int sz; msa = new
4788    * SequenceI[sz = seqs.getSize(false)];
4789    *
4790    * for (int i = 0; i < sz; i++) { msa[i] = (SequenceI) seqs.getSequenceAt(i); }
4791    */
4792  0 msa = viewport.getAlignmentView(true);
4793    }
4794  0 else if (viewport.getSelectionGroup() != null
4795    && viewport.getSelectionGroup().getSize() == 1)
4796    {
4797  0 int option = JvOptionPane.showConfirmDialog(this,
4798    MessageManager.getString("warn.oneseq_msainput_selection"),
4799    MessageManager.getString("label.invalid_selection"),
4800    JvOptionPane.OK_CANCEL_OPTION);
4801  0 if (option == JvOptionPane.OK_OPTION)
4802    {
4803  0 msa = viewport.getAlignmentView(false);
4804    }
4805    }
4806    else
4807    {
4808  0 msa = viewport.getAlignmentView(false);
4809    }
4810  0 return msa;
4811    }
4812   
4813    /**
4814    * Decides what is submitted to a secondary structure prediction service: the
4815    * first sequence in the alignment, or in the current selection, or, if the
4816    * alignment is 'aligned' (ie padded with gaps), then the currently selected
4817    * region or the whole alignment. (where the first sequence in the set is the
4818    * one that the prediction will be for).
4819    */
 
4820  0 toggle public AlignmentView gatherSeqOrMsaForSecStrPrediction()
4821    {
4822  0 AlignmentView seqs = null;
4823   
4824  0 if ((viewport.getSelectionGroup() != null)
4825    && (viewport.getSelectionGroup().getSize() > 0))
4826    {
4827  0 seqs = viewport.getAlignmentView(true);
4828    }
4829    else
4830    {
4831  0 seqs = viewport.getAlignmentView(false);
4832    }
4833    // limit sequences - JBPNote in future - could spawn multiple prediction
4834    // jobs
4835    // TODO: viewport.getAlignment().isAligned is a global state - the local
4836    // selection may well be aligned - we preserve 2.0.8 behaviour for moment.
4837  0 if (!viewport.getAlignment().isAligned(false))
4838    {
4839  0 seqs.setSequences(new SeqCigar[] { seqs.getSequences()[0] });
4840    // TODO: if seqs.getSequences().length>1 then should really have warned
4841    // user!
4842   
4843    }
4844  0 return seqs;
4845    }
4846   
4847    //// ***************************************************
4848    //// TODO REFACTOR TREE I/O TO CONTROLLER/SEPARATE CLASS
4849    //// ***************************************************
4850   
4851    /**
4852    * DOCUMENT ME!
4853    *
4854    * @param e
4855    * DOCUMENT ME!
4856    */
 
4857  0 toggle @Override
4858    protected void loadTreeMenuItem_actionPerformed(ActionEvent e)
4859    {
4860    // Pick the tree file
4861  0 JalviewFileChooser chooser = new JalviewFileChooser(
4862    Cache.getProperty("LAST_DIRECTORY"));
4863  0 chooser.setFileView(new JalviewFileView());
4864  0 chooser.setDialogTitle(
4865    MessageManager.getString("label.select_newick_like_tree_file"));
4866  0 chooser.setToolTipText(
4867    MessageManager.getString("label.load_tree_file"));
4868   
4869  0 chooser.setResponseHandler(0, () -> {
4870  0 String filePath = chooser.getSelectedFile().getPath();
4871  0 Cache.setProperty("LAST_DIRECTORY", filePath);
4872  0 NewickFile fin = null;
4873  0 try
4874    {
4875  0 fin = new NewickFile(new FileParse(chooser.getSelectedFile(),
4876    DataSourceType.FILE));
4877  0 viewport.setCurrentTree(showNewickTree(fin, filePath).getTree());
4878    } catch (Exception ex)
4879    {
4880  0 JvOptionPane.showMessageDialog(Desktop.getDesktopPane(),
4881    ex.getMessage(),
4882    MessageManager.getString("label.problem_reading_tree_file"),
4883    JvOptionPane.WARNING_MESSAGE);
4884  0 ex.printStackTrace();
4885    }
4886  0 if (fin != null && fin.hasWarningMessage())
4887    {
4888  0 JvOptionPane.showMessageDialog(Desktop.getDesktopPane(),
4889    fin.getWarningMessage(),
4890    MessageManager
4891    .getString("label.possible_problem_with_tree_file"),
4892    JvOptionPane.WARNING_MESSAGE);
4893    }
4894    });
4895  0 chooser.showOpenDialog(this);
4896    }
4897   
 
4898  2 toggle public TreePanel showNewickTree(NewickFile nf, String treeTitle)
4899    {
4900  2 return showNewickTree(nf, treeTitle, 600, 500, 4, 5);
4901    }
4902   
 
4903  12 toggle public TreePanel showNewickTree(NewickFile nf, String treeTitle, int w,
4904    int h, int x, int y)
4905    {
4906  12 return showNewickTree(nf, treeTitle, null, w, h, x, y);
4907    }
4908   
4909    /**
4910    * Add a treeviewer for the tree extracted from a Newick file object to the
4911    * current alignment view
4912    *
4913    * @param nf
4914    * the tree
4915    * @param title
4916    * tree viewer title
4917    * @param input
4918    * Associated alignment input data (or null)
4919    * @param w
4920    * width
4921    * @param h
4922    * height
4923    * @param x
4924    * position
4925    * @param y
4926    * position
4927    * @return TreePanel handle
4928    */
 
4929  12 toggle public TreePanel showNewickTree(NewickFile nf, String treeTitle,
4930    AlignmentView input, int w, int h, int x, int y)
4931    {
4932  12 TreePanel tp = null;
4933   
4934  12 try
4935    {
4936  12 nf.parse();
4937   
4938  12 if (nf.getTree() != null)
4939    {
4940  12 tp = new TreePanel(alignPanel, nf, treeTitle, input);
4941   
4942  12 layoutTreePanel(tp, treeTitle, w, h, x, y);
4943    }
4944    } catch (Exception ex)
4945    {
4946  0 ex.printStackTrace();
4947    }
4948   
4949  12 return tp;
4950    }
4951   
4952    /**
4953    * called by Jalview2XML only just now - import a tree that should be resolved
4954    * against annotations.
4955    *
4956    * @param nf
4957    * @param annotationIds
4958    * @param treeTitle
4959    * @param input
4960    * @param w
4961    * @param h
4962    * @param x
4963    * @param y
4964    * @return
4965    */
 
4966  3 toggle public TreePanel showNewickTreeForAnnotation(NewickFile nf,
4967    Map<String, AlignmentAnnotation> annotationIds, String treeTitle,
4968    AlignmentView input, int w, int h, int x, int y)
4969    {
4970  3 TreePanel tp = null;
4971   
4972  3 try
4973    {
4974  3 nf.parse();
4975   
4976  3 if (nf.getTree() != null)
4977    {
4978  3 tp = TreePanel.newTreeForAnnotations(alignPanel, nf, annotationIds,
4979    treeTitle, input);
4980   
4981  3 layoutTreePanel(tp, treeTitle, w, h, x, y);
4982    }
4983    } catch (Exception ex)
4984    {
4985  0 ex.printStackTrace();
4986    }
4987   
4988  3 return tp;
4989    }
4990   
4991    /**
4992    * Applies layout configuration to a TreePanel and add it to the desktop.
4993    *
4994    * @param treePanel
4995    * the TreePanel to configure and display
4996    * @param title
4997    * the title of the tree panel
4998    * @param width
4999    * the width of the tree panel
5000    * @param height
5001    * the height of the tree panel
5002    * @param x
5003    * the x-coordinate of the panel
5004    * @param y
5005    * the y-coordinate of the panel
5006    */
 
5007  15 toggle public static void layoutTreePanel(TreePanel tp, String title, int w,
5008    int h, int x, int y)
5009    {
5010    // TODO JAL-4107 - verify restore of w/h for all tree panels vs embedded
5011    // restore
5012  15 Dimension dim = Platform.getDimIfEmbedded(tp, w, h); // in 2.12 was -1, -1);
5013  15 if (dim == null)
5014    {
5015  0 dim = new Dimension(w, h);
5016    }
5017    else
5018    {
5019    // no offset, either
5020  15 x = 0;
5021    }
5022  15 tp.setSize(dim.width, dim.height);
5023  15 if (x > 0 && y > 0)
5024    {
5025  0 tp.setLocation(x, y);
5026    }
5027  15 Desktop.addInternalFrame(tp, title, dim.width, dim.height);
5028    }
5029   
 
5030  0 toggle public void showContactMapTree(AlignmentAnnotation aa, ContactMatrixI cm)
5031    {
5032  0 int x = 4, y = 5;
5033  0 int w = 400, h = 500;
5034   
5035  0 try
5036    {
5037  0 NewickFile fin = new NewickFile(
5038    new FileParse(cm.getNewick(), DataSourceType.PASTE));
5039  0 String title = aa.label + " " + cm.getTreeMethod() + " tree"
5040  0 + (aa.sequenceRef != null
5041    ? (" for " + aa.sequenceRef.getDisplayId(false))
5042    : "");
5043   
5044  0 showColumnWiseTree(fin, aa, title, w, h, x, y);
5045    } catch (Throwable xx)
5046    {
5047  0 Console.error("Unexpected exception showing tree for contact matrix",
5048    xx);
5049    }
5050    }
5051   
 
5052  0 toggle public TreePanel showColumnWiseTree(NewickFile nf, AlignmentAnnotation aa,
5053    String treeTitle, int w, int h, int x, int y)
5054    {
5055  0 try
5056    {
5057  0 nf.parse();
5058  0 if (nf.getTree() == null)
5059    {
5060  0 return null;
5061    }
5062  0 TreePanel tp = new TreePanel(alignPanel, nf, aa, treeTitle);
5063   
5064  0 tp.setSize(w, h);
5065   
5066  0 if (x > 0 && y > 0)
5067    {
5068  0 tp.setLocation(x, y);
5069    }
5070    // TODO: JAL-4107 - decide if columnwise trees should always float or
5071    // support being embedded ?
5072  0 tp.setLayer(JLayeredPane.PALETTE_LAYER);
5073   
5074  0 Desktop.addInternalFrame(tp, treeTitle, w, h);
5075  0 return tp;
5076    } catch (Throwable xx)
5077    {
5078  0 Console.error("Unexpected exception showing tree for contact matrix",
5079    xx);
5080    }
5081  0 return null;
5082    }
5083    //// ***************************************************
5084    //// TODO REFACTOR TREE I/O TO CONTROLLER/SEPARATE CLASS - END OF METHODS
5085    //// ***************************************************
5086   
5087    private WebServicesMenuManager slivkaMenu = new WebServicesMenuManager(
5088    "slivka", AlignFrame.this);
5089   
5090    private WebServicesMenuManager ebiMenu = new WebServicesMenuManager(
5091    "job dispatcher", AlignFrame.this);
5092   
5093    private WebServicesMenuManager jpred4Menu = new WebServicesMenuManager(
5094    "jpred4", AlignFrame.this);
5095   
5096    /**
5097    * Schedule the web services menu rebuild to the event dispatch thread.
5098    */
 
5099  8233 toggle public void buildWebServicesMenu()
5100    {
5101  8233 SwingUtilities.invokeLater(() -> {
5102  8229 Console.info("Rebuiling WS menu");
5103  8229 webService.removeAll();
5104  8229 if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true))
5105    {
5106  8229 Console.info("Building web service menu for slivka");
5107  8229 SlivkaWSDiscoverer discoverer = SlivkaWSDiscoverer.getInstance();
5108  8229 slivkaMenu.setServices(discoverer);
5109  8229 slivkaMenu.setInProgress(discoverer.isRunning());
5110  8229 slivkaMenu.setNoServices(
5111    discoverer.isDone() && !discoverer.hasServices());
5112  8229 webService.add(slivkaMenu.getMenu());
5113    }
5114  8229 if (Cache.getDefault("SHOW_EBI_SERVICES", true))
5115    {
5116  8229 Console.info("Building web services menu for jobs dispatcher");
5117  8229 JobDispatcherWSDiscoverer discoverer = JobDispatcherWSDiscoverer
5118    .getInstance();
5119  8229 ebiMenu.setServices(discoverer);
5120  8229 ebiMenu.setInProgress(discoverer.isRunning());
5121  8229 ebiMenu.setNoServices(
5122    discoverer.isDone() && !discoverer.hasServices());
5123  8229 webService.add(ebiMenu.getMenu());
5124    }
5125  8229 if (Cache.getDefault("SHOW_JPRED4_SERVICES", true))
5126    {
5127  8229 Console.info("Building web services menu for jpred4");
5128  8229 JPred4WSDiscoverer discoverer = JPred4WSDiscoverer.getInstance();
5129  8229 jpred4Menu.setServices(discoverer);
5130  8229 jpred4Menu.setInProgress(discoverer.isRunning());
5131  8229 jpred4Menu.setNoServices(
5132    discoverer.isDone() && !discoverer.hasServices());
5133  8229 webService.add(jpred4Menu.getMenu());
5134    }
5135  8229 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
5136    {
5137  8229 WSDiscovererI jws2servs = Jws2Discoverer.getInstance();
5138  8229 JMenu submenu = new JMenu("JABAWS");
5139  8229 buildLegacyWebServicesMenu(submenu);
5140  8229 buildWebServicesMenu(jws2servs, submenu);
5141  8229 webService.add(submenu);
5142    }
5143  8229 build_urlServiceMenu(webService);
5144  8229 build_fetchdbmenu(webService);
5145    });
5146    }
5147   
 
5148  8229 toggle private void buildLegacyWebServicesMenu(JMenu menu)
5149    {
5150  8229 JMenu secstrmenu = new JMenu("Secondary Structure Prediction");
5151  8229 if (Discoverer.getServices() != null
5152    && Discoverer.getServices().size() > 0)
5153    {
5154  8209 var secstrpred = Discoverer.getServices().get("SecStrPred");
5155  8209 if (secstrpred != null)
5156    {
5157  8209 for (ext.vamsas.ServiceHandle sh : secstrpred)
5158    {
5159  8280 var menuProvider = Discoverer.getServiceClient(sh);
5160  8280 menuProvider.attachWSMenuEntry(secstrmenu, this);
5161    }
5162    }
5163    }
5164  8229 menu.add(secstrmenu);
5165    }
5166   
5167    /**
5168    * Constructs the web services menu for the given discoverer under the
5169    * specified menu. This method must be called on the EDT
5170    *
5171    * @param discoverer
5172    * the discoverer used to build the menu
5173    * @param menu
5174    * parent component which the elements will be attached to
5175    */
 
5176  8229 toggle private void buildWebServicesMenu(WSDiscovererI discoverer, JMenu menu)
5177    {
5178  8229 if (discoverer.hasServices())
5179    {
5180  2691 PreferredServiceRegistry.getRegistry().populateWSMenuEntry(
5181    discoverer.getServices(), sv -> buildWebServicesMenu(), menu,
5182    this, null);
5183    }
5184  8229 if (discoverer.isRunning())
5185    {
5186  3446 JMenuItem item = new JMenuItem("Service discovery in progress.");
5187  3446 item.setEnabled(false);
5188  3446 menu.add(item);
5189    }
5190  4783 else if (!discoverer.hasServices())
5191    {
5192  2097 JMenuItem item = new JMenuItem("No services available.");
5193  2097 item.setEnabled(false);
5194  2097 menu.add(item);
5195    }
5196    }
5197   
5198    /**
5199    * construct any groupURL type service menu entries.
5200    *
5201    * @param webService
5202    */
 
5203  8229 toggle protected void build_urlServiceMenu(JMenu webService)
5204    {
5205    // TODO: remove this code when 2.7 is released
5206    // DEBUG - alignmentView
5207    /*
5208    * JMenuItem testAlView = new JMenuItem("Test AlignmentView"); final AlignFrame
5209    * af = this; testAlView.addActionListener(new ActionListener() {
5210    *
5211    * public void actionPerformed(ActionEvent e) {
5212    * jalview.datamodel.AlignmentView
5213    * .testSelectionViews(af.viewport.getAlignment(),
5214    * af.viewport.getColumnSelection(), af.viewport.selectionGroup); }
5215    *
5216    * }); webService.add(testAlView);
5217    */
5218    // TODO: refactor to RestClient discoverer and merge menu entries for
5219    // rest-style services with other types of analysis/calculation service
5220    // SHmmr test client - still being implemented.
5221    // DEBUG - alignmentView
5222   
5223  8229 for (jalview.ws.rest.RestClient client : jalview.ws.rest.RestClient
5224    .getRestClients())
5225    {
5226  8229 client.attachWSMenuEntry(
5227    JvSwingUtils.findOrCreateMenu(webService, client.getAction()),
5228    this);
5229    }
5230    }
5231   
5232    /**
5233    * Searches the alignment sequences for xRefs and builds the Show
5234    * Cross-References menu (formerly called Show Products), with database
5235    * sources for which cross-references are found (protein sources for a
5236    * nucleotide alignment and vice versa)
5237    *
5238    * @return true if Show Cross-references menu should be enabled
5239    */
 
5240  729 toggle public boolean canShowProducts()
5241    {
5242  729 SequenceI[] seqs = viewport.getAlignment().getSequencesArray();
5243  729 AlignmentI dataset = viewport.getAlignment().getDataset();
5244   
5245  729 showProducts.removeAll();
5246  729 final boolean dna = viewport.getAlignment().isNucleotide();
5247   
5248  729 if (seqs == null || seqs.length == 0)
5249    {
5250    // nothing to see here.
5251  0 return false;
5252    }
5253   
5254  729 boolean showp = false;
5255  729 try
5256    {
5257  729 List<String> ptypes = new CrossRef(seqs, dataset)
5258    .findXrefSourcesForSequences(dna);
5259   
5260  729 for (final String source : ptypes)
5261    {
5262  19 showp = true;
5263  19 final AlignFrame af = this;
5264  19 JMenuItem xtype = new JMenuItem(source);
5265  19 xtype.addActionListener(new ActionListener()
5266    {
 
5267  0 toggle @Override
5268    public void actionPerformed(ActionEvent e)
5269    {
5270  0 showProductsFor(af.viewport.getSequenceSelection(), dna,
5271    source);
5272    }
5273    });
5274  19 showProducts.add(xtype);
5275    }
5276  729 showProducts.setVisible(showp);
5277  729 showProducts.setEnabled(showp);
5278    } catch (Exception e)
5279    {
5280  0 Console.warn(
5281    "canShowProducts threw an exception - please report to help@jalview.org",
5282    e);
5283  0 return false;
5284    }
5285  729 return showp;
5286    }
5287   
5288    /**
5289    * Finds and displays cross-references for the selected sequences (protein
5290    * products for nucleotide sequences, dna coding sequences for peptides).
5291    *
5292    * @param sel
5293    * the sequences to show cross-references for
5294    * @param dna
5295    * true if from a nucleotide alignment (so showing proteins)
5296    * @param source
5297    * the database to show cross-references for
5298    */
 
5299  0 toggle protected void showProductsFor(final SequenceI[] sel, final boolean _odna,
5300    final String source)
5301    {
5302  0 new Thread(CrossRefAction.getHandlerFor(sel, _odna, source, this))
5303    .start();
5304    }
5305   
5306    /**
5307    * Construct and display a new frame containing the translation of this
5308    * frame's DNA sequences to their aligned protein (amino acid) equivalents.
5309    */
 
5310  1 toggle @Override
5311    public void showTranslation_actionPerformed(GeneticCodeI codeTable)
5312    {
5313  1 AlignmentI al = null;
5314  1 try
5315    {
5316  1 Dna dna = new Dna(viewport, viewport.getViewAsVisibleContigs(true));
5317   
5318  1 al = dna.translateCdna(codeTable);
5319    } catch (Exception ex)
5320    {
5321  0 Console.error("Exception during translation. Please report this !",
5322    ex);
5323  0 final String msg = MessageManager.getString(
5324    "label.error_when_translating_sequences_submit_bug_report");
5325  0 final String errorTitle = MessageManager
5326    .getString("label.implementation_error")
5327    + MessageManager.getString("label.translation_failed");
5328  0 JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), msg,
5329    errorTitle, JvOptionPane.ERROR_MESSAGE);
5330  0 return;
5331    }
5332  1 if (al == null || al.getHeight() == 0)
5333    {
5334  0 final String msg = MessageManager.getString(
5335    "label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation");
5336  0 final String errorTitle = MessageManager
5337    .getString("label.translation_failed");
5338  0 JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), msg,
5339    errorTitle, JvOptionPane.WARNING_MESSAGE);
5340    }
5341    else
5342    {
5343  1 AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
5344  1 af.setFileFormat(this.currentFileFormat);
5345  1 final String newTitle = MessageManager
5346    .formatMessage("label.translation_of_params", new Object[]
5347    { this.getTitle(), codeTable.getId() });
5348  1 af.setTitle(newTitle);
5349  1 if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
5350    {
5351  1 final SequenceI[] seqs = viewport.getSelectionAsNewSequence();
5352  1 AlignViewport.openSplitFrame(this, af, new Alignment(seqs));
5353    }
5354    else
5355    {
5356  0 Desktop.addInternalFrame(af, newTitle, DEFAULT_WIDTH,
5357    DEFAULT_HEIGHT);
5358    }
5359    }
5360    }
5361   
5362    /**
5363    * Set the file format
5364    *
5365    * @param format
5366    */
 
5367  342 toggle public void setFileFormat(FileFormatI format)
5368    {
5369  342 this.currentFileFormat = format;
5370    }
5371   
5372    /**
5373    * Try to load a features file onto the alignment.
5374    *
5375    * @param file
5376    * contents or path to retrieve file or a File object
5377    * @param sourceType
5378    * access mode of file (see jalview.io.AlignFile)
5379    * @return true if features file was parsed correctly.
5380    */
 
5381  4 toggle public boolean parseFeaturesFile(Object file, DataSourceType sourceType)
5382    {
5383    // BH 2018
5384  4 return avc.parseFeaturesFile(file, sourceType,
5385    Cache.getDefault(Preferences.RELAXEDSEQIDMATCHING, false));
5386   
5387    }
5388   
 
5389  5 toggle @Override
5390    public void refreshFeatureUI(boolean enableIfNecessary)
5391    {
5392    // note - currently this is only still here rather than in the controller
5393    // because of the featureSettings hard reference that is yet to be
5394    // abstracted
5395  5 if (enableIfNecessary)
5396    {
5397  5 viewport.setShowSequenceFeatures(true);
5398  5 showSeqFeatures.setSelected(true);
5399    }
5400   
5401    }
5402   
 
5403  0 toggle @Override
5404    public void dragEnter(DropTargetDragEvent evt)
5405    {
5406    }
5407   
 
5408  0 toggle @Override
5409    public void dragExit(DropTargetEvent evt)
5410    {
5411    }
5412   
 
5413  0 toggle @Override
5414    public void dragOver(DropTargetDragEvent evt)
5415    {
5416    }
5417   
 
5418  0 toggle @Override
5419    public void dropActionChanged(DropTargetDragEvent evt)
5420    {
5421    }
5422   
 
5423  0 toggle @Override
5424    public void drop(DropTargetDropEvent evt)
5425    {
5426    // JAL-1552 - acceptDrop required before getTransferable call for
5427    // Java's Transferable for native dnd
5428  0 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
5429  0 Transferable t = evt.getTransferable();
5430   
5431  0 final List<Object> files = new ArrayList<>();
5432  0 List<DataSourceType> protocols = new ArrayList<>();
5433   
5434  0 try
5435    {
5436  0 Desktop.transferFromDropTarget(files, protocols, evt, t);
5437  0 if (files.size() > 0)
5438    {
5439  0 new Thread(new Runnable()
5440    {
5441   
 
5442  0 toggle @Override
5443    public void run()
5444    {
5445  0 loadDroppedFiles(files, protocols, evt, t);
5446    }
5447    }).start();
5448    }
5449    } catch (Exception e)
5450    {
5451  0 e.printStackTrace();
5452    }
5453    }
5454   
 
5455  0 toggle protected void loadDroppedFiles(List<Object> files,
5456    List<DataSourceType> protocols, DropTargetDropEvent evt,
5457    Transferable t)
5458    {
5459  0 try
5460    {
5461    // check to see if any of these files have names matching sequences
5462    // in
5463    // the alignment
5464  0 SequenceIdMatcher idm = new SequenceIdMatcher(
5465    viewport.getAlignment().getSequencesArray());
5466    /**
5467    * Object[] { String,SequenceI}
5468    */
5469  0 ArrayList<Object[]> filesmatched = new ArrayList<>();
5470  0 ArrayList<Object[]> filesnotmatched = new ArrayList<>();
5471  0 for (int i = 0; i < files.size(); i++)
5472    {
5473    // BH 2018
5474  0 Object fileObj = files.get(i);
5475  0 String fileName = fileObj.toString();
5476  0 String pdbfn = "";
5477  0 DataSourceType protocol = (fileObj instanceof File
5478    ? DataSourceType.FILE
5479    : FormatAdapter.checkProtocol(fileName));
5480  0 if (protocol == DataSourceType.FILE)
5481    {
5482  0 File file;
5483  0 if (fileObj instanceof File)
5484    {
5485  0 file = (File) fileObj;
5486  0 Platform.cacheFileData(file);
5487    }
5488    else
5489    {
5490  0 file = new File(fileName);
5491    }
5492  0 pdbfn = file.getName();
5493    }
5494  0 else if (protocol == DataSourceType.URL)
5495    {
5496  0 URL url = new URL(fileName);
5497  0 pdbfn = url.getFile();
5498    }
5499  0 if (pdbfn.length() > 0)
5500    {
5501    // attempt to find a match in the alignment
5502  0 SequenceI[] mtch = idm.findAllIdMatches(pdbfn);
5503  0 int l = 0, c = pdbfn.indexOf(".");
5504  0 while (mtch == null && c != -1)
5505    {
5506  0 do
5507    {
5508  0 l = c;
5509  ? } while ((c = pdbfn.indexOf(".", l)) > l);
5510  0 if (l > -1)
5511    {
5512  0 pdbfn = pdbfn.substring(0, l);
5513    }
5514  0 mtch = idm.findAllIdMatches(pdbfn);
5515    }
5516  0 FileFormatI type;
5517  0 if (mtch != null)
5518    {
5519  0 try
5520    {
5521  0 type = new IdentifyFile().identify(fileObj, protocol);
5522    } catch (Exception ex)
5523    {
5524  0 type = null;
5525    }
5526  0 if (type != null && type.isStructureFile())
5527    {
5528    // TODO: JAL-4107 Check behaviour of dropped files for structures
5529    // in 2.11.5 - looks like a bug for unmatched structures
5530    // Fixed below
5531  0 filesmatched
5532    .add(new Object[]
5533    { fileObj, protocol, mtch, type });
5534  0 continue;
5535    }
5536    }
5537    // File wasn't named like one of the sequences or wasn't a PDB
5538    // file.
5539  0 filesnotmatched.add(new Object[] { fileObj, protocol, mtch });
5540    }
5541    }
5542  0 int assocfiles = 0;
5543  0 if (filesmatched.size() > 0)
5544    {
5545  0 boolean autoAssociate = Cache
5546    .getDefault(Preferences.AUTOASSOCIATE_PDBANDSEQS, false);
5547  0 if (!autoAssociate)
5548    {
5549  0 String msg = MessageManager.formatMessage(
5550    "label.automatically_associate_structure_files_with_sequences_same_name",
5551    new Object[]
5552    { Integer.valueOf(filesmatched.size()).toString() });
5553  0 String ttl = MessageManager.getString(
5554    "label.automatically_associate_structure_files_by_name");
5555  0 int choice = JvOptionPane.showConfirmDialog(this, msg, ttl,
5556    JvOptionPane.YES_NO_OPTION);
5557  0 autoAssociate = choice == JvOptionPane.YES_OPTION;
5558    }
5559  0 if (autoAssociate)
5560    {
5561  0 for (Object[] fm : filesmatched)
5562    {
5563    // try and associate
5564    // TODO: may want to set a standard ID naming formalism for
5565    // associating PDB files which have no IDs.
5566  0 for (SequenceI toassoc : (SequenceI[]) fm[2])
5567    {
5568  0 PDBEntry pe = AssociatePdbFileWithSeq.associatePdbWithSeq(
5569    fm[0].toString(), (DataSourceType) fm[1], toassoc,
5570    false);
5571  0 if (pe != null)
5572    {
5573  0 jalview.bin.Console.errPrintln(
5574    "Associated file : " + (fm[0].toString()) + " with "
5575    + toassoc.getDisplayId(true));
5576  0 assocfiles++;
5577    }
5578   
5579    }
5580    // TODO: do we need to update overview ? only if features are
5581    // shown I guess
5582  0 alignPanel.paintAlignment(true, false);
5583    }
5584    }
5585    else
5586    {
5587    /*
5588    * add declined structures as sequences
5589    */
5590  0 for (Object[] o : filesmatched)
5591    {
5592    // TODO: JAL-4107 2.11.5.0 didn't pass the type (o[3]) to the
5593    // filesnotmatched mechanism... poss doesn't have any effect but
5594    // fixed below.
5595  0 filesnotmatched.add(new Object[] { o[0], o[1], o[3] });
5596    }
5597    }
5598    }
5599  0 if (filesnotmatched.size() > 0)
5600    {
5601  0 if (assocfiles > 0 && (Cache
5602    .getDefault("AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false)
5603    || JvOptionPane.showConfirmDialog(this,
5604    "<html>" + MessageManager.formatMessage(
5605    "label.ignore_unmatched_dropped_files_info",
5606    new Object[]
5607    { Integer.valueOf(filesnotmatched.size())
5608    .toString() })
5609    + "</html>",
5610    MessageManager.getString(
5611    "label.ignore_unmatched_dropped_files"),
5612    JvOptionPane.YES_NO_OPTION) == JvOptionPane.YES_OPTION))
5613    {
5614  0 return;
5615    }
5616  0 for (Object[] fn : filesnotmatched)
5617    {
5618  0 loadJalviewDataFile(fn[0], (DataSourceType) fn[1],
5619    (FileFormatI) fn[2], null);
5620    }
5621    }
5622    } catch (Exception ex)
5623    {
5624  0 ex.printStackTrace();
5625    }
5626    }
5627   
5628    /**
5629    * Attempt to load a "dropped" file or URL string, by testing in turn for
5630    * <ul>
5631    * <li>an Annotation file</li>
5632    * <li>a JNet file</li>
5633    * <li>a features file</li>
5634    * <li>else try to interpret as an alignment file</li>
5635    * </ul>
5636    *
5637    * @param file
5638    * either a filename or a URL string.
5639    * @throws InterruptedException
5640    * @throws IOException
5641    */
 
5642  11 toggle public void loadJalviewDataFile(Object file, DataSourceType sourceType,
5643    FileFormatI format, SequenceI assocSeq)
5644    {
5645    // BH 2018 was String file
5646  11 try
5647    {
5648  11 if (sourceType == null)
5649    {
5650  6 sourceType = FormatAdapter.checkProtocol(file);
5651    }
5652    // if the file isn't identified, or not positively identified as some
5653    // other filetype (PFAM is default unidentified alignment file type) then
5654    // try to parse as annotation.
5655  11 boolean isAnnotation = (format == null
5656    || FileFormat.Pfam.equals(format))
5657    ? new AnnotationFile().annotateAlignmentView(viewport,
5658    file, sourceType)
5659    : false;
5660    // The 'true' flag checks for annotations
5661  11 isAnnotation |= new IdentifyFile().identify(file, sourceType,
5662    true) == FileFormat.JalviewAnnotation;
5663  11 ;
5664   
5665  11 if (!isAnnotation)
5666    {
5667    // first see if its a T-COFFEE score file
5668  3 TCoffeeScoreFile tcf = null;
5669  3 try
5670    {
5671  3 tcf = new TCoffeeScoreFile(file, sourceType);
5672  3 if (tcf.isValid())
5673    {
5674  1 if (tcf.annotateAlignment(viewport.getAlignment(), true))
5675    {
5676  1 buildColourMenu();
5677  1 changeColour(
5678    new TCoffeeColourScheme(viewport.getAlignment()));
5679  1 isAnnotation = true;
5680  1 setStatus(MessageManager.getString(
5681    "label.successfully_pasted_tcoffee_scores_to_alignment"));
5682    }
5683    else
5684    {
5685    // some problem - if no warning its probable that the ID matching
5686    // process didn't work
5687  0 JvOptionPane.showMessageDialog(Desktop.getDesktopPane(),
5688  0 tcf.getWarningMessage() == null
5689    ? MessageManager.getString(
5690    "label.check_file_matches_sequence_ids_alignment")
5691    : tcf.getWarningMessage(),
5692    MessageManager.getString(
5693    "label.problem_reading_tcoffee_score_file"),
5694    JvOptionPane.WARNING_MESSAGE);
5695    }
5696    }
5697    else
5698    {
5699  2 tcf = null;
5700    }
5701    } catch (Exception x)
5702    {
5703  0 Console.debug(
5704    "Exception when processing data source as T-COFFEE score file",
5705    x);
5706  0 tcf = null;
5707    }
5708  3 if (tcf == null)
5709    {
5710    // try to see if its a JNet 'concise' style annotation file *before*
5711    // we
5712    // try to parse it as a features file
5713  2 if (format == null)
5714    {
5715  2 format = new IdentifyFile().identify(file, sourceType);
5716    }
5717  2 if (FileFormat.FeatureSettings == format)
5718    {
5719  0 if (featureSettings != null)
5720    {
5721  0 featureSettings.load(file, sourceType);
5722    }
5723    else
5724    {
5725  0 FeatureSettings.loadFeatureSettingsFile(getFeatureRenderer(),
5726    fileObject, sourceType);
5727    }
5728    }
5729  2 else if (FileFormat.ScoreMatrix == format)
5730    {
5731  0 ScoreMatrixFile sm = new ScoreMatrixFile(
5732    new FileParse(file, sourceType));
5733  0 sm.parse();
5734    // todo: i18n this message
5735  0 setStatus(MessageManager.formatMessage(
5736    "label.successfully_loaded_matrix",
5737    sm.getMatrixName()));
5738    }
5739  2 else if (FileFormat.Jnet.equals(format))
5740    {
5741  0 JPredFile predictions = new JPredFile(file, sourceType);
5742  0 new JnetAnnotationMaker();
5743  0 JnetAnnotationMaker.add_annotation(predictions,
5744    viewport.getAlignment(), 0, false);
5745  0 viewport.getAlignment().setupJPredAlignment();
5746  0 isAnnotation = true;
5747    }
5748   
5749    // else if (IdentifyFile.FeaturesFile.equals(format))
5750  2 else if (FileFormat.Features.equals(format))
5751    {
5752  2 if (parseFeaturesFile(file, sourceType))
5753    {
5754  2 SplitFrame splitFrame = (SplitFrame) getSplitViewContainer();
5755  2 if (splitFrame != null)
5756    {
5757  0 splitFrame.repaint();
5758    }
5759    else
5760    {
5761  2 alignPanel.paintAlignment(true, true);
5762    }
5763    }
5764    }
5765    else
5766    {
5767  0 new FileLoader().LoadFile(viewport, file, sourceType, format);
5768    }
5769    }
5770    }
5771  11 if (isAnnotation)
5772    {
5773  9 updateForAnnotations();
5774    }
5775    } catch (Exception ex)
5776    {
5777  0 ex.printStackTrace();
5778    } catch (OutOfMemoryError oom)
5779    {
5780  0 try
5781    {
5782  0 System.gc();
5783    } catch (Exception x)
5784    {
5785    }
5786  0 new OOMWarning(
5787    "loading data "
5788  0 + (sourceType != null
5789  0 ? (sourceType == DataSourceType.PASTE
5790    ? "from clipboard."
5791    : "using " + sourceType + " from "
5792    + file)
5793    : ".")
5794  0 + (format != null
5795    ? "(parsing as '" + format + "' file)"
5796    : ""),
5797    oom, Desktop.getDesktopPane());
5798    }
5799    }
5800   
5801    /**
5802    * Do all updates necessary after an annotation file such as jnet. Also called
5803    * from Jalview.loadAppletParams for "annotations", "jnetFile"
5804    */
5805   
 
5806  9 toggle public void updateForAnnotations()
5807    {
5808  9 alignPanel.adjustAnnotationHeight();
5809  9 viewport.updateSequenceIdColours();
5810  9 viewport.updateAnnotationColours();
5811  9 buildSortByAnnotationScoresMenu();
5812  9 alignPanel.alignmentChanged();
5813  9 viewport.updateSecondaryStructureConsensus(alignPanel);
5814  9 viewport.alignmentChanged(alignPanel);
5815  9 alignPanel.paintAlignment(true, true);
5816    }
5817   
5818    /**
5819    * Change the display state for the given feature groups -- Added by BH from
5820    * JalviewLite
5821    *
5822    * @param groups
5823    * list of group strings
5824    * @param state
5825    * visible or invisible
5826    */
5827   
 
5828  0 toggle public void setFeatureGroupState(String[] groups, boolean state)
5829    {
5830  0 jalview.api.FeatureRenderer fr = null;
5831  0 viewport.setShowSequenceFeatures(true);
5832  0 if (alignPanel != null
5833    && (fr = alignPanel.getFeatureRenderer()) != null)
5834    {
5835   
5836  0 fr.setGroupVisibility(Arrays.asList(groups), state);
5837  0 alignPanel.getSeqPanel().seqCanvas.repaint();
5838  0 if (alignPanel.overviewPanel != null)
5839    {
5840  0 alignPanel.overviewPanel.updateOverviewImage();
5841    }
5842    }
5843    }
5844   
5845    /**
5846    * Method invoked by the ChangeListener on the tabbed pane, in other words
5847    * when a different tabbed pane is selected by the user or programmatically.
5848    */
 
5849  160 toggle @Override
5850    public void tabSelectionChanged(int index)
5851    {
5852  160 if (index > -1)
5853    {
5854    /*
5855    * update current Overview window title (if there is one) to add view name
5856    * "Original" if necessary
5857    */
5858  105 alignPanel.setOverviewTitle(this);
5859   
5860    /*
5861    * switch panels and set Overview title (if there is one because it was opened
5862    * automatically)
5863    */
5864  105 alignPanel = alignPanels.get(index);
5865  105 alignPanel.setOverviewTitle(this);
5866   
5867  105 viewport = alignPanel.av;
5868  105 avc.setViewportAndAlignmentPanel(viewport, alignPanel);
5869  105 setMenusFromViewport(viewport);
5870  105 if (featureSettings != null && featureSettings.isOpen()
5871    && featureSettings.fr.getViewport() != viewport)
5872    {
5873  0 if (viewport.isShowSequenceFeatures())
5874    {
5875    // refresh the featureSettings to reflect UI change
5876  0 showFeatureSettingsUI();
5877    }
5878    else
5879    {
5880    // close feature settings for this view.
5881  0 featureSettings.close();
5882    }
5883    }
5884   
5885    }
5886   
5887    /*
5888    * 'focus' any colour slider that is open to the selected viewport
5889    */
5890  160 if (viewport.getConservationSelected())
5891    {
5892  2 SliderPanel.setConservationSlider(alignPanel,
5893    viewport.getResidueShading(), alignPanel.getViewName());
5894    }
5895    else
5896    {
5897  158 SliderPanel.hideConservationSlider();
5898    }
5899  160 if (viewport.getByConsensusSecondaryStructureSelected())
5900    {
5901  0 SliderPanel.setConsensusSecondaryStructureSlider(alignPanel,
5902    viewport.getResidueShading(), alignPanel.getViewName());
5903    }
5904    else
5905    {
5906  160 SliderPanel.hideConsensusSecondaryStructureSlider();
5907    }
5908  160 if (viewport.getAbovePIDThreshold())
5909    {
5910  2 SliderPanel.setPIDSliderSource(alignPanel,
5911    viewport.getResidueShading(), alignPanel.getViewName());
5912    }
5913    else
5914    {
5915  158 SliderPanel.hidePIDSlider();
5916    }
5917   
5918    /*
5919    * If there is a frame linked to this one in a SplitPane, switch it to the same
5920    * view tab index. No infinite recursion of calls should happen, since
5921    * tabSelectionChanged() should not get invoked on setting the selected index to
5922    * an unchanged value. Guard against setting an invalid index before the new
5923    * view peer tab has been created.
5924    */
5925  160 final AlignViewportI peer = viewport.getCodingComplement();
5926  160 if (peer != null)
5927    {
5928  0 AlignFrame linkedAlignFrame = ((AlignViewport) peer)
5929    .getAlignPanel().alignFrame;
5930  0 if (linkedAlignFrame.tabbedPane.getTabCount() > index)
5931    {
5932  0 linkedAlignFrame.tabbedPane.setSelectedIndex(index);
5933    }
5934    }
5935    }
5936   
5937    /**
5938    * On right mouse click on view tab, prompt for and set new view name.
5939    */
 
5940  0 toggle @Override
5941    public void tabbedPane_mousePressed(MouseEvent e)
5942    {
5943  0 if (e.isPopupTrigger())
5944    {
5945  0 String msg = MessageManager.getString("label.enter_view_name");
5946  0 String ttl = tabbedPane.getTitleAt(tabbedPane.getSelectedIndex());
5947  0 String reply = JvOptionPane.showInputDialog(msg, ttl);
5948   
5949  0 if (reply != null)
5950    {
5951  0 viewport.setViewName(reply);
5952    // TODO warn if reply is in getExistingViewNames()?
5953  0 tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
5954    }
5955    }
5956    }
5957   
 
5958  171 toggle public AlignViewport getCurrentView()
5959    {
5960  171 return viewport;
5961    }
5962   
5963    /**
5964    * Open the dialog for regex description parsing.
5965    */
 
5966  0 toggle @Override
5967    protected void extractScores_actionPerformed(ActionEvent e)
5968    {
5969  0 ParseProperties pp = new jalview.analysis.ParseProperties(
5970    viewport.getAlignment());
5971    // TODO: verify regex and introduce GUI dialog for version 2.5
5972    // if (pp.getScoresFromDescription("col", "score column ",
5973    // "\\W*([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)",
5974    // true)>0)
5975  0 if (pp.getScoresFromDescription("description column",
5976    "score in description column ", "\\W*([-+eE0-9.]+)", true) > 0)
5977    {
5978  0 buildSortByAnnotationScoresMenu();
5979    }
5980    }
5981   
5982    /*
5983    * (non-Javadoc)
5984    *
5985    * @see jalview.jbgui.GAlignFrame#showDbRefs_actionPerformed(java.awt.event.
5986    * ActionEvent )
5987    */
 
5988  0 toggle @Override
5989    protected void showDbRefs_actionPerformed(ActionEvent e)
5990    {
5991  0 viewport.setShowDBRefs(showDbRefsMenuitem.isSelected());
5992    }
5993   
5994    /*
5995    * (non-Javadoc)
5996    *
5997    * @seejalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event.
5998    * ActionEvent)
5999    */
 
6000  0 toggle @Override
6001    protected void showNpFeats_actionPerformed(ActionEvent e)
6002    {
6003  0 viewport.setShowNPFeats(showNpFeatsMenuitem.isSelected());
6004    }
6005   
6006    /**
6007    * find the viewport amongst the tabs in this alignment frame and close that
6008    * tab
6009    *
6010    * @param av
6011    */
 
6012  0 toggle public boolean closeView(AlignViewportI av)
6013    {
6014  0 if (viewport == av)
6015    {
6016  0 this.closeMenuItem_actionPerformed(false);
6017  0 return true;
6018    }
6019  0 Component[] comp = tabbedPane.getComponents();
6020  0 for (int i = 0; comp != null && i < comp.length; i++)
6021    {
6022  0 if (comp[i] instanceof AlignmentPanel)
6023    {
6024  0 if (((AlignmentPanel) comp[i]).av == av)
6025    {
6026    // close the view.
6027  0 closeView((AlignmentPanel) comp[i]);
6028  0 return true;
6029    }
6030    }
6031    }
6032  0 return false;
6033    }
6034   
 
6035  8229 toggle protected void build_fetchdbmenu(JMenu webService)
6036    {
6037    // Temporary hack - DBRef Fetcher always top level ws entry.
6038    // TODO We probably want to store a sequence database checklist in
6039    // preferences and have checkboxes.. rather than individual sources selected
6040    // here
6041  8229 final JMenu rfetch = new JMenu(
6042    MessageManager.getString("action.fetch_db_references"));
6043  8229 rfetch.setToolTipText(MessageManager.getString(
6044    "label.retrieve_parse_sequence_database_records_alignment_or_selected_sequences"));
6045  8229 webService.add(rfetch);
6046   
6047  8229 final JCheckBoxMenuItem trimrs = new JCheckBoxMenuItem(
6048    MessageManager.getString("option.trim_retrieved_seqs"));
6049  8229 trimrs.setToolTipText(
6050    MessageManager.getString("label.trim_retrieved_sequences"));
6051  8229 trimrs.setSelected(
6052    Cache.getDefault(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES, true));
6053  8229 trimrs.addActionListener(new ActionListener()
6054    {
 
6055  0 toggle @Override
6056    public void actionPerformed(ActionEvent e)
6057    {
6058  0 trimrs.setSelected(trimrs.isSelected());
6059  0 Cache.setProperty(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES,
6060    Boolean.valueOf(trimrs.isSelected()).toString());
6061    }
6062    });
6063  8229 rfetch.add(trimrs);
6064  8229 JMenuItem fetchr = new JMenuItem(
6065    MessageManager.getString("label.standard_databases"));
6066  8229 fetchr.setToolTipText(
6067    MessageManager.getString("label.fetch_embl_uniprot"));
6068  8229 fetchr.addActionListener(new ActionListener()
6069    {
6070   
 
6071  0 toggle @Override
6072    public void actionPerformed(ActionEvent e)
6073    {
6074  0 new Thread(new Runnable()
6075    {
 
6076  0 toggle @Override
6077    public void run()
6078    {
6079  0 boolean isNucleotide = alignPanel.alignFrame.getViewport()
6080    .getAlignment().isNucleotide();
6081  0 DBRefFetcher dbRefFetcher = new DBRefFetcher(
6082    alignPanel.av.getSequenceSelection(),
6083    alignPanel.alignFrame, null,
6084    alignPanel.alignFrame.featureSettings, isNucleotide);
6085  0 dbRefFetcher.addListener(new FetchFinishedListenerI()
6086    {
 
6087  0 toggle @Override
6088    public void finished()
6089    {
6090   
6091  0 for (FeatureSettingsModelI srcSettings : dbRefFetcher
6092    .getFeatureSettingsModels())
6093    {
6094   
6095  0 alignPanel.av.mergeFeaturesStyle(srcSettings);
6096    }
6097  0 AlignFrame.this.setMenusForViewport();
6098    }
6099    });
6100  0 dbRefFetcher.fetchDBRefs(false);
6101    }
6102    }).start();
6103   
6104    }
6105   
6106    });
6107  8229 rfetch.add(fetchr);
6108  8229 new Thread(new Runnable()
6109    {
 
6110  8228 toggle @Override
6111    public void run()
6112    {
6113    // ??
6114    // final jalview.ws.SequenceFetcher sf = jalview.gui.SequenceFetcher
6115    // .getSequenceFetcherSingleton();
6116  8228 javax.swing.SwingUtilities.invokeLater(new Runnable()
6117    {
 
6118  8229 toggle @Override
6119    public void run()
6120    {
6121  8229 jalview.ws.SequenceFetcher sf = jalview.ws.SequenceFetcher
6122    .getInstance();
6123  8229 String[] dbclasses = sf.getNonAlignmentSources();
6124  8229 List<DbSourceProxy> otherdb;
6125  8229 JMenu dfetch = new JMenu();
6126  8229 JMenu ifetch = new JMenu();
6127  8229 JMenuItem fetchr = null;
6128  8229 int comp = 0, icomp = 0, mcomp = 15;
6129  8229 String mname = null;
6130  8229 int dbi = 0;
6131  8229 for (String dbclass : dbclasses)
6132    {
6133  41145 otherdb = sf.getSourceProxy(dbclass);
6134    // add a single entry for this class, or submenu allowing 'fetch
6135    // all' or pick one
6136  41145 if (otherdb == null || otherdb.size() < 1)
6137    {
6138  0 continue;
6139    }
6140  41145 if (mname == null)
6141    {
6142  8229 mname = "From " + dbclass;
6143    }
6144  41145 if (otherdb.size() == 1)
6145    {
6146  41145 DbSourceProxy src = otherdb.get(0);
6147  41145 DbSourceProxy[] dassource = new DbSourceProxy[] { src };
6148  41145 fetchr = new JMenuItem(src.getDbSource());
6149  41145 fetchr.addActionListener(new ActionListener()
6150    {
6151   
 
6152  0 toggle @Override
6153    public void actionPerformed(ActionEvent e)
6154    {
6155  0 new Thread(new Runnable()
6156    {
6157   
 
6158  0 toggle @Override
6159    public void run()
6160    {
6161  0 boolean isNucleotide = alignPanel.alignFrame
6162    .getViewport().getAlignment()
6163    .isNucleotide();
6164  0 DBRefFetcher dbRefFetcher = new DBRefFetcher(
6165    alignPanel.av.getSequenceSelection(),
6166    alignPanel.alignFrame, dassource,
6167    alignPanel.alignFrame.featureSettings,
6168    isNucleotide);
6169  0 dbRefFetcher
6170    .addListener(new FetchFinishedListenerI()
6171    {
 
6172  0 toggle @Override
6173    public void finished()
6174    {
6175  0 FeatureSettingsModelI srcSettings = dassource[0]
6176    .getFeatureColourScheme();
6177  0 alignPanel.av.mergeFeaturesStyle(
6178    srcSettings);
6179  0 AlignFrame.this.setMenusForViewport();
6180    }
6181    });
6182  0 dbRefFetcher.fetchDBRefs(false);
6183    }
6184    }).start();
6185    }
6186   
6187    });
6188  41145 fetchr.setToolTipText(JvSwingUtils.wrapTooltip(true,
6189    MessageManager.formatMessage(
6190    "label.fetch_retrieve_from", new Object[]
6191    { src.getDbName() })));
6192  41145 dfetch.add(fetchr);
6193  41145 comp++;
6194    }
6195    else
6196    {
6197  0 final DbSourceProxy[] dassource = otherdb
6198    .toArray(new DbSourceProxy[0]);
6199    // fetch all entry
6200  0 DbSourceProxy src = otherdb.get(0);
6201  0 fetchr = new JMenuItem(MessageManager
6202    .formatMessage("label.fetch_all_param", new Object[]
6203    { src.getDbSource() }));
6204  0 fetchr.addActionListener(new ActionListener()
6205    {
 
6206  0 toggle @Override
6207    public void actionPerformed(ActionEvent e)
6208    {
6209  0 new Thread(new Runnable()
6210    {
6211   
 
6212  0 toggle @Override
6213    public void run()
6214    {
6215  0 boolean isNucleotide = alignPanel.alignFrame
6216    .getViewport().getAlignment()
6217    .isNucleotide();
6218  0 DBRefFetcher dbRefFetcher = new DBRefFetcher(
6219    alignPanel.av.getSequenceSelection(),
6220    alignPanel.alignFrame, dassource,
6221    alignPanel.alignFrame.featureSettings,
6222    isNucleotide);
6223  0 dbRefFetcher
6224    .addListener(new FetchFinishedListenerI()
6225    {
 
6226  0 toggle @Override
6227    public void finished()
6228    {
6229  0 AlignFrame.this.setMenusForViewport();
6230    }
6231    });
6232  0 dbRefFetcher.fetchDBRefs(false);
6233    }
6234    }).start();
6235    }
6236    });
6237   
6238  0 fetchr.setToolTipText(JvSwingUtils.wrapTooltip(true,
6239    MessageManager.formatMessage(
6240    "label.fetch_retrieve_from_all_sources",
6241    new Object[]
6242    { Integer.valueOf(otherdb.size())
6243    .toString(),
6244    src.getDbSource(), src.getDbName() })));
6245  0 dfetch.add(fetchr);
6246  0 comp++;
6247    // and then build the rest of the individual menus
6248  0 ifetch = new JMenu(MessageManager.formatMessage(
6249    "label.source_from_db_source", new Object[]
6250    { src.getDbSource() }));
6251  0 icomp = 0;
6252  0 String imname = null;
6253  0 int i = 0;
6254  0 for (DbSourceProxy sproxy : otherdb)
6255    {
6256  0 String dbname = sproxy.getDbName();
6257  0 String sname = dbname.length() > 5
6258    ? dbname.substring(0, 5) + "..."
6259    : dbname;
6260  0 String msname = dbname.length() > 10
6261    ? dbname.substring(0, 10) + "..."
6262    : dbname;
6263  0 if (imname == null)
6264    {
6265  0 imname = MessageManager
6266    .formatMessage("label.from_msname", new Object[]
6267    { sname });
6268    }
6269  0 fetchr = new JMenuItem(msname);
6270  0 final DbSourceProxy[] dassrc = { sproxy };
6271  0 fetchr.addActionListener(new ActionListener()
6272    {
6273   
 
6274  0 toggle @Override
6275    public void actionPerformed(ActionEvent e)
6276    {
6277  0 new Thread(new Runnable()
6278    {
6279   
 
6280  0 toggle @Override
6281    public void run()
6282    {
6283  0 boolean isNucleotide = alignPanel.alignFrame
6284    .getViewport().getAlignment()
6285    .isNucleotide();
6286  0 DBRefFetcher dbRefFetcher = new DBRefFetcher(
6287    alignPanel.av.getSequenceSelection(),
6288    alignPanel.alignFrame, dassrc,
6289    alignPanel.alignFrame.featureSettings,
6290    isNucleotide);
6291  0 dbRefFetcher
6292    .addListener(new FetchFinishedListenerI()
6293    {
 
6294  0 toggle @Override
6295    public void finished()
6296    {
6297  0 AlignFrame.this.setMenusForViewport();
6298    }
6299    });
6300  0 dbRefFetcher.fetchDBRefs(false);
6301    }
6302    }).start();
6303    }
6304   
6305    });
6306  0 fetchr.setToolTipText(
6307    "<html>" + MessageManager.formatMessage(
6308    "label.fetch_retrieve_from", new Object[]
6309    { dbname }));
6310  0 ifetch.add(fetchr);
6311  0 ++i;
6312  0 if (++icomp >= mcomp || i == (otherdb.size()))
6313    {
6314  0 ifetch.setText(MessageManager.formatMessage(
6315    "label.source_to_target", imname, sname));
6316  0 dfetch.add(ifetch);
6317  0 ifetch = new JMenu();
6318  0 imname = null;
6319  0 icomp = 0;
6320  0 comp++;
6321    }
6322    }
6323    }
6324  41145 ++dbi;
6325  41145 if (comp >= mcomp || dbi >= (dbclasses.length))
6326    {
6327  8229 dfetch.setText(MessageManager.formatMessage(
6328    "label.source_to_target", mname, dbclass));
6329  8229 rfetch.add(dfetch);
6330  8229 dfetch = new JMenu();
6331  8229 mname = null;
6332  8229 comp = 0;
6333    }
6334    }
6335    }
6336   
6337    });
6338    }
6339    }).start();
6340   
6341    }
6342   
6343    /**
6344    * Left justify the whole alignment.
6345    */
 
6346  0 toggle @Override
6347    protected void justifyLeftMenuItem_actionPerformed(ActionEvent e)
6348    {
6349  0 avc.justify_Region(true);
6350    }
6351   
6352    /**
6353    * Right justify the whole alignment.
6354    */
 
6355  0 toggle @Override
6356    protected void justifyRightMenuItem_actionPerformed(ActionEvent e)
6357    {
6358  0 avc.justify_Region(false);
6359    }
6360   
 
6361  16 toggle @Override
6362    public void setShowSeqFeatures(boolean b)
6363    {
6364  16 showSeqFeatures.setSelected(b);
6365  16 viewport.setShowSequenceFeatures(b);
6366    }
6367   
6368    /*
6369    * (non-Javadoc)
6370    *
6371    * @see jalview.jbgui.GAlignFrame#showUnconservedMenuItem_actionPerformed(java.
6372    * awt.event.ActionEvent)
6373    */
 
6374  0 toggle @Override
6375    protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)
6376    {
6377  0 viewport.setShowUnconserved(showNonconservedMenuItem.getState());
6378  0 alignPanel.paintAlignment(false, false);
6379    }
6380   
 
6381  0 toggle @Override
6382    protected void showStructureProvider_actionPerformed(ActionEvent e)
6383    {
6384  0 viewport.setShowStructureProvider(showStrucProvider.getState());
6385  0 alignPanel.paintAlignment(false, false);
6386   
6387    }
6388   
 
6389  0 toggle @Override
6390    protected void updateShowSecondaryStructureMenu(JMenu showSS,
6391    ButtonGroup ssButtonGroup)
6392    {
6393   
6394  0 List<String> ssSources = new ArrayList<String>();
6395  0 AlignmentAnnotation[] anns = alignPanel.getAlignment()
6396    .getAlignmentAnnotation();
6397  0 Map<String, JCheckBoxMenuItem> checkboxMap = getCheckboxesInMenu(
6398    showSS);
6399   
6400  0 ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(anns);
6401   
6402  0 if (ssSources == null)
6403    {
6404  0 showSS.removeAll();
6405  0 ssButtonGroup.clearSelection();
6406  0 return;
6407    }
6408   
6409  0 List<String> selectedCheckBoxes = getSelectedOptions(checkboxMap);
6410   
6411    // Add checkboxes for categories
6412  0 for (String ssSource : ssSources)
6413    {
6414   
6415  0 if (checkboxMap.get(ssSource) == null)
6416    {
6417  0 JCheckBoxMenuItem checkBox = new JCheckBoxMenuItem(ssSource);
6418  0 checkBox.setSelected(false);
6419   
6420  0 checkBox.addItemListener(e -> {
6421  0 if (e.getStateChange() == ItemEvent.SELECTED)
6422    {
6423   
6424  0 showOrHideSecondaryStructureForSource(ssSource, true);
6425   
6426    }
6427    else
6428    {
6429   
6430  0 showOrHideSecondaryStructureForSource(ssSource, false);
6431   
6432    }
6433    });
6434  0 showSS.add(checkBox);
6435    }
6436    }
6437    // Iterate over the keys of checkboxMap
6438  0 for (String key : checkboxMap.keySet())
6439    {
6440    // Check if the key is not in ssSources
6441  0 if (!ssSources.contains(key))
6442    {
6443  0 showSS.remove(checkboxMap.get(key));
6444  0 checkboxMap.remove(key);
6445  0 selectedCheckBoxes.remove(key);
6446    }
6447  0 if (selectedCheckBoxes.contains(key))
6448    {
6449  0 checkboxMap.get(key).setSelected(true);
6450    }
6451    else
6452    {
6453  0 checkboxMap.get(key).setSelected(false);
6454    }
6455   
6456  0 ssButtonGroup.clearSelection();
6457    }
6458   
6459    }
6460   
 
6461  0 toggle private List<String> getSelectedOptions(
6462    Map<String, JCheckBoxMenuItem> checkboxMap)
6463    {
6464  0 List<String> selectedOptions = new ArrayList<>();
6465  0 for (String key : checkboxMap.keySet())
6466    {
6467  0 JCheckBoxMenuItem checkbox = checkboxMap.get(key);
6468  0 if (checkbox.isSelected())
6469    {
6470  0 selectedOptions.add(key);
6471    }
6472    }
6473  0 return selectedOptions;
6474    }
6475   
 
6476  0 toggle private Map<String, JCheckBoxMenuItem> getCheckboxesInMenu(JMenu menu)
6477    {
6478  0 Map<String, JCheckBoxMenuItem> checkboxMap = new HashMap<>();
6479  0 for (Component component : menu.getMenuComponents())
6480    {
6481  0 if (component instanceof JCheckBoxMenuItem)
6482    {
6483  0 JCheckBoxMenuItem checkbox = (JCheckBoxMenuItem) component;
6484  0 checkboxMap.put(checkbox.getText(), checkbox);
6485    }
6486    }
6487  0 return checkboxMap;
6488    }
6489   
 
6490  0 toggle @Override
6491    protected void showOrHideSecondaryStructureForSource(
6492    String ssSourceSelection, boolean visible)
6493    {
6494   
6495  0 String _noneOption = MessageManager
6496    .getString("option.ss_providers_none");
6497  0 boolean nonOption = ssSourceSelection != null
6498    && ssSourceSelection.equals(_noneOption);
6499  0 String allOption = MessageManager.getString("option.ss_providers_all");
6500   
6501  0 AlignmentAnnotation[] annotations = alignPanel.getAlignment()
6502    .getAlignmentAnnotation();
6503   
6504  0 for (AlignmentAnnotation aa : annotations)
6505    {
6506   
6507  0 if (aa.groupRef != null)
6508    {
6509  0 continue;
6510    }
6511   
6512  0 boolean isSSConsensus = aa.label.startsWith(
6513    MessageManager.getString("label.ssconsensus_label"));
6514  0 boolean matchesSSSourceSelection = aa.description
6515    .startsWith(ssSourceSelection);
6516   
6517  0 if (isSSConsensus && (matchesSSSourceSelection || nonOption))
6518    {
6519   
6520  0 if (ssSourceSelection.equals(allOption))
6521    {
6522  0 aa.visible = true;
6523  0 break;
6524    }
6525   
6526  0 if (!aa.description.startsWith(allOption))
6527  0 aa.visible = visible;
6528   
6529    }
6530   
6531  0 for (String label : Constants.SECONDARY_STRUCTURE_LABELS.keySet())
6532    {
6533   
6534  0 if (label.equals(aa.label))
6535    {
6536   
6537  0 String ssSource = AlignmentAnnotationUtils
6538    .extractSSSourceFromAnnotationDescription(aa);
6539   
6540  0 if (nonOption || ssSource != null
6541    && (ssSource.equals(ssSourceSelection)))
6542    {
6543  0 aa.visible = visible;
6544    }
6545    }
6546    }
6547   
6548    }
6549   
6550  0 PaintRefresher.Refresh(this, viewport.getSequenceSetId());
6551  0 alignPanel.updateAnnotation();
6552  0 viewport.updateSecondaryStructureConsensus(alignPanel);
6553  0 alignPanel.paintAlignment(true, true);
6554   
6555    }
6556   
 
6557  0 toggle @Override
6558    protected void showSSConsensus_actionPerformed(ActionEvent e)
6559    {
6560  0 viewport.setShowSSConsensus(showSSConsensus.getState());
6561  0 viewport.updateSecondaryStructureConsensus(alignPanel);
6562  0 alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
6563    }
6564   
6565    /*
6566    * (non-Javadoc)
6567    *
6568    * @see
6569    * jalview.jbgui.GAlignFrame#showGroupConsensus_actionPerformed(java.awt.event
6570    * .ActionEvent)
6571    */
 
6572  0 toggle @Override
6573    protected void showGroupConsensus_actionPerformed(ActionEvent e)
6574    {
6575  0 viewport.setShowGroupConsensus(showGroupConsensus.getState());
6576  0 alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
6577   
6578    }
6579   
 
6580  0 toggle @Override
6581    protected void showGroupSSConsensus_actionPerformed(ActionEvent e)
6582    {
6583  0 viewport.setShowGroupSSConsensus(showGroupSSConsensus.getState());
6584  0 alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
6585   
6586    }
6587   
6588    /*
6589    * (non-Javadoc)
6590    *
6591    * @see jalview.jbgui.GAlignFrame#showGroupConservation_actionPerformed(java.awt
6592    * .event.ActionEvent)
6593    */
 
6594  0 toggle @Override
6595    protected void showGroupConservation_actionPerformed(ActionEvent e)
6596    {
6597  0 viewport.setShowGroupConservation(showGroupConservation.getState());
6598  0 alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
6599    }
6600   
6601    /*
6602    * (non-Javadoc)
6603    *
6604    * @see
6605    * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt
6606    * .event.ActionEvent)
6607    */
 
6608  0 toggle @Override
6609    protected void showConsensusHistogram_actionPerformed(ActionEvent e)
6610    {
6611  0 viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
6612  0 alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
6613    }
6614   
6615    /*
6616    * (non-Javadoc)
6617    *
6618    * @see jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt
6619    * .event.ActionEvent)
6620    */
 
6621  0 toggle @Override
6622    protected void showSequenceLogo_actionPerformed(ActionEvent e)
6623    {
6624  0 viewport.setShowSequenceLogo(showSequenceLogo.getState());
6625  0 alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
6626    }
6627   
 
6628  0 toggle @Override
6629    protected void normaliseSequenceLogo_actionPerformed(ActionEvent e)
6630    {
6631  0 showSequenceLogo.setState(true);
6632  0 viewport.setShowSequenceLogo(true);
6633  0 viewport.setNormaliseSequenceLogo(normaliseSequenceLogo.getState());
6634  0 alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
6635    }
6636   
 
6637  0 toggle @Override
6638    protected void applyAutoAnnotationSettings_actionPerformed(ActionEvent e)
6639    {
6640  0 alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
6641    }
6642   
6643    /*
6644    * (non-Javadoc)
6645    *
6646    * @see jalview.jbgui.GAlignFrame#makeGrpsFromSelection_actionPerformed(java.awt
6647    * .event.ActionEvent)
6648    */
 
6649  0 toggle @Override
6650    protected void makeGrpsFromSelection_actionPerformed(ActionEvent e)
6651    {
6652  0 if (avc.makeGroupsFromSelection())
6653    {
6654  0 PaintRefresher.Refresh(this, viewport.getSequenceSetId());
6655  0 alignPanel.updateAnnotation();
6656  0 alignPanel.paintAlignment(true,
6657    viewport.needToUpdateStructureViews());
6658    }
6659    }
6660   
 
6661  0 toggle public void clearAlignmentSeqRep()
6662    {
6663    // TODO refactor alignmentseqrep to controller
6664  0 if (viewport.getAlignment().hasSeqrep())
6665    {
6666  0 viewport.getAlignment().setSeqrep(null);
6667  0 PaintRefresher.Refresh(this, viewport.getSequenceSetId());
6668  0 alignPanel.updateAnnotation();
6669  0 alignPanel.paintAlignment(true, true);
6670    }
6671    }
6672   
 
6673  0 toggle @Override
6674    protected void createGroup_actionPerformed(ActionEvent e)
6675    {
6676  0 if (avc.createGroup())
6677    {
6678  0 if (applyAutoAnnotationSettings.isSelected())
6679    {
6680  0 alignPanel.updateAnnotation(true, false);
6681    }
6682  0 alignPanel.alignmentChanged();
6683    }
6684    }
6685   
 
6686  0 toggle @Override
6687    protected void unGroup_actionPerformed(ActionEvent e)
6688    {
6689  0 if (avc.unGroup())
6690    {
6691  0 alignPanel.alignmentChanged();
6692    }
6693    }
6694   
6695    /**
6696    * make the given alignmentPanel the currently selected tab
6697    *
6698    * @param alignmentPanel
6699    */
 
6700  0 toggle public void setDisplayedView(AlignmentPanel alignmentPanel)
6701    {
6702  0 if (!viewport.getSequenceSetId()
6703    .equals(alignmentPanel.av.getSequenceSetId()))
6704    {
6705  0 throw new Error(MessageManager.getString(
6706    "error.implementation_error_cannot_show_view_alignment_frame"));
6707    }
6708  0 if (tabbedPane != null && tabbedPane.getTabCount() > 0 && alignPanels
6709    .indexOf(alignmentPanel) != tabbedPane.getSelectedIndex())
6710    {
6711  0 tabbedPane.setSelectedIndex(alignPanels.indexOf(alignmentPanel));
6712    }
6713    }
6714   
6715    /**
6716    * Action on selection of menu options to Show or Hide annotations.
6717    *
6718    * @param visible
6719    * @param forSequences
6720    * update sequence-related annotations
6721    * @param forAlignment
6722    * update non-sequence-related annotations
6723    */
 
6724  298 toggle @Override
6725    public void setAnnotationsVisibility(boolean visible,
6726    boolean forSequences, boolean forAlignment)
6727    {
6728  298 AlignmentAnnotation[] anns = alignPanel.getAlignment()
6729    .getAlignmentAnnotation();
6730  298 if (anns == null)
6731    {
6732  0 return;
6733    }
6734  298 for (AlignmentAnnotation aa : anns)
6735    {
6736    /*
6737    * don't display non-positional annotations on an alignment
6738    */
6739  1138 if (aa.annotations == null)
6740    {
6741  0 continue;
6742    }
6743  1138 boolean apply = (aa.sequenceRef == null && forAlignment)
6744    || (aa.sequenceRef != null && forSequences);
6745  1138 if (apply)
6746    {
6747  569 aa.visible = visible;
6748    }
6749    }
6750  298 alignPanel.updateAnnotation();
6751    // TODO: do we need these additional bits - or merge into above
6752  298 alignPanel.validateAnnotationDimensions(true);
6753    // TODO this triggers relayout of annotation panel - otherwise annotation
6754    // label height is different to panel height
6755  298 alignPanel.fontChanged();
6756  298 alignPanel.alignmentChanged();
6757    }
6758   
6759    /**
6760    * Store selected annotation sort order for the view and repaint.
6761    */
 
6762  0 toggle @Override
6763    protected void sortAnnotations_actionPerformed()
6764    {
6765  0 this.alignPanel.av.setSortAnnotationsBy(getAnnotationSortOrder());
6766  0 this.alignPanel.av
6767    .setShowAutocalculatedAbove(isShowAutoCalculatedAbove());
6768  0 alignPanel.paintAlignment(false, false);
6769    }
6770   
6771    /**
6772    *
6773    * @return alignment panels in this alignment frame
6774    */
 
6775  878 toggle public List<? extends AlignmentViewPanel> getAlignPanels()
6776    {
6777    // alignPanels is never null
6778    // return alignPanels == null ? Arrays.asList(alignPanel) : alignPanels;
6779  878 return alignPanels;
6780    }
6781   
6782    /**
6783    * Open a new alignment window, with the cDNA associated with this (protein)
6784    * alignment, aligned as is the protein.
6785    */
 
6786  0 toggle protected void viewAsCdna_actionPerformed()
6787    {
6788    // TODO no longer a menu action - refactor as required
6789  0 final AlignmentI alignment = getViewport().getAlignment();
6790  0 List<AlignedCodonFrame> mappings = alignment.getCodonFrames();
6791  0 if (mappings == null)
6792    {
6793  0 return;
6794    }
6795  0 List<SequenceI> cdnaSeqs = new ArrayList<>();
6796  0 for (SequenceI aaSeq : alignment.getSequences())
6797    {
6798  0 for (AlignedCodonFrame acf : mappings)
6799    {
6800  0 SequenceI dnaSeq = acf.getDnaForAaSeq(aaSeq.getDatasetSequence());
6801  0 if (dnaSeq != null)
6802    {
6803    /*
6804    * There is a cDNA mapping for this protein sequence - add to new alignment. It
6805    * will share the same dataset sequence as other mapped cDNA (no new mappings
6806    * need to be created).
6807    */
6808  0 final Sequence newSeq = new Sequence(dnaSeq);
6809  0 newSeq.setDatasetSequence(dnaSeq);
6810  0 cdnaSeqs.add(newSeq);
6811    }
6812    }
6813    }
6814  0 if (cdnaSeqs.size() == 0)
6815    {
6816    // show a warning dialog no mapped cDNA
6817  0 return;
6818    }
6819  0 AlignmentI cdna = new Alignment(
6820    cdnaSeqs.toArray(new SequenceI[cdnaSeqs.size()]));
6821  0 GAlignFrame alignFrame = new AlignFrame(cdna, AlignFrame.DEFAULT_WIDTH,
6822    AlignFrame.DEFAULT_HEIGHT);
6823  0 cdna.alignAs(alignment);
6824  0 String newtitle = "cDNA " + MessageManager.getString("label.for") + " "
6825    + this.title;
6826  0 Desktop.addInternalFrame(alignFrame, newtitle, AlignFrame.DEFAULT_WIDTH,
6827    AlignFrame.DEFAULT_HEIGHT);
6828    }
6829   
6830    /**
6831    * Set visibility of dna/protein complement view (available when shown in a
6832    * split frame).
6833    *
6834    * @param show
6835    */
 
6836  0 toggle @Override
6837    protected void showComplement_actionPerformed(boolean show)
6838    {
6839  0 SplitContainerI sf = getSplitViewContainer();
6840  0 if (sf != null)
6841    {
6842  0 sf.setComplementVisible(this, show);
6843    }
6844    }
6845   
6846    /**
6847    * Generate the reverse (optionally complemented) of the selected sequences,
6848    * and add them to the alignment
6849    */
 
6850  0 toggle @Override
6851    protected void showReverse_actionPerformed(boolean complement)
6852    {
6853  0 AlignmentI al = null;
6854  0 try
6855    {
6856  0 Dna dna = new Dna(viewport, viewport.getViewAsVisibleContigs(true));
6857  0 al = dna.reverseCdna(complement);
6858  0 viewport.addAlignment(al, "");
6859  0 addHistoryItem(new EditCommand(
6860    MessageManager.getString("label.add_sequences"), Action.PASTE,
6861    al.getSequencesArray(), 0, al.getWidth(),
6862    viewport.getAlignment()));
6863    } catch (Exception ex)
6864    {
6865  0 jalview.bin.Console.errPrintln(ex.getMessage());
6866  0 return;
6867    }
6868    }
6869   
6870    /**
6871    * Try to run a script in the Groovy console, having first ensured that this
6872    * AlignFrame is set as currentAlignFrame in Desktop, to allow the script to
6873    * be targeted at this alignment.
6874    */
 
6875  0 toggle @Override
6876    protected void runGroovy_actionPerformed()
6877    {
6878  0 Jalview.getInstance().setCurrentAlignFrame(this);
6879  0 groovy.console.ui.Console console = Desktop.getGroovyConsole();
6880  0 if (console != null)
6881    {
6882  0 try
6883    {
6884  0 console.setVariable(JalviewObjectI.currentAlFrameName, this);
6885  0 console.runScript();
6886    } catch (Exception ex)
6887    {
6888  0 jalview.bin.Console.errPrintln((ex.toString()));
6889  0 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
6890    MessageManager.getString("label.couldnt_run_groovy_script"),
6891    MessageManager.getString("label.groovy_support_failed"),
6892    JvOptionPane.ERROR_MESSAGE);
6893    }
6894    }
6895    else
6896    {
6897  0 jalview.bin.Console
6898    .errPrintln("Can't run Groovy script as console not found");
6899    }
6900    }
6901   
6902    /**
6903    * Hides columns containing (or not containing) a specified feature, provided
6904    * that would not leave all columns hidden
6905    *
6906    * @param featureType
6907    * @param columnsContaining
6908    * @return
6909    */
 
6910  7 toggle public boolean hideFeatureColumns(String featureType,
6911    boolean columnsContaining)
6912    {
6913  7 boolean notForHiding = avc.markColumnsContainingFeatures(
6914    columnsContaining, false, false, featureType);
6915  7 if (notForHiding)
6916    {
6917  5 if (avc.markColumnsContainingFeatures(!columnsContaining, false,
6918    false, featureType))
6919    {
6920  4 getViewport().hideSelectedColumns();
6921  4 return true;
6922    }
6923    }
6924  3 return false;
6925    }
6926   
 
6927  0 toggle @Override
6928    protected void selectHighlightedColumns_actionPerformed(
6929    ActionEvent actionEvent)
6930    {
6931    // include key modifier check in case user selects from menu
6932  0 avc.markHighlightedColumns(
6933    (actionEvent.getModifiers() & ActionEvent.ALT_MASK) != 0, true,
6934    (actionEvent.getModifiers() & (ActionEvent.META_MASK
6935    | ActionEvent.CTRL_MASK)) != 0);
6936    }
6937   
 
6938  0 toggle @Override
6939    protected void copyHighlightedColumns_actionPerformed(
6940    ActionEvent actionEvent)
6941    {
6942  0 avc.copyHighlightedRegionsToClipboard();
6943    }
6944   
6945    /**
6946    * Rebuilds the Colour menu, including any user-defined colours which have
6947    * been loaded either on startup or during the session
6948    */
 
6949  488 toggle public void buildColourMenu()
6950    {
6951  488 colourMenu.removeAll();
6952   
6953  488 colourMenu.add(applyToAllGroups);
6954  488 colourMenu.add(textColour);
6955  488 colourMenu.addSeparator();
6956   
6957  488 ButtonGroup bg = ColourMenuHelper.addMenuItems(colourMenu, this,
6958    viewport.getAlignment(), false);
6959   
6960  488 colourMenu.add(annotationColour);
6961  488 bg.add(annotationColour);
6962  488 colourMenu.addSeparator();
6963  488 colourMenu.add(conservationMenuItem);
6964  488 colourMenu.add(modifyConservation);
6965  488 colourMenu.add(byConsensusSecondaryStructureMenuItem);
6966  488 colourMenu.add(modifyConsensusSecondaryStructureThreshold);
6967  488 colourMenu.add(abovePIDThreshold);
6968  488 colourMenu.add(modifyPID);
6969   
6970  488 ColourSchemeI colourScheme = viewport.getGlobalColourScheme();
6971  488 ColourMenuHelper.setColourSelected(colourMenu, colourScheme);
6972    }
6973   
6974    /**
6975    * Open a dialog (if not already open) that allows the user to select and
6976    * calculate PCA or Tree analysis
6977    */
 
6978  0 toggle protected void openTreePcaDialog()
6979    {
6980  0 if (alignPanel.getCalculationDialog() == null)
6981    {
6982  0 new CalculationChooser(AlignFrame.this);
6983    }
6984    }
6985   
6986    /**
6987    * Sets the status of the HMMER menu
6988    */
 
6989  0 toggle public void updateHMMERStatus()
6990    {
6991  0 hmmerMenu.setEnabled(HmmerCommand.isHmmerAvailable());
6992    }
6993   
 
6994  0 toggle @Override
6995    protected void loadVcf_actionPerformed()
6996    {
6997  0 JalviewFileChooser chooser = new JalviewFileChooser(
6998    Cache.getProperty("LAST_DIRECTORY"));
6999  0 chooser.setFileView(new JalviewFileView());
7000  0 chooser.setDialogTitle(MessageManager.getString("label.load_vcf_file"));
7001  0 chooser.setToolTipText(MessageManager.getString("label.load_vcf_file"));
7002  0 final AlignFrame us = this;
7003  0 chooser.setResponseHandler(0, () -> {
7004  0 String choice = chooser.getSelectedFile().getPath();
7005  0 Cache.setProperty("LAST_DIRECTORY", choice);
7006  0 SequenceI[] seqs = viewport.getAlignment().getSequencesArray();
7007  0 new VCFLoader(choice).loadVCF(seqs, us);
7008    });
7009  0 chooser.showOpenDialog(null);
7010   
7011    }
7012   
7013    private Rectangle lastFeatureSettingsBounds = null;
7014   
 
7015  1 toggle @Override
7016    public void setFeatureSettingsGeometry(Rectangle bounds)
7017    {
7018  1 lastFeatureSettingsBounds = bounds;
7019    }
7020   
 
7021  2 toggle @Override
7022    public Rectangle getFeatureSettingsGeometry()
7023    {
7024  2 return lastFeatureSettingsBounds;
7025    }
7026   
7027    /**
7028    * helper for jalview.bin.Commands and loader that sets annotation visibility
7029    * in a single call
7030    *
7031    * @param showSSAnnotations
7032    * @param showAnnotations
7033    * @param hideTFrows
7034    */
 
7035  149 toggle public void showOrHideAnnotations(boolean showSSAnnotations,
7036    boolean showAnnotations, boolean hideTFrows)
7037    {
7038  149 setAnnotationsVisibility(showSSAnnotations, true, false);
7039  149 setAnnotationsVisibility(showAnnotations, false, true);
7040   
7041    // show temperature factor annotations?
7042  149 if (hideTFrows)
7043    {
7044    // do this better (annotation types?)
7045    // TODO: JAL-4595
7046  0 List<String> hideThese = new ArrayList<>();
7047  0 hideThese.add("Temperature Factor");
7048  0 hideThese.add(AlphaFoldAnnotationRowBuilder.LABEL);
7049  0 AlignmentUtils.showOrHideSequenceAnnotations(
7050    getCurrentView().getAlignment(), hideThese, null, false,
7051    false);
7052  0 alignPanel.updateAnnotation();
7053   
7054    }
7055    }
7056   
7057    /**
7058    * A method to temporarily disable input to the AlignFrame while another
7059    * process finishes (e.g. SVG/EPS output) by placing a glass pane on top of
7060    * the JInternalFrame's JRootPane, optionally with transparent grey cover.
7061    *
7062    * @param boolean
7063    * greyPanel
7064    */
 
7065  29 toggle public void disableInput(boolean greyPanel, boolean coverStatusPanel)
7066    {
7067    // Add a glass pane to the JRootPane that sucks up all mouse events
7068   
7069    // create glass pane if it doesn't exist yet. Can re-use it.
7070  29 if (glassPane == null)
7071    {
7072  29 JPanel glass;
7073  29 if (greyPanel)
7074    {
7075  29 glass = new JPanel()
7076    {
 
7077  33 toggle @Override
7078    public void paintComponent(Graphics g)
7079    {
7080  33 if (greyPanel)
7081    {
7082  33 g.setColor(new Color(0, 0, 0, 48));
7083  33 g.fillRect(0, 0, this.getWidth(), this.getHeight()
7084    - AlignFrame.this.getStatusPanel().getHeight());
7085    }
7086    }
7087    };
7088    }
7089    else
7090    {
7091  0 glass = new JPanel();
7092    }
7093   
7094  29 glass.addMouseListener(new MouseAdapter()
7095    {
 
7096  0 toggle @Override
7097    public void mousePressed(MouseEvent e)
7098    {
7099    // block mouse input
7100  0 e.consume();
7101    }
7102    });
7103  29 glass.addKeyListener(new KeyListener()
7104    {
 
7105  0 toggle @Override
7106    public void keyTyped(KeyEvent e)
7107    {
7108  0 e.consume();
7109    }
7110   
 
7111  0 toggle @Override
7112    public void keyPressed(KeyEvent e)
7113    {
7114  0 e.consume();
7115    }
7116   
 
7117  0 toggle @Override
7118    public void keyReleased(KeyEvent e)
7119    {
7120  0 e.consume();
7121    }
7122    });
7123  29 glass.setOpaque(false);
7124  29 glassPane = glass;
7125    }
7126    else
7127    {
7128  0 int myHeight = coverStatusPanel ? getRootPane().getHeight()
7129    : getRootPane().getHeight() - getStatusPanel().getHeight();
7130  0 int myWidth = getRootPane().getWidth();
7131   
7132  0 glassPane.setSize(myWidth, myHeight);
7133    }
7134   
7135  29 JRootPane root = getRootPane();
7136  29 savedRootGlassPane = root.getGlassPane();
7137  29 root.setGlassPane(glassPane);
7138  29 savedRootGlassPane.setVisible(false);
7139  29 glassPane.setVisible(true);
7140  29 setResizable(false);
7141  29 setMaximizable(false);
7142  29 setIconifiable(false);
7143  29 setClosable(false);
7144    }
7145   
7146    private JPanel glassPane = null;
7147   
7148    private Component savedRootGlassPane = getRootPane().getGlassPane();
7149   
7150    /**
7151    * And a method to re-enable the AlignFrame, restoring the original JRootPane
7152    * glass pane
7153    */
 
7154  29 toggle public void enableInput()
7155    {
7156  29 setResizable(true);
7157  29 setMaximizable(true);
7158  29 setIconifiable(true);
7159  29 setClosable(true);
7160  29 getRootPane().setGlassPane(savedRootGlassPane);
7161  29 savedRootGlassPane.setVisible(true);
7162  29 if (glassPane != null)
7163    {
7164  29 glassPane.setVisible(false);
7165    }
7166    }
7167   
 
7168  0 toggle public void scrollTo(int row, int column)
7169    {
7170  0 alignPanel.getSeqPanel().scrollTo(row, column);
7171    }
7172   
 
7173  0 toggle public void scrollToRow(int row)
7174    {
7175  0 alignPanel.getSeqPanel().scrollToRow(row);
7176    }
7177   
 
7178  0 toggle public void scrollToColumn(int column)
7179    {
7180  0 alignPanel.getSeqPanel().scrollToColumn(column);
7181    }
7182   
7183    /**
7184    * BH 2019 from JalviewLite
7185    *
7186    * get sequence feature groups that are hidden or shown
7187    *
7188    * @param visible
7189    * true is visible
7190    * @return list
7191    */
7192   
 
7193  0 toggle public String[] getFeatureGroupsOfState(boolean visible)
7194    {
7195  0 jalview.api.FeatureRenderer fr = null;
7196  0 if (alignPanel != null
7197    && (fr = alignPanel.getFeatureRenderer()) != null)
7198    {
7199  0 List<String> gps = fr.getGroups(visible);
7200  0 String[] _gps = gps.toArray(new String[gps.size()]);
7201  0 return _gps;
7202    }
7203  0 return null;
7204    }
7205   
7206    /**
7207    *
7208    * @return list of feature groups on the view
7209    */
7210   
 
7211  0 toggle public String[] getFeatureGroups()
7212    {
7213  0 jalview.api.FeatureRenderer fr = null;
7214  0 if (alignPanel != null
7215    && (fr = alignPanel.getFeatureRenderer()) != null)
7216    {
7217  0 List<String> gps = fr.getFeatureGroups();
7218  0 String[] _gps = gps.toArray(new String[gps.size()]);
7219  0 return _gps;
7220    }
7221  0 return null;
7222    }
7223   
 
7224  0 toggle public void select(SequenceGroup sel, ColumnSelection csel,
7225    HiddenColumns hidden)
7226    {
7227  0 alignPanel.getSeqPanel().selection(sel, csel, hidden, null);
7228    }
7229   
 
7230  0 toggle public int getID()
7231    {
7232  0 return id;
7233    }
7234   
 
7235    static class PrintThread extends Thread
7236    {
7237    AlignmentPanel ap;
7238   
 
7239  0 toggle public PrintThread(AlignmentPanel ap)
7240    {
7241  0 this.ap = ap;
7242    }
7243   
7244    static PageFormat pf;
7245   
 
7246  0 toggle @Override
7247    public void run()
7248    {
7249  0 PrinterJob printJob = PrinterJob.getPrinterJob();
7250   
7251  0 if (pf != null)
7252    {
7253  0 printJob.setPrintable(ap, pf);
7254    }
7255    else
7256    {
7257  0 printJob.setPrintable(ap);
7258    }
7259   
7260  0 if (printJob.printDialog())
7261    {
7262  0 try
7263    {
7264  0 printJob.print();
7265    } catch (Exception PrintException)
7266    {
7267  0 PrintException.printStackTrace();
7268    }
7269    }
7270    }
7271    }
7272    }