Clover icon

Coverage Report

  1. Project Clover database Wed Nov 19 2025 15:00:14 GMT
  2. Package jalview.gui

File AlignFrame.java

 

Coverage histogram

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

Code metrics

710
1,983
271
2
6,737
4,840
770
0.39
7.32
135.5
2.84

Classes

Class Line # Actions
AlignFrame 185 1,974 765
0.3326551333.3%
PrintThread 6701 9 5
0.00%
 

Contributing tests

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