Clover icon

Coverage Report

  1. Project Clover database Mon Nov 18 2024 09:38:20 GMT
  2. Package jalview.gui

File AlignFrame.java

 

Coverage histogram

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

Code metrics

692
1,911
259
2
6,502
4,668
750
0.39
7.38
129.5
2.9

Classes

Class Line # Actions
AlignFrame 178 1,902 745
0.273972627.4%
PrintThread 6466 9 5
0.00%
 

Contributing tests

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