Clover icon

Coverage Report

  1. Project Clover database Mon Oct 6 2025 17:39:40 BST
  2. Package jalview.gui

File AlignFrame.java

 

Coverage histogram

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

Code metrics

700
1,947
264
2
6,620
4,749
758
0.39
7.38
132
2.87

Classes

Class Line # Actions
AlignFrame 181 1,938 753
0.3276933732.8%
PrintThread 6584 9 5
0.00%
 

Contributing tests

This file is covered by 341 tests. .

Source view

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