Clover icon

Coverage Report

  1. Project Clover database Mon Sep 2 2024 17:57:51 BST
  2. Package jalview.gui

File AlignFrame.java

 

Coverage histogram

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

Code metrics

676
1,866
254
2
6,369
4,568
731
0.39
7.35
127
2.88

Classes

Class Line # Actions
AlignFrame 180 1,857 726
0.327939632.8%
PrintThread 6333 9 5
0.00%
 

Contributing tests

This file is covered by 328 tests. .

Source view

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