Clover icon

Coverage Report

  1. Project Clover database Mon Dec 1 2025 15:35:32 GMT
  2. Package jalview.gui

File AlignFrame.java

 

Coverage histogram

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

Code metrics

710
1,989
271
2
6,749
4,848
773
0.39
7.34
135.5
2.85

Classes

Class Line # Actions
AlignFrame 185 1,980 768
0.3336717533.4%
PrintThread 6713 9 5
0.00%
 

Contributing tests

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