Clover icon

Coverage Report

  1. Project Clover database Fri Dec 6 2024 13:47:14 GMT
  2. Package jalview.gui

File AlignFrame.java

 

Coverage histogram

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

Code metrics

692
1,910
257
2
6,487
4,659
748
0.39
7.43
128.5
2.91

Classes

Class Line # Actions
AlignFrame 178 1,901 743
0.3248945232.5%
PrintThread 6451 9 5
0.00%
 

Contributing tests

This file is covered by 292 tests. .

Source view

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