X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FAlignFrame.java;h=9013416294550d8dbf359bfd96386fc5e3c72cc4;hb=9c16178c0601ea3169d7a5d5d623dafa45c54f85;hp=11570ed7aa127532522a16f8939ab2800d7096e3;hpb=d5912abc02b0fd206d9705cf13a0383f09d3d951;p=jalview.git diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java old mode 100755 new mode 100644 index 11570ed..9013416 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -1,107 +1,327 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer - * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Softwarechang - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.gui; -import java.beans.*; -import java.io.*; -import java.util.*; - -import java.awt.*; -import java.awt.datatransfer.*; -import java.awt.event.*; -import java.awt.print.*; -import javax.swing.*; - -import jalview.analysis.*; -import jalview.datamodel.*; -import jalview.io.*; -import jalview.jbgui.*; -import jalview.schemes.*; -import jalview.commands.*; -import jalview.ws.*; -import java.awt.dnd.*; -import javax.swing.event.ChangeListener; -import javax.swing.event.ChangeEvent; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.print.PageFormat; +import java.awt.print.PrinterJob; +import java.beans.PropertyChangeEvent; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Deque; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.List; +import java.util.Vector; + +import javax.swing.ButtonGroup; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JEditorPane; +import javax.swing.JInternalFrame; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; + +import jalview.analysis.AlignmentSorter; +import jalview.analysis.AlignmentUtils; +import jalview.analysis.CrossRef; +import jalview.analysis.Dna; +import jalview.analysis.GeneticCodeI; +import jalview.analysis.ParseProperties; +import jalview.analysis.SequenceIdMatcher; +import jalview.api.AlignExportSettingI; +import jalview.api.AlignViewControllerGuiI; +import jalview.api.AlignViewControllerI; +import jalview.api.AlignViewportI; +import jalview.api.AlignmentViewPanel; +import jalview.api.FeatureSettingsControllerI; +import jalview.api.FeatureSettingsModelI; +import jalview.api.SplitContainerI; +import jalview.api.ViewStyleI; +import jalview.api.analysis.SimilarityParamsI; +import jalview.bin.Cache; +import jalview.bin.Jalview; +import jalview.commands.CommandI; +import jalview.commands.EditCommand; +import jalview.commands.EditCommand.Action; +import jalview.commands.OrderCommand; +import jalview.commands.RemoveGapColCommand; +import jalview.commands.RemoveGapsCommand; +import jalview.commands.SlideSequencesCommand; +import jalview.commands.TrimRegionCommand; +import jalview.datamodel.AlignedCodonFrame; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentExportData; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.AlignmentOrder; +import jalview.datamodel.AlignmentView; +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.HiddenSequences; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SeqCigar; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; +import jalview.gui.ColourMenuHelper.ColourChangeListener; +import jalview.gui.ViewSelectionMenu.ViewSetProvider; +import jalview.io.AlignmentProperties; +import jalview.io.AnnotationFile; +import jalview.io.BackupFiles; +import jalview.io.BioJsHTMLOutput; +import jalview.io.DataSourceType; +import jalview.io.FileFormat; +import jalview.io.FileFormatI; +import jalview.io.FileFormats; +import jalview.io.FileLoader; +import jalview.io.FileParse; +import jalview.io.FormatAdapter; +import jalview.io.HtmlSvgOutput; +import jalview.io.IdentifyFile; +import jalview.io.JPredFile; +import jalview.io.JalviewFileChooser; +import jalview.io.JalviewFileView; +import jalview.io.JnetAnnotationMaker; +import jalview.io.NewickFile; +import jalview.io.ScoreMatrixFile; +import jalview.io.TCoffeeScoreFile; +import jalview.io.vcf.VCFLoader; +import jalview.jbgui.GAlignFrame; +import jalview.schemes.ColourSchemeI; +import jalview.schemes.ColourSchemes; +import jalview.schemes.ResidueColourScheme; +import jalview.schemes.TCoffeeColourScheme; +import jalview.util.HttpUtils; +import jalview.util.MessageManager; +import jalview.util.Platform; +import jalview.viewmodel.AlignmentViewport; +import jalview.viewmodel.ViewportRanges; +import jalview.ws.DBRefFetcher; +import jalview.ws.DBRefFetcher.FetchFinishedListenerI; +import jalview.ws.jws1.Discoverer; +import jalview.ws.jws2.Jws2Discoverer; +import jalview.ws.jws2.jabaws2.Jws2Instance; +import jalview.ws.seqfetcher.DbSourceProxy; /** * DOCUMENT ME! - * + * * @author $author$ * @version $Revision$ */ -public class AlignFrame extends GAlignFrame implements DropTargetListener +public class AlignFrame extends GAlignFrame implements DropTargetListener, + IProgressIndicator, AlignViewControllerGuiI, ColourChangeListener { - /** DOCUMENT ME!! */ + public static final int DEFAULT_WIDTH = 700; - /** DOCUMENT ME!! */ public static final int DEFAULT_HEIGHT = 500; + + /* + * The currently displayed panel (selected tabbed view if more than one) + */ public AlignmentPanel alignPanel; AlignViewport viewport; - Vector alignPanels = new Vector(); + public AlignViewControllerI avc; + List alignPanels = new ArrayList<>(); - /** DOCUMENT ME!! */ - String currentFileFormat = null; + /** + * Last format used to load or save alignments in this window + */ + FileFormatI currentFileFormat = null; + /** + * Current filename for this alignment + */ String fileName = null; - /** - * Creates a new AlignFrame object. - * - * @param al DOCUMENT ME! + * Creates a new AlignFrame object with specific width and height. + * + * @param al + * @param width + * @param height */ public AlignFrame(AlignmentI al, int width, int height) { this(al, null, width, height); } + /** + * Creates a new AlignFrame object with specific width, height and + * sequenceSetId + * + * @param al + * @param width + * @param height + * @param sequenceSetId + */ + public AlignFrame(AlignmentI al, int width, int height, + String sequenceSetId) + { + this(al, null, width, height, sequenceSetId); + } + + /** + * Creates a new AlignFrame object with specific width, height and + * sequenceSetId + * + * @param al + * @param width + * @param height + * @param sequenceSetId + * @param viewId + */ + public AlignFrame(AlignmentI al, int width, int height, + String sequenceSetId, String viewId) + { + this(al, null, width, height, sequenceSetId, viewId); + } /** * new alignment window with hidden columns - * @param al AlignmentI - * @param hiddenColumns ColumnSelection or null + * + * @param al + * AlignmentI + * @param hiddenColumns + * ColumnSelection or null + * @param width + * Width of alignment frame + * @param height + * height of frame. */ - public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns, - int width, int height) + public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns, int width, + int height) { - this.setSize(width, height); - viewport = new AlignViewport(al, hiddenColumns); + this(al, hiddenColumns, width, height, null); + } + + /** + * Create alignment frame for al with hiddenColumns, a specific width and + * height, and specific sequenceId + * + * @param al + * @param hiddenColumns + * @param width + * @param height + * @param sequenceSetId + * (may be null) + */ + public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns, int width, + int height, String sequenceSetId) + { + this(al, hiddenColumns, width, height, sequenceSetId, null); + } + + /** + * Create alignment frame for al with hiddenColumns, a specific width and + * height, and specific sequenceId + * + * @param al + * @param hiddenColumns + * @param width + * @param height + * @param sequenceSetId + * (may be null) + * @param viewId + * (may be null) + */ + public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns, int width, + int height, String sequenceSetId, String viewId) + { + setSize(width, height); + + if (al.getDataset() == null) + { + al.setDataset(null); + } + + viewport = new AlignViewport(al, hiddenColumns, sequenceSetId, viewId); alignPanel = new AlignmentPanel(this, viewport); - if(al.getDataset()==null) + addAlignmentPanel(alignPanel, true); + init(); + } + + public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs, + HiddenColumns hiddenColumns, int width, int height) + { + setSize(width, height); + + if (al.getDataset() == null) { al.setDataset(null); } + viewport = new AlignViewport(al, hiddenColumns); + + if (hiddenSeqs != null && hiddenSeqs.length > 0) + { + viewport.hideSequence(hiddenSeqs); + } + alignPanel = new AlignmentPanel(this, viewport); addAlignmentPanel(alignPanel, true); init(); } /** - * Make a new AlignFrame from exisiting alignmentPanels - * @param ap AlignmentPanel - * @param av AlignViewport + * Make a new AlignFrame from existing alignmentPanels + * + * @param ap + * AlignmentPanel + * @param av + * AlignViewport */ public AlignFrame(AlignmentPanel ap) { @@ -111,263 +331,419 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener init(); } + /** + * initalise the alignframe from the underlying viewport data and the + * configurations + */ void init() { - this.setDropTarget(new java.awt.dnd.DropTarget(this, this)); + if (!Jalview.isHeadlessMode()) + { + progressBar = new ProgressBar(this.statusPanel, this.statusBar); + } - if (viewport.conservation == null) + avc = new jalview.controller.AlignViewController(this, viewport, + alignPanel); + if (viewport.getAlignmentConservationAnnotation() == null) { - BLOSUM62Colour.setEnabled(false); + // BLOSUM62Colour.setEnabled(false); conservationMenuItem.setEnabled(false); modifyConservation.setEnabled(false); - // PIDColour.setEnabled(false); - // abovePIDThreshold.setEnabled(false); - // modifyPID.setEnabled(false); + // PIDColour.setEnabled(false); + // abovePIDThreshold.setEnabled(false); + // modifyPID.setEnabled(false); } - String sortby = jalview.bin.Cache.getDefault("SORT_ALIGNMENT", "No sort"); + String sortby = jalview.bin.Cache.getDefault("SORT_ALIGNMENT", + "No sort"); if (sortby.equals("Id")) + { sortIDMenuItem_actionPerformed(null); + } else if (sortby.equals("Pairwise Identity")) + { sortPairwiseMenuItem_actionPerformed(null); + } + + this.alignPanel.av + .setShowAutocalculatedAbove(isShowAutoCalculatedAbove()); + + setMenusFromViewport(viewport); + buildSortByAnnotationScoresMenu(); + calculateTree.addActionListener(new ActionListener() + { + + @Override + public void actionPerformed(ActionEvent e) + { + openTreePcaDialog(); + } + }); + buildColourMenu(); if (Desktop.desktop != null) - { - addServiceListeners(); - setGUINucleotide(viewport.alignment.isNucleotide()); - } + { + this.setDropTarget(new java.awt.dnd.DropTarget(this, this)); + addServiceListeners(); + setGUINucleotide(); + } + + if (viewport.getWrapAlignment()) + { + wrapMenuItem_actionPerformed(null); + } + + if (jalview.bin.Cache.getDefault("SHOW_OVERVIEW", false)) + { + this.overviewMenuItem_actionPerformed(null); + } + + addKeyListener(); + + final List selviews = new ArrayList<>(); + final List origview = new ArrayList<>(); + final String menuLabel = MessageManager + .getString("label.copy_format_from"); + ViewSelectionMenu vsel = new ViewSelectionMenu(menuLabel, + new ViewSetProvider() + { - setMenusFromViewport(viewport); + @Override + public AlignmentPanel[] getAllAlignmentPanels() + { + origview.clear(); + origview.add(alignPanel); + // make an array of all alignment panels except for this one + List aps = new ArrayList<>( + Arrays.asList(Desktop.getAlignmentPanels(null))); + aps.remove(AlignFrame.this.alignPanel); + return aps.toArray(new AlignmentPanel[aps.size()]); + } + }, selviews, new ItemListener() + { + + @Override + public void itemStateChanged(ItemEvent e) + { + if (origview.size() > 0) + { + final AlignmentPanel ap = origview.get(0); + + /* + * Copy the ViewStyle of the selected panel to 'this one'. + * Don't change value of 'scaleProteinAsCdna' unless copying + * from a SplitFrame. + */ + ViewStyleI vs = selviews.get(0).getAlignViewport() + .getViewStyle(); + boolean fromSplitFrame = selviews.get(0) + .getAlignViewport().getCodingComplement() != null; + if (!fromSplitFrame) + { + vs.setScaleProteinAsCdna(ap.getAlignViewport() + .getViewStyle().isScaleProteinAsCdna()); + } + ap.getAlignViewport().setViewStyle(vs); + + /* + * Also rescale ViewStyle of SplitFrame complement if there is + * one _and_ it is set to 'scaledProteinAsCdna'; we don't copy + * the whole ViewStyle (allow cDNA protein to have different + * fonts) + */ + AlignViewportI complement = ap.getAlignViewport() + .getCodingComplement(); + if (complement != null && vs.isScaleProteinAsCdna()) + { + AlignFrame af = Desktop.getAlignFrameFor(complement); + ((SplitFrame) af.getSplitViewContainer()) + .adjustLayout(); + af.setMenusForViewport(); + } - if (viewport.wrapAlignment) - { - wrapMenuItem_actionPerformed(null); - } + ap.updateLayout(); + ap.setSelected(true); + ap.alignFrame.setMenusForViewport(); - addKeyListener(); + } + } + }); + if (Cache.getDefault("VERSION", "DEVELOPMENT").toLowerCase() + .indexOf("devel") > -1 + || Cache.getDefault("VERSION", "DEVELOPMENT").toLowerCase() + .indexOf("test") > -1) + { + formatMenu.add(vsel); + } + addFocusListener(new FocusAdapter() + { + @Override + public void focusGained(FocusEvent e) + { + Jalview.setCurrentAlignFrame(AlignFrame.this); + } + }); } - public void setFileName(String file, String format) + /** + * Change the filename and format for the alignment, and enable the 'reload' + * button functionality. + * + * @param file + * valid filename + * @param format + * format of file + */ + public void setFileName(String file, FileFormatI format) { - fileName = file; - currentFileFormat = format; - reload.setEnabled(true); + fileName = file; + setFileFormat(format); + reload.setEnabled(true); } + /** + * Add a KeyListener with handlers for various KeyPressed and KeyReleased + * events + */ void addKeyListener() { - addKeyListener(new KeyAdapter() + addKeyListener(new KeyAdapter() + { + @Override + public void keyPressed(KeyEvent evt) { - public void keyPressed(KeyEvent evt) + if (viewport.cursorMode + && ((evt.getKeyCode() >= KeyEvent.VK_0 + && evt.getKeyCode() <= KeyEvent.VK_9) + || (evt.getKeyCode() >= KeyEvent.VK_NUMPAD0 + && evt.getKeyCode() <= KeyEvent.VK_NUMPAD9)) + && Character.isDigit(evt.getKeyChar())) { - if (viewport.cursorMode - && evt.getKeyCode() >= KeyEvent.VK_0 - && evt.getKeyCode() <= KeyEvent.VK_9) - { - alignPanel.seqPanel.numberPressed(evt.getKeyChar()); - } - - switch (evt.getKeyCode()) - { - - case 27: // escape key - deselectAllSequenceMenuItem_actionPerformed(null); - - break; + alignPanel.getSeqPanel().numberPressed(evt.getKeyChar()); + } - case KeyEvent.VK_DOWN: - if (viewport.cursorMode) - { - alignPanel.seqPanel.moveCursor(0, 1); - } - else - moveSelectedSequences(false); - break; + switch (evt.getKeyCode()) + { - case KeyEvent.VK_UP: - if (viewport.cursorMode) - { - alignPanel.seqPanel.moveCursor(0, -1); - } - else - moveSelectedSequences(true); - break; + case 27: // escape key + deselectAllSequenceMenuItem_actionPerformed(null); - case KeyEvent.VK_LEFT: - if (viewport.cursorMode) - { - alignPanel.seqPanel.moveCursor( -1, 0); - } - break; + break; - case KeyEvent.VK_RIGHT: - if (viewport.cursorMode) - { - alignPanel.seqPanel.moveCursor(1, 0); - } - break; + case KeyEvent.VK_DOWN: + if (evt.isAltDown() || !viewport.cursorMode) + { + moveSelectedSequences(false); + } + if (viewport.cursorMode) + { + alignPanel.getSeqPanel().moveCursor(0, 1, + evt.isShiftDown() && !evt.isAltDown()); + } + break; - case KeyEvent.VK_SPACE: - if (viewport.cursorMode) - { - alignPanel.seqPanel.insertGapAtCursor(evt.isControlDown() - || evt.isShiftDown() - || evt.isAltDown()); - } - break; + case KeyEvent.VK_UP: + if (evt.isAltDown() || !viewport.cursorMode) + { + moveSelectedSequences(true); + } + if (viewport.cursorMode) + { + alignPanel.getSeqPanel().moveCursor(0, -1, + evt.isShiftDown() && !evt.isAltDown()); + } + break; - case KeyEvent.VK_DELETE: - case KeyEvent.VK_BACK_SPACE: - if (!viewport.cursorMode) - { - cut_actionPerformed(null); - } - else - alignPanel.seqPanel.deleteGapAtCursor(evt.isControlDown() - || evt.isShiftDown() - || evt.isAltDown()); + case KeyEvent.VK_LEFT: + if (evt.isAltDown() || !viewport.cursorMode) + { + slideSequences(false, + alignPanel.getSeqPanel().getKeyboardNo1()); + } + else + { + alignPanel.getSeqPanel().moveCursor(-1, 0, evt.isShiftDown()); + } - break; + break; - case KeyEvent.VK_S: - if (viewport.cursorMode) - { - alignPanel.seqPanel.setCursorRow(); - } - break; - case KeyEvent.VK_C: - if (viewport.cursorMode && !evt.isControlDown()) - { - alignPanel.seqPanel.setCursorColumn(); - } - break; - case KeyEvent.VK_P: - if (viewport.cursorMode) - { - alignPanel.seqPanel.setCursorPosition(); - } - break; + case KeyEvent.VK_RIGHT: + if (evt.isAltDown() || !viewport.cursorMode) + { + slideSequences(true, alignPanel.getSeqPanel().getKeyboardNo1()); + } + else + { + alignPanel.getSeqPanel().moveCursor(1, 0, evt.isShiftDown()); + } + break; - case KeyEvent.VK_ENTER: - case KeyEvent.VK_COMMA: - if (viewport.cursorMode) - { - alignPanel.seqPanel.setCursorRowAndColumn(); - } - break; + case KeyEvent.VK_SPACE: + if (viewport.cursorMode) + { + alignPanel.getSeqPanel().insertGapAtCursor(evt.isControlDown() + || evt.isShiftDown() || evt.isAltDown()); + } + break; + + // case KeyEvent.VK_A: + // if (viewport.cursorMode) + // { + // alignPanel.seqPanel.insertNucAtCursor(false,"A"); + // //System.out.println("A"); + // } + // break; + /* + * case KeyEvent.VK_CLOSE_BRACKET: if (viewport.cursorMode) { + * System.out.println("closing bracket"); } break; + */ + case KeyEvent.VK_DELETE: + case KeyEvent.VK_BACK_SPACE: + if (!viewport.cursorMode) + { + cut_actionPerformed(null); + } + else + { + alignPanel.getSeqPanel().deleteGapAtCursor(evt.isControlDown() + || evt.isShiftDown() || evt.isAltDown()); + } - case KeyEvent.VK_Q: - if (viewport.cursorMode) - { - alignPanel.seqPanel.setSelectionAreaAtCursor(true); - } - break; - case KeyEvent.VK_M: - if (viewport.cursorMode) - { - alignPanel.seqPanel.setSelectionAreaAtCursor(false); - } - break; + break; - case KeyEvent.VK_F2: - viewport.cursorMode = !viewport.cursorMode; - statusBar.setText("Keyboard editing mode is " + - (viewport.cursorMode ? "on" : "off")); - if (viewport.cursorMode) - { - alignPanel.seqPanel.seqCanvas.cursorX = viewport.startRes; - alignPanel.seqPanel.seqCanvas.cursorY = viewport.startSeq; - } - alignPanel.seqPanel.seqCanvas.repaint(); - break; + case KeyEvent.VK_S: + if (viewport.cursorMode) + { + alignPanel.getSeqPanel().setCursorRow(); + } + break; + case KeyEvent.VK_C: + if (viewport.cursorMode && !evt.isControlDown()) + { + alignPanel.getSeqPanel().setCursorColumn(); + } + break; + case KeyEvent.VK_P: + if (viewport.cursorMode) + { + alignPanel.getSeqPanel().setCursorPosition(); + } + break; - case KeyEvent.VK_F1: - try - { - ClassLoader cl = jalview.gui.Desktop.class.getClassLoader(); - java.net.URL url = javax.help.HelpSet.findHelpSet(cl, "help/help"); - javax.help.HelpSet hs = new javax.help.HelpSet(cl, url); + case KeyEvent.VK_ENTER: + case KeyEvent.VK_COMMA: + if (viewport.cursorMode) + { + alignPanel.getSeqPanel().setCursorRowAndColumn(); + } + break; - javax.help.HelpBroker hb = hs.createHelpBroker(); - hb.setCurrentID("home"); - hb.setDisplayed(true); - } - catch (Exception ex) - { - ex.printStackTrace(); - } - break - ; - case KeyEvent.VK_H: - { - boolean toggleSeqs = !evt.isControlDown(); - boolean toggleCols = !evt.isShiftDown(); + case KeyEvent.VK_Q: + if (viewport.cursorMode) + { + alignPanel.getSeqPanel().setSelectionAreaAtCursor(true); + } + break; + case KeyEvent.VK_M: + if (viewport.cursorMode) + { + alignPanel.getSeqPanel().setSelectionAreaAtCursor(false); + } + break; + + case KeyEvent.VK_F2: + viewport.cursorMode = !viewport.cursorMode; + statusBar.setText(MessageManager + .formatMessage("label.keyboard_editing_mode", new String[] + { (viewport.cursorMode ? "on" : "off") })); + if (viewport.cursorMode) + { + ViewportRanges ranges = viewport.getRanges(); + alignPanel.getSeqPanel().seqCanvas.cursorX = ranges + .getStartRes(); + alignPanel.getSeqPanel().seqCanvas.cursorY = ranges + .getStartSeq(); + } + alignPanel.getSeqPanel().seqCanvas.repaint(); + break; - boolean hide = false; + case KeyEvent.VK_F1: + try + { + Help.showHelpWindow(); + } catch (Exception ex) + { + ex.printStackTrace(); + } + break; + case KeyEvent.VK_H: + { + boolean toggleSeqs = !evt.isControlDown(); + boolean toggleCols = !evt.isShiftDown(); + toggleHiddenRegions(toggleSeqs, toggleCols); + break; + } + case KeyEvent.VK_B: + { + boolean toggleSel = evt.isControlDown() || evt.isMetaDown(); + boolean modifyExisting = true; // always modify, don't clear + // evt.isShiftDown(); + boolean invertHighlighted = evt.isAltDown(); + avc.markHighlightedColumns(invertHighlighted, modifyExisting, + toggleSel); + break; + } + case KeyEvent.VK_PAGE_UP: + viewport.getRanges().pageUp(); + break; + case KeyEvent.VK_PAGE_DOWN: + viewport.getRanges().pageDown(); + break; + } + } - SequenceGroup sg = viewport.getSelectionGroup(); - if (toggleSeqs) - { - if (sg != null && sg.getSize(false) != viewport.alignment.getHeight()) - { - hideSelSequences_actionPerformed(null); - hide = true; - } - else if (! (toggleCols && viewport.colSel.getSelected().size() > 0)) - showAllSeqs_actionPerformed(null); - } + @Override + public void keyReleased(KeyEvent evt) + { + switch (evt.getKeyCode()) + { + case KeyEvent.VK_LEFT: + if (evt.isAltDown() || !viewport.cursorMode) + { + viewport.firePropertyChange("alignment", null, + viewport.getAlignment().getSequences()); + } + break; - if (toggleCols) - { - if (viewport.colSel.getSelected().size() > 0) - { - hideSelColumns_actionPerformed(null); - if (!toggleSeqs) - viewport.selectionGroup = sg; - } - else if (!hide) - showAllColumns_actionPerformed(null); - } - break; - } - case KeyEvent.VK_PAGE_UP: - if (viewport.wrapAlignment) - alignPanel.scrollUp(true); - else - alignPanel.setScrollValues(viewport.startRes, - viewport.startSeq - - viewport.endSeq + viewport.startSeq); - break; - case KeyEvent.VK_PAGE_DOWN: - if (viewport.wrapAlignment) - alignPanel.scrollUp(false); - else - alignPanel.setScrollValues(viewport.startRes, - viewport.startSeq - + viewport.endSeq - viewport.startSeq); - break; + case KeyEvent.VK_RIGHT: + if (evt.isAltDown() || !viewport.cursorMode) + { + viewport.firePropertyChange("alignment", null, + viewport.getAlignment().getSequences()); } + break; } - }); + } + }); } - - public void addAlignmentPanel(final AlignmentPanel ap, - boolean newPanel) + public void addAlignmentPanel(final AlignmentPanel ap, boolean newPanel) { ap.alignFrame = this; + avc = new jalview.controller.AlignViewController(this, viewport, + alignPanel); - alignPanels.addElement(ap); + alignPanels.add(ap); PaintRefresher.Register(ap, ap.av.getSequenceSetId()); int aSize = alignPanels.size(); - tabbedPane.setVisible(aSize>1 || ap.av.viewName!=null); + tabbedPane.setVisible(aSize > 1 || ap.av.getViewName() != null); - if (aSize == 1 && ap.av.viewName==null) + if (aSize == 1 && ap.av.getViewName() == null) { this.getContentPane().add(ap, BorderLayout.CENTER); } @@ -380,17 +756,20 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener expandViews.setEnabled(true); gatherViews.setEnabled(true); - tabbedPane.addTab(ap.av.viewName, ap); + tabbedPane.addTab(ap.av.getViewName(), ap); ap.setVisible(false); } - if(newPanel) + if (newPanel) { - if (ap.av.padGaps) - ap.av.alignment.padGaps(); + if (ap.av.isPadGaps()) + { + ap.av.getAlignment().padGaps(); + } ap.av.updateConservation(ap); ap.av.updateConsensus(ap); + ap.av.updateStrucConsensus(ap); } } @@ -399,12 +778,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener expandViews.setEnabled(true); gatherViews.setEnabled(true); tabbedPane.setVisible(true); - AlignmentPanel first = (AlignmentPanel) alignPanels.firstElement(); - tabbedPane.addTab(first.av.viewName,first); + AlignmentPanel first = alignPanels.get(0); + tabbedPane.addTab(first.av.getViewName(), first); this.getContentPane().add(tabbedPane, BorderLayout.CENTER); } - public AlignViewport getViewport() { return viewport; @@ -414,379 +792,595 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener private void addServiceListeners() { final java.beans.PropertyChangeListener thisListener; - // Do this once to get current state - BuildWebServiceMenu(); - Desktop.discoverer.addPropertyChangeListener( - thisListener = new java.beans.PropertyChangeListener() - { - public void propertyChange(PropertyChangeEvent evt) - { - // System.out.println("Discoverer property change."); - if (evt.getPropertyName().equals("services")) - { - // System.out.println("Rebuilding web service menu"); - BuildWebServiceMenu(); - } - } - }); + Desktop.instance.addJalviewPropertyChangeListener("services", + thisListener = new java.beans.PropertyChangeListener() + { + @Override + public void propertyChange(PropertyChangeEvent evt) + { + // // System.out.println("Discoverer property change."); + // if (evt.getPropertyName().equals("services")) + { + SwingUtilities.invokeLater(new Runnable() + { + + @Override + public void run() + { + System.err.println( + "Rebuild WS Menu for service change"); + BuildWebServiceMenu(); + } - addInternalFrameListener(new javax.swing.event. - InternalFrameAdapter() + }); + } + } + }); + addInternalFrameListener(new javax.swing.event.InternalFrameAdapter() { + @Override public void internalFrameClosed( - javax.swing.event.InternalFrameEvent evt) + javax.swing.event.InternalFrameEvent evt) { // System.out.println("deregistering discoverer listener"); - Desktop.discoverer.removePropertyChangeListener(thisListener); + Desktop.instance.removeJalviewPropertyChangeListener("services", + thisListener); closeMenuItem_actionPerformed(true); - } - ; + }; }); + // Finally, build the menu once to get current service state + new Thread(new Runnable() + { + @Override + public void run() + { + BuildWebServiceMenu(); + } + }).start(); } - public void setGUINucleotide(boolean nucleotide) + /** + * Configure menu items that vary according to whether the alignment is + * nucleotide or protein + */ + public void setGUINucleotide() { - showTranslation.setVisible( nucleotide ); - conservationMenuItem.setEnabled( !nucleotide ); - modifyConservation.setEnabled( !nucleotide ); + AlignmentI al = getViewport().getAlignment(); + boolean nucleotide = al.isNucleotide(); - //Remember AlignFrame always starts as protein - if(!nucleotide) - { - calculateMenu.remove(calculateMenu.getItemCount()-2); - } + loadVcf.setVisible(nucleotide); + showTranslation.setVisible(nucleotide); + showReverse.setVisible(nucleotide); + showReverseComplement.setVisible(nucleotide); + conservationMenuItem.setEnabled(!nucleotide); + modifyConservation + .setEnabled(!nucleotide && conservationMenuItem.isSelected()); + showGroupConservation.setEnabled(!nucleotide); + + showComplementMenuItem + .setText(nucleotide ? MessageManager.getString("label.protein") + : MessageManager.getString("label.nucleotide")); + } + + /** + * set up menus for the current viewport. This may be called after any + * operation that affects the data in the current view (selection changed, + * etc) to update the menus to reflect the new state. + */ + @Override + public void setMenusForViewport() + { + setMenusFromViewport(viewport); } /** - * Need to call this method when tabs are selected for multiple views, - * or when loading from Jalview2XML.java - * @param av AlignViewport + * Need to call this method when tabs are selected for multiple views, or when + * loading from Jalview2XML.java + * + * @param av + * AlignViewport */ - void setMenusFromViewport(AlignViewport av) + public void setMenusFromViewport(AlignViewport av) { - padGapsMenuitem.setSelected(av.padGaps); - colourTextMenuItem.setSelected(av.showColourText); + padGapsMenuitem.setSelected(av.isPadGaps()); + colourTextMenuItem.setSelected(av.isShowColourText()); abovePIDThreshold.setSelected(av.getAbovePIDThreshold()); + modifyPID.setEnabled(abovePIDThreshold.isSelected()); conservationMenuItem.setSelected(av.getConservationSelected()); + modifyConservation.setEnabled(conservationMenuItem.isSelected()); seqLimits.setSelected(av.getShowJVSuffix()); - idRightAlign.setSelected(av.rightAlignIds); - renderGapsMenuItem.setSelected(av.renderGaps); - wrapMenuItem.setSelected(av.wrapAlignment); - annotationPanelMenuItem.setState(av.showAnnotation); - viewBoxesMenuItem.setSelected(av.showBoxes); - viewTextMenuItem.setSelected(av.showText); - - setColourSelected(ColourSchemeProperty. - getColourName(av.getGlobalColourScheme())); - - showSeqFeatures.setSelected(av.showSequenceFeatures); - hiddenMarkers.setState(av.showHiddenMarkers); - applyToAllGroups.setState(av.colourAppliesToAllGroups); + idRightAlign.setSelected(av.isRightAlignIds()); + centreColumnLabelsMenuItem.setState(av.isCentreColumnLabels()); + renderGapsMenuItem.setSelected(av.isRenderGaps()); + wrapMenuItem.setSelected(av.getWrapAlignment()); + scaleAbove.setVisible(av.getWrapAlignment()); + scaleLeft.setVisible(av.getWrapAlignment()); + scaleRight.setVisible(av.getWrapAlignment()); + annotationPanelMenuItem.setState(av.isShowAnnotation()); + /* + * Show/hide annotations only enabled if annotation panel is shown + */ + showAllSeqAnnotations.setEnabled(annotationPanelMenuItem.getState()); + hideAllSeqAnnotations.setEnabled(annotationPanelMenuItem.getState()); + showAllAlAnnotations.setEnabled(annotationPanelMenuItem.getState()); + hideAllAlAnnotations.setEnabled(annotationPanelMenuItem.getState()); + viewBoxesMenuItem.setSelected(av.getShowBoxes()); + viewTextMenuItem.setSelected(av.getShowText()); + showNonconservedMenuItem.setSelected(av.getShowUnconserved()); + showGroupConsensus.setSelected(av.isShowGroupConsensus()); + showGroupConservation.setSelected(av.isShowGroupConservation()); + showConsensusHistogram.setSelected(av.isShowConsensusHistogram()); + showSequenceLogo.setSelected(av.isShowSequenceLogo()); + normaliseSequenceLogo.setSelected(av.isNormaliseSequenceLogo()); + + ColourMenuHelper.setColourSelected(colourMenu, + av.getGlobalColourScheme()); + + showSeqFeatures.setSelected(av.isShowSequenceFeatures()); + hiddenMarkers.setState(av.getShowHiddenMarkers()); + applyToAllGroups.setState(av.getColourAppliesToAllGroups()); + showNpFeatsMenuitem.setSelected(av.isShowNPFeats()); + showDbRefsMenuitem.setSelected(av.isShowDBRefs()); + autoCalculate.setSelected(av.autoCalculateConsensus); + sortByTree.setSelected(av.sortByTree); + listenToViewSelections.setSelected(av.followSelection); + + showProducts.setEnabled(canShowProducts()); + setGroovyEnabled(Desktop.getGroovyConsole() != null); updateEditMenuBar(); } + /** + * Set the enabled state of the 'Run Groovy' option in the Calculate menu + * + * @param b + */ + public void setGroovyEnabled(boolean b) + { + runGroovy.setEnabled(b); + } + + private IProgressIndicator progressBar; - Hashtable progressBars; + /* + * (non-Javadoc) + * + * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long) + */ + @Override public void setProgressBar(String message, long id) { - if(progressBars == null) - progressBars = new Hashtable(); - - JPanel progressPanel; - GridLayout layout = (GridLayout) statusPanel.getLayout(); - if(progressBars.get( new Long(id) )!=null) - { - progressPanel = (JPanel)progressBars.get( new Long(id) ); - statusPanel.remove(progressPanel); - progressBars.remove( progressPanel ); - progressPanel = null; - if(message!=null) - statusBar.setText(message); - - layout.setRows(layout.getRows() - 1); - } - else - { - progressPanel = new JPanel(new BorderLayout(10, 5)); - - JProgressBar progressBar = new JProgressBar(); - progressBar.setIndeterminate(true); + progressBar.setProgressBar(message, id); + } - progressPanel.add(new JLabel(message), BorderLayout.WEST); - progressPanel.add(progressBar, BorderLayout.CENTER); - - layout.setRows(layout.getRows() + 1); - statusPanel.add(progressPanel); - - progressBars.put(new Long(id), progressPanel); - } - - validate(); + @Override + public void registerHandler(final long id, + final IProgressIndicatorHandler handler) + { + progressBar.registerHandler(id, handler); } + /** + * + * @return true if any progress bars are still active + */ + @Override + public boolean operationInProgress() + { + return progressBar.operationInProgress(); + } - + /** + * Sets the text of the status bar. Note that setting a null or empty value + * will cause the status bar to be hidden, with possibly undesirable flicker + * of the screen layout. + */ + @Override + public void setStatus(String text) + { + statusBar.setText(text == null || text.isEmpty() ? " " : text); + } /* - Added so Castor Mapping file can obtain Jalview Version - */ + * Added so Castor Mapping file can obtain Jalview Version + */ public String getVersion() { - return jalview.bin.Cache.getProperty("VERSION"); + return jalview.bin.Cache.getProperty("VERSION"); } public FeatureRenderer getFeatureRenderer() { - return alignPanel.seqPanel.seqCanvas.getFeatureRenderer(); + return alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer(); } - + @Override public void fetchSequence_actionPerformed(ActionEvent e) { - new SequenceFetcher(this); + new jalview.gui.SequenceFetcher(this); } + @Override public void addFromFile_actionPerformed(ActionEvent e) { Desktop.instance.inputLocalFileMenuItem_actionPerformed(viewport); } + @Override public void reload_actionPerformed(ActionEvent e) { - if(fileName!=null) + if (fileName != null) { - if(currentFileFormat.equals("Jalview")) + // TODO: JAL-1108 - ensure all associated frames are closed regardless of + // originating file's format + // TODO: work out how to recover feature settings for correct view(s) when + // file is reloaded. + if (FileFormat.Jalview.equals(currentFileFormat)) { - JInternalFrame [] frames = Desktop.desktop.getAllFrames(); - for(int i=0; i 0) - { - viewport.alignment.deleteSequence(0); - } + Rectangle bounds = this.getBounds(); + + FileLoader loader = new FileLoader(); + DataSourceType protocol = HttpUtils.startsWithHttpOrHttps(fileName) + ? DataSourceType.URL + : DataSourceType.FILE; + AlignFrame newframe = loader.LoadFileWaitTillLoaded(fileName, + protocol, currentFileFormat); - viewport.historyList.clear(); - viewport.redoList.clear(); - Alignment dset = viewport.alignment.getDataset(); - while (dset.getHeight() > 0) + newframe.setBounds(bounds); + if (featureSettings != null && featureSettings.isShowing()) { - dset.deleteSequence(0); + final Rectangle fspos = featureSettings.frame.getBounds(); + // TODO: need a 'show feature settings' function that takes bounds - + // need to refactor Desktop.addFrame + newframe.featureSettings_actionPerformed(null); + final FeatureSettings nfs = newframe.featureSettings; + SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { + nfs.frame.setBounds(fspos); + } + }); + this.featureSettings.close(); + this.featureSettings = null; } - - firePropertyChange("Alignment", null, null); - - updateEditMenuBar(); + this.closeMenuItem_actionPerformed(true); } - - FileLoader loader = new FileLoader(); - String protocol = fileName.startsWith("http:")? "URL":"File"; - loader.LoadFile(viewport, fileName, protocol, currentFileFormat); - } } - + @Override public void addFromText_actionPerformed(ActionEvent e) { - Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport); + Desktop.instance + .inputTextboxMenuItem_actionPerformed(viewport.getAlignPanel()); } + @Override public void addFromURL_actionPerformed(ActionEvent e) { Desktop.instance.inputURLMenuItem_actionPerformed(viewport); } - + @Override public void save_actionPerformed(ActionEvent e) { - if(fileName==null || currentFileFormat==null) + if (fileName == null || (currentFileFormat == null) + || HttpUtils.startsWithHttpOrHttps(fileName)) + { saveAs_actionPerformed(null); + } else + { saveAlignment(fileName, currentFileFormat); + } } /** * DOCUMENT ME! - * - * @param e DOCUMENT ME! + * + * @param e + * DOCUMENT ME! */ + @Override public void saveAs_actionPerformed(ActionEvent e) { - JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache. - getProperty( "LAST_DIRECTORY"), - new String[] - { "fa, fasta, fastq", "aln", "pfam", "msf", "pir", "blc","jar" }, - new String[] - { "Fasta", "Clustal", "PFAM", "MSF", "PIR", "BLC", "Jalview" }, - currentFileFormat, - false); - + String format = currentFileFormat == null ? null + : currentFileFormat.getName(); + JalviewFileChooser chooser = JalviewFileChooser + .forWrite(Cache.getProperty("LAST_DIRECTORY"), format); chooser.setFileView(new JalviewFileView()); - chooser.setDialogTitle("Save Alignment to file"); - chooser.setToolTipText("Save"); + chooser.setDialogTitle( + MessageManager.getString("label.save_alignment_to_file")); + chooser.setToolTipText(MessageManager.getString("action.save")); int value = chooser.showSaveDialog(this); if (value == JalviewFileChooser.APPROVE_OPTION) { + currentFileFormat = chooser.getSelectedFormat(); + while (currentFileFormat == null) + { + JvOptionPane.showInternalMessageDialog(Desktop.desktop, + MessageManager.getString( + "label.select_file_format_before_saving"), + MessageManager.getString("label.file_format_not_specified"), + JvOptionPane.WARNING_MESSAGE); currentFileFormat = chooser.getSelectedFormat(); - if (currentFileFormat == null) + value = chooser.showSaveDialog(this); + if (value != JalviewFileChooser.APPROVE_OPTION) { - JOptionPane.showInternalMessageDialog(Desktop.desktop, - "You must select a file format before saving!", - "File format not specified", - JOptionPane.WARNING_MESSAGE); - value = chooser.showSaveDialog(this); return; } + } - fileName = chooser.getSelectedFile().getPath(); - - jalview.bin.Cache.setProperty("DEFAULT_FILE_FORMAT", - currentFileFormat); + fileName = chooser.getSelectedFile().getPath(); - jalview.bin.Cache.setProperty("LAST_DIRECTORY", fileName); + Cache.setProperty("DEFAULT_FILE_FORMAT", currentFileFormat.getName()); + Cache.setProperty("LAST_DIRECTORY", fileName); saveAlignment(fileName, currentFileFormat); } } - public boolean saveAlignment(String file, String format) + public boolean saveAlignment(String file, FileFormatI format) { - if (format.equalsIgnoreCase("Jalview")) + boolean success = true; + + if (FileFormat.Jalview.equals(format)) { String shortName = title; if (shortName.indexOf(java.io.File.separatorChar) > -1) { - shortName = shortName.substring(shortName.lastIndexOf( - java.io.File.separatorChar) + 1); + shortName = shortName.substring( + shortName.lastIndexOf(java.io.File.separatorChar) + 1); } - new Jalview2XML().SaveAlignment(this, file, shortName); + success = new jalview.project.Jalview2XML().saveAlignment(this, file, + shortName); - statusBar.setText("Successfully saved to file: " - +fileName+" in " - +format +" format."); + statusBar.setText(MessageManager.formatMessage( + "label.successfully_saved_to_file_in_format", new Object[] + { file, format })); - - // USE Jalview2XML to save this file - return true; } else { - - String[] omitHidden = null; - - if (viewport.hasHiddenColumns) + AlignmentExportData exportData = getAlignmentForExport(format, + viewport, null); + if (exportData.getSettings().isCancelled()) { - int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop, - "The Alignment contains hidden columns." - + "\nDo you want to save only the visible alignment?", - "Save / Omit Hidden Columns", - JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); - - if (reply == JOptionPane.YES_OPTION) - omitHidden = viewport.getViewAsString(false); + return false; } - - String output = new FormatAdapter().formatSequences( - format, - viewport.alignment.getSequencesArray(), - omitHidden); + FormatAdapter f = new FormatAdapter(alignPanel, + exportData.getSettings()); + String output = f.formatSequences(format, exportData.getAlignment(), // class + // cast + // exceptions + // will + // occur in the distant future + exportData.getOmitHidden(), exportData.getStartEndPostions(), + f.getCacheSuffixDefault(format), + viewport.getAlignment().getHiddenColumns()); if (output == null) { - return false; + success = false; } - - try + else { - java.io.PrintWriter out = new java.io.PrintWriter( - new java.io.FileWriter(file)); + // create backupfiles object and get new temp filename destination + Cache.log.trace("ALIGNFRAME making backupfiles object for " + file); + BackupFiles backupfiles = new BackupFiles(file); + + try + { + String tempFilePath = backupfiles.getTempFilePath(); + Cache.log.trace( + "ALIGNFRAME setting PrintWriter to " + tempFilePath); + PrintWriter out = new PrintWriter(new FileWriter(tempFilePath)); + + Cache.log.trace( + "ALIGNFRAME about to write to temp file " + tempFilePath); + + out.print(output); + Cache.log.trace("ALIGNFRAME about to close file"); + out.close(); + Cache.log.trace("ALIGNFRAME closed file"); + this.setTitle(file); + statusBar.setText(MessageManager.formatMessage( + "label.successfully_saved_to_file_in_format", new Object[] + { file, format.getName() })); + } catch (IOException e) + { + success = false; + Cache.log.error( + "ALIGNFRAME Something happened writing the temp file"); + Cache.log.error(e.getMessage()); + Cache.log.debug(Cache.getStackTraceString(e)); + + } catch (Exception ex) + { + success = false; + Cache.log.error( + "ALIGNFRAME Something unexpected happened writing the temp file"); + Cache.log.error(ex.getMessage()); + Cache.log.debug(Cache.getStackTraceString(ex)); + } + + backupfiles.setWriteSuccess(success); + Cache.log.debug("ALIGNFRAME writing temp file was " + + (success ? "" : "NOT ") + "successful"); + // do the backup file roll and rename the temp file to actual file + Cache.log.trace("ALIGNFRAME about to rollBackupsAndRenameTempFile"); + success = backupfiles.rollBackupsAndRenameTempFile(); + Cache.log.debug("ALIGNFRAME performed rollBackupsAndRenameTempFile " + + (success ? "" : "un") + "successfully"); - out.print(output); - out.close(); - this.setTitle(file); - statusBar.setText("Successfully saved to file: " - +fileName+" in " - +format +" format."); - return true; } - catch (Exception ex) + } + + if (!success) + { + if (!Platform.isHeadless()) { - ex.printStackTrace(); + JvOptionPane.showInternalMessageDialog(this, MessageManager + .formatMessage("label.couldnt_save_file", new Object[] + { file }), + MessageManager.getString("label.error_saving_file"), + JvOptionPane.WARNING_MESSAGE); } } - return false; + + return success; + } + + private void warningMessage(String warning, String title) + { + if (new jalview.util.Platform().isHeadless()) + { + System.err.println("Warning: " + title + "\nWarning: " + warning); + + } + else + { + JvOptionPane.showInternalMessageDialog(this, warning, title, + JvOptionPane.WARNING_MESSAGE); + } + return; } /** * DOCUMENT ME! - * - * @param e DOCUMENT ME! + * + * @param e + * DOCUMENT ME! */ + @Override protected void outputText_actionPerformed(ActionEvent e) { - String [] omitHidden = null; - - if(viewport.hasHiddenColumns) + FileFormatI fileFormat = FileFormats.getInstance() + .forName(e.getActionCommand()); + AlignmentExportData exportData = getAlignmentForExport(fileFormat, + viewport, null); + if (exportData.getSettings().isCancelled()) { - int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop, - "The Alignment contains hidden columns." - +"\nDo you want to output only the visible alignment?", - "Save / Omit Hidden Columns", - JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); - - if(reply==JOptionPane.YES_OPTION) - { - omitHidden = viewport.getViewAsString(false); - } + return; } - CutAndPasteTransfer cap = new CutAndPasteTransfer(); cap.setForInput(null); - Desktop.addInternalFrame(cap, - "Alignment output - " + e.getActionCommand(), 600, - 500); + try + { + FileFormatI format = fileFormat; + cap.setText(new FormatAdapter(alignPanel, exportData.getSettings()) + .formatSequences(format, exportData.getAlignment(), + exportData.getOmitHidden(), + exportData.getStartEndPostions(), + viewport.getAlignment().getHiddenColumns())); + Desktop.addInternalFrame(cap, MessageManager + .formatMessage("label.alignment_output_command", new Object[] + { e.getActionCommand() }), 600, 500); + } catch (OutOfMemoryError oom) + { + new OOMWarning("Outputting alignment as " + e.getActionCommand(), + oom); + cap.dispose(); + } + + } + + public static AlignmentExportData getAlignmentForExport( + FileFormatI format, AlignViewportI viewport, + AlignExportSettingI exportSettings) + { + AlignmentI alignmentToExport = null; + AlignExportSettingI settings = exportSettings; + String[] omitHidden = null; + + HiddenSequences hiddenSeqs = viewport.getAlignment() + .getHiddenSequences(); + + alignmentToExport = viewport.getAlignment(); + + boolean hasHiddenSeqs = hiddenSeqs.getSize() > 0; + if (settings == null) + { + settings = new AlignExportSettings(hasHiddenSeqs, + viewport.hasHiddenColumns(), format); + } + // settings.isExportAnnotations(); + if (viewport.hasHiddenColumns() && !settings.isExportHiddenColumns()) + { + omitHidden = viewport.getViewAsString(false, + settings.isExportHiddenSequences()); + } - cap.setText(new FormatAdapter().formatSequences( - e.getActionCommand(), - viewport.alignment.getSequencesArray(), - omitHidden)); + int[] alignmentStartEnd = new int[2]; + if (hasHiddenSeqs && settings.isExportHiddenSequences()) + { + alignmentToExport = hiddenSeqs.getFullAlignment(); + } + else + { + alignmentToExport = viewport.getAlignment(); + } + alignmentStartEnd = viewport.getAlignment().getHiddenColumns() + .getVisibleStartAndEndIndex(alignmentToExport.getWidth()); + AlignmentExportData ed = new AlignmentExportData(alignmentToExport, + omitHidden, alignmentStartEnd, settings); + return ed; } /** * DOCUMENT ME! - * - * @param e DOCUMENT ME! + * + * @param e + * DOCUMENT ME! */ + @Override protected void htmlMenuItem_actionPerformed(ActionEvent e) { - new HTMLOutput(viewport, - alignPanel.seqPanel.seqCanvas.getSequenceRenderer(), - alignPanel.seqPanel.seqCanvas.getFeatureRenderer()); + HtmlSvgOutput htmlSVG = new HtmlSvgOutput(alignPanel); + htmlSVG.exportHTML(null); + } + + @Override + public void bioJSMenuItem_actionPerformed(ActionEvent e) + { + BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel); + bjs.exportHTML(null); } public void createImageMap(File file, String image) @@ -796,9 +1390,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener /** * DOCUMENT ME! - * - * @param e DOCUMENT ME! + * + * @param e + * DOCUMENT ME! */ + @Override public void createPNG(File f) { alignPanel.makePNG(f); @@ -806,50 +1402,66 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener /** * DOCUMENT ME! - * - * @param e DOCUMENT ME! + * + * @param e + * DOCUMENT ME! */ + @Override public void createEPS(File f) { alignPanel.makeEPS(f); } + @Override + public void createSVG(File f) + { + alignPanel.makeSVG(f); + } + + @Override + public void pageSetup_actionPerformed(ActionEvent e) + { + PrinterJob printJob = PrinterJob.getPrinterJob(); + PrintThread.pf = printJob.pageDialog(printJob.defaultPage()); + } + /** * DOCUMENT ME! - * - * @param e DOCUMENT ME! + * + * @param e + * DOCUMENT ME! */ + @Override public void printMenuItem_actionPerformed(ActionEvent e) { - //Putting in a thread avoids Swing painting problems - PrintThread thread = new PrintThread(); + // Putting in a thread avoids Swing painting problems + PrintThread thread = new PrintThread(alignPanel); thread.start(); } + @Override public void exportFeatures_actionPerformed(ActionEvent e) { - new AnnotationExporter().exportFeatures(alignPanel); + new AnnotationExporter(alignPanel).exportFeatures(); } - + @Override public void exportAnnotations_actionPerformed(ActionEvent e) { - new AnnotationExporter().exportAnnotations( - alignPanel, - viewport.alignment.getAlignmentAnnotation() - ); + new AnnotationExporter(alignPanel).exportAnnotations(); } - + @Override public void associatedData_actionPerformed(ActionEvent e) { // Pick the tree file - JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache. - getProperty( - "LAST_DIRECTORY")); + JalviewFileChooser chooser = new JalviewFileChooser( + jalview.bin.Cache.getProperty("LAST_DIRECTORY")); chooser.setFileView(new JalviewFileView()); - chooser.setDialogTitle("Load Jalview Annotations or Features File"); - chooser.setToolTipText("Load Jalview Annotations / Features file"); + chooser.setDialogTitle( + MessageManager.getString("label.load_jalview_annotations")); + chooser.setToolTipText( + MessageManager.getString("label.load_jalview_annotations")); int value = chooser.showOpenDialog(null); @@ -857,64 +1469,90 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener { String choice = chooser.getSelectedFile().getPath(); jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice); - loadJalviewDataFile(choice); + loadJalviewDataFile(choice, null, null, null); } } - /** - * DOCUMENT ME! - * - * @param e DOCUMENT ME! + * Close the current view or all views in the alignment frame. If the frame + * only contains one view then the alignment will be removed from memory. + * + * @param closeAllTabs */ + @Override public void closeMenuItem_actionPerformed(boolean closeAllTabs) { - if(alignPanels!=null && alignPanels.size()<2) + if (alignPanels != null && alignPanels.size() < 2) + { closeAllTabs = true; + } try { - if(alignPanels!=null) + if (alignPanels != null) { if (closeAllTabs) - for (int i = 0; i < alignPanels.size(); i++) + { + if (this.isClosed()) { - AlignmentPanel ap = (AlignmentPanel) alignPanels.elementAt(i); - PaintRefresher.RemoveComponent(ap.seqPanel.seqCanvas); - PaintRefresher.RemoveComponent(ap.idPanel.idCanvas); - PaintRefresher.RemoveComponent(ap); + // really close all the windows - otherwise wait till + // setClosed(true) is called + for (int i = 0; i < alignPanels.size(); i++) + { + AlignmentPanel ap = alignPanels.get(i); + ap.closePanel(); + } } + } else { - int index = tabbedPane.getSelectedIndex(); - - alignPanels.removeElement(alignPanel); - PaintRefresher.RemoveComponent(alignPanel.seqPanel.seqCanvas); - PaintRefresher.RemoveComponent(alignPanel.idPanel.idCanvas); - PaintRefresher.RemoveComponent(alignPanel); - alignPanel = null; - viewport = null; - - tabbedPane.removeTabAt(index); - tabbedPane.validate(); - - if(index==tabbedPane.getTabCount()) - index --; - - this.tabSelectionChanged(index); + closeView(alignPanel); } } - if (closeAllTabs) + { + if (featureSettings != null && featureSettings.isOpen()) + { + featureSettings.close(); + featureSettings = null; + } + /* + * this will raise an INTERNAL_FRAME_CLOSED event and this method will + * be called recursively, with the frame now in 'closed' state + */ this.setClosed(true); - } - catch (Exception ex) + } + } catch (Exception ex) { ex.printStackTrace(); } } + /** + * Close the specified panel and close up tabs appropriately. + * + * @param panelToClose + */ + public void closeView(AlignmentPanel panelToClose) + { + int index = tabbedPane.getSelectedIndex(); + int closedindex = tabbedPane.indexOfComponent(panelToClose); + alignPanels.remove(panelToClose); + panelToClose.closePanel(); + panelToClose = null; + + tabbedPane.removeTabAt(closedindex); + tabbedPane.validate(); + + if (index > closedindex || index == tabbedPane.getTabCount()) + { + // modify currently selected tab index if necessary. + index--; + } + + this.tabSelectionChanged(index); + } /** * DOCUMENT ME! @@ -922,132 +1560,201 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener void updateEditMenuBar() { - if (viewport.historyList.size() > 0) + if (viewport.getHistoryList().size() > 0) { undoMenuItem.setEnabled(true); - CommandI command = (CommandI) viewport.historyList.peek(); - undoMenuItem.setText("Undo " + command.getDescription()); + CommandI command = viewport.getHistoryList().peek(); + undoMenuItem.setText(MessageManager + .formatMessage("label.undo_command", new Object[] + { command.getDescription() })); } else { undoMenuItem.setEnabled(false); - undoMenuItem.setText("Undo"); + undoMenuItem.setText(MessageManager.getString("action.undo")); } - if (viewport.redoList.size() > 0) + if (viewport.getRedoList().size() > 0) { redoMenuItem.setEnabled(true); - CommandI command = (CommandI) viewport.redoList.peek(); - redoMenuItem.setText("Redo " + command.getDescription()); + CommandI command = viewport.getRedoList().peek(); + redoMenuItem.setText(MessageManager + .formatMessage("label.redo_command", new Object[] + { command.getDescription() })); } else { redoMenuItem.setEnabled(false); - redoMenuItem.setText("Redo"); + redoMenuItem.setText(MessageManager.getString("action.redo")); } } - + @Override public void addHistoryItem(CommandI command) { - if(command.getSize()>0) + if (command.getSize() > 0) { - viewport.historyList.push(command); - viewport.redoList.clear(); + viewport.addToHistoryList(command); + viewport.clearRedoList(); updateEditMenuBar(); - viewport.hasHiddenColumns = viewport.colSel.getHiddenColumns() != null; + viewport.updateHiddenColumns(); + // viewport.hasHiddenColumns = (viewport.getColumnSelection() != null + // && viewport.getColumnSelection().getHiddenColumns() != null && + // viewport.getColumnSelection() + // .getHiddenColumns().size() > 0); } } - + /** + * + * @return alignment objects for all views + */ + AlignmentI[] getViewAlignments() + { + if (alignPanels != null) + { + AlignmentI[] als = new AlignmentI[alignPanels.size()]; + int i = 0; + for (AlignmentPanel ap : alignPanels) + { + als[i++] = ap.av.getAlignment(); + } + return als; + } + if (viewport != null) + { + return new AlignmentI[] { viewport.getAlignment() }; + } + return null; + } /** * DOCUMENT ME! - * - * @param e DOCUMENT ME! + * + * @param e + * DOCUMENT ME! */ + @Override protected void undoMenuItem_actionPerformed(ActionEvent e) { - CommandI command = (CommandI)viewport.historyList.pop(); - viewport.redoList.push(command); - command.undoCommand(); + if (viewport.getHistoryList().isEmpty()) + { + return; + } + CommandI command = viewport.getHistoryList().pop(); + viewport.addToRedoList(command); + command.undoCommand(getViewAlignments()); - AlignViewport originalSource = getOriginatingSource(command); + AlignmentViewport originalSource = getOriginatingSource(command); updateEditMenuBar(); - if(originalSource!=null) + if (originalSource != null) { - originalSource.hasHiddenColumns = viewport.colSel.getHiddenColumns() != null; - originalSource.firePropertyChange("alignment", null,null); + if (originalSource != viewport) + { + Cache.log.warn( + "Implementation worry: mismatch of viewport origin for undo"); + } + originalSource.updateHiddenColumns(); + // originalSource.hasHiddenColumns = (viewport.getColumnSelection() != + // null + // && viewport.getColumnSelection().getHiddenColumns() != null && + // viewport.getColumnSelection() + // .getHiddenColumns().size() > 0); + originalSource.firePropertyChange("alignment", null, + originalSource.getAlignment().getSequences()); } } /** * DOCUMENT ME! - * - * @param e DOCUMENT ME! + * + * @param e + * DOCUMENT ME! */ + @Override protected void redoMenuItem_actionPerformed(ActionEvent e) { - CommandI command = (CommandI) viewport.redoList.pop(); - viewport.historyList.push(command); - command.doCommand(); + if (viewport.getRedoList().size() < 1) + { + return; + } - AlignViewport originalSource = getOriginatingSource(command); + CommandI command = viewport.getRedoList().pop(); + viewport.addToHistoryList(command); + command.doCommand(getViewAlignments()); + + AlignmentViewport originalSource = getOriginatingSource(command); updateEditMenuBar(); - if(originalSource!=null) + if (originalSource != null) { - originalSource.hasHiddenColumns = viewport.colSel.getHiddenColumns() != null; - originalSource.firePropertyChange("alignment", null,null); + + if (originalSource != viewport) + { + Cache.log.warn( + "Implementation worry: mismatch of viewport origin for redo"); + } + originalSource.updateHiddenColumns(); + // originalSource.hasHiddenColumns = (viewport.getColumnSelection() != + // null + // && viewport.getColumnSelection().getHiddenColumns() != null && + // viewport.getColumnSelection() + // .getHiddenColumns().size() > 0); + originalSource.firePropertyChange("alignment", null, + originalSource.getAlignment().getSequences()); } } - AlignViewport getOriginatingSource(CommandI command) + AlignmentViewport getOriginatingSource(CommandI command) { - AlignViewport originalSource = null; - //For sequence removal and addition, we need to fire - //the property change event FROM the viewport where the - //original alignment was altered + AlignmentViewport originalSource = null; + // For sequence removal and addition, we need to fire + // the property change event FROM the viewport where the + // original alignment was altered + AlignmentI al = null; if (command instanceof EditCommand) { EditCommand editCommand = (EditCommand) command; - AlignmentI al = editCommand.getAlignment(); - Vector comps = (Vector) PaintRefresher.components - .get(viewport.getSequenceSetId()); + al = editCommand.getAlignment(); + List comps = PaintRefresher.components + .get(viewport.getSequenceSetId()); - for (int i = 0; i < comps.size(); i++) + for (Component comp : comps) { - if (comps.elementAt(i) instanceof AlignmentPanel) + if (comp instanceof AlignmentPanel) { - if (al == ( (AlignmentPanel) comps.elementAt(i)).av.alignment) + if (al == ((AlignmentPanel) comp).av.getAlignment()) { - originalSource = ( (AlignmentPanel) comps.elementAt(i)).av; + originalSource = ((AlignmentPanel) comp).av; break; } } } - if (originalSource == null) - { - //The original view is closed, we must validate - //the current view against the closed view first - if (al != null) - PaintRefresher.validateSequences(al, viewport.alignment); + } - originalSource = viewport; + if (originalSource == null) + { + // The original view is closed, we must validate + // the current view against the closed view first + if (al != null) + { + PaintRefresher.validateSequences(al, viewport.getAlignment()); } + originalSource = viewport; } - return originalSource; } /** - * DOCUMENT ME! - * - * @param up DOCUMENT ME! + * Calls AlignmentI.moveSelectedSequencesByOne with current sequence selection + * or the sequence under cursor in keyboard mode + * + * @param up + * or down (if !up) */ public void moveSelectedSequences(boolean up) { @@ -1055,144 +1762,206 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener if (sg == null) { - return; + if (viewport.cursorMode) + { + sg = new SequenceGroup(); + sg.addSequence(viewport.getAlignment().getSequenceAt( + alignPanel.getSeqPanel().seqCanvas.cursorY), false); + } + else + { + return; + } } - if (up) + if (sg.getSize() < 1) { - for (int i = 1; i < viewport.alignment.getHeight(); i++) - { - SequenceI seq = viewport.alignment.getSequenceAt(i); + return; + } - if (!sg.getSequences(false).contains(seq)) - { - continue; - } + // TODO: JAL-3733 - add an event to the undo buffer for this ! - SequenceI temp = viewport.alignment.getSequenceAt(i - 1); + viewport.getAlignment().moveSelectedSequencesByOne(sg, + viewport.getHiddenRepSequences(), up); + alignPanel.paintAlignment(true, false); + } - if (sg.getSequences(false).contains(temp)) - { - continue; - } + synchronized void slideSequences(boolean right, int size) + { + List sg = new ArrayList<>(); + if (viewport.getSelectionGroup() != null && viewport.getSelectionGroup() + .getSize() != viewport.getAlignment().getHeight()) + { + sg = viewport.getSelectionGroup() + .getSequences(viewport.getHiddenRepSequences()); + } - viewport.alignment.getSequences().setElementAt(temp, i); - viewport.alignment.getSequences().setElementAt(seq, i - 1); - } + if (sg.size() == 0 && viewport.cursorMode) + { + sg.add(viewport.getAlignment() + .getSequenceAt(alignPanel.getSeqPanel().seqCanvas.cursorY)); } - else + + if (sg.size() < 1) + { + return; + } + + List invertGroup = new ArrayList<>(); + + for (SequenceI seq : viewport.getAlignment().getSequences()) { - for (int i = viewport.alignment.getHeight() - 2; i > -1; i--) + if (!sg.contains(seq)) { - SequenceI seq = viewport.alignment.getSequenceAt(i); + invertGroup.add(seq); + } + } - if (!sg.getSequences(false).contains(seq)) - { - continue; - } + SequenceI[] seqs1 = sg.toArray(new SequenceI[0]); - SequenceI temp = viewport.alignment.getSequenceAt(i + 1); + SequenceI[] seqs2 = new SequenceI[invertGroup.size()]; + for (int i = 0; i < invertGroup.size(); i++) + { + seqs2[i] = invertGroup.get(i); + } - if (sg.getSequences(false).contains(temp)) - { - continue; - } + SlideSequencesCommand ssc; + if (right) + { + ssc = new SlideSequencesCommand("Slide Sequences", seqs2, seqs1, size, + viewport.getGapCharacter()); + } + else + { + ssc = new SlideSequencesCommand("Slide Sequences", seqs1, seqs2, size, + viewport.getGapCharacter()); + } - viewport.alignment.getSequences().setElementAt(temp, i); - viewport.alignment.getSequences().setElementAt(seq, i + 1); + int groupAdjustment = 0; + if (ssc.getGapsInsertedBegin() && right) + { + if (viewport.cursorMode) + { + alignPanel.getSeqPanel().moveCursor(size, 0); + } + else + { + groupAdjustment = size; + } + } + else if (!ssc.getGapsInsertedBegin() && !right) + { + if (viewport.cursorMode) + { + alignPanel.getSeqPanel().moveCursor(-size, 0); + } + else + { + groupAdjustment = -size; } } - alignPanel.repaint(); - } + if (groupAdjustment != 0) + { + viewport.getSelectionGroup().setStartRes( + viewport.getSelectionGroup().getStartRes() + groupAdjustment); + viewport.getSelectionGroup().setEndRes( + viewport.getSelectionGroup().getEndRes() + groupAdjustment); + } + + /* + * just extend the last slide command if compatible; but not if in + * SplitFrame mode (to ensure all edits are broadcast - JAL-1802) + */ + boolean appendHistoryItem = false; + Deque historyList = viewport.getHistoryList(); + boolean inSplitFrame = getSplitViewContainer() != null; + if (!inSplitFrame && historyList != null && historyList.size() > 0 + && historyList.peek() instanceof SlideSequencesCommand) + { + appendHistoryItem = ssc.appendSlideCommand( + (SlideSequencesCommand) historyList.peek()); + } + if (!appendHistoryItem) + { + addHistoryItem(ssc); + } + repaint(); + } /** * DOCUMENT ME! - * - * @param e DOCUMENT ME! + * + * @param e + * DOCUMENT ME! */ + @Override protected void copy_actionPerformed(ActionEvent e) { - System.gc(); if (viewport.getSelectionGroup() == null) { return; } - - SequenceI [] seqs = viewport.getSelectionAsNewSequence(); + // TODO: preserve the ordering of displayed alignment annotation in any + // internal paste (particularly sequence associated annotation) + SequenceI[] seqs = viewport.getSelectionAsNewSequence(); String[] omitHidden = null; - if (viewport.hasHiddenColumns) + if (viewport.hasHiddenColumns()) { omitHidden = viewport.getViewAsString(true); } - String output = new FormatAdapter().formatSequences( - "Fasta", - seqs, - omitHidden); + String output = new FormatAdapter().formatSequences(FileFormat.Fasta, + seqs, omitHidden, null); StringSelection ss = new StringSelection(output); try { - //Its really worth setting the clipboard contents - //to empty before setting the large StringSelection!! + jalview.gui.Desktop.internalCopy = true; + // Its really worth setting the clipboard contents + // to empty before setting the large StringSelection!! Toolkit.getDefaultToolkit().getSystemClipboard() - .setContents(new StringSelection(""), null); + .setContents(new StringSelection(""), null); - Toolkit.getDefaultToolkit().getSystemClipboard() - .setContents(ss, Desktop.instance); - } - catch (OutOfMemoryError er) + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, + Desktop.instance); + } catch (OutOfMemoryError er) { - er.printStackTrace(); - javax.swing.SwingUtilities.invokeLater(new Runnable() - { - public void run() - { - javax.swing.JOptionPane.showInternalMessageDialog(Desktop.desktop, - "Out of memory copying region!!" - + - "\nSee help files for increasing Java Virtual Machine memory." - , "Out of memory", - javax.swing.JOptionPane.WARNING_MESSAGE); - } - }); - + new OOMWarning("copying region", er); return; } - Vector hiddenColumns = null; - if(viewport.hasHiddenColumns) + HiddenColumns hiddenColumns = null; + if (viewport.hasHiddenColumns()) { - hiddenColumns =new Vector(); int hiddenOffset = viewport.getSelectionGroup().getStartRes(); - for(int i=0; i