Clover icon

Coverage Report

  1. Project Clover database Mon Nov 11 2024 17:27:16 GMT
  2. Package jalview.gui

File AlignFrame.java

 

Coverage histogram

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

Code metrics

676
1,872
258
2
6,403
4,590
735
0.39
7.26
129
2.85

Classes

Class Line # Actions
AlignFrame 180 1,863 730
0.3289143732.9%
PrintThread 6367 9 5
0.00%
 

Contributing tests

This file is covered by 313 tests. .

Source view

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