/* * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2) * Copyright (C) 2014 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. * * 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 Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ /* * Jalview - A Sequence Alignment Editor and Viewer * Copyright (C) 2007 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 * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package jalview.gui; import jalview.analysis.AlignmentUtils; import jalview.analysis.AlignmentUtils.MappingResult; import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder; import jalview.analysis.NJTree; import jalview.api.AlignViewportI; import jalview.api.ViewStyleI; import jalview.bin.Cache; import jalview.commands.CommandI; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; import jalview.datamodel.PDBEntry; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.schemes.ColourSchemeProperty; import jalview.schemes.UserColourScheme; import jalview.structure.CommandListener; import jalview.structure.SelectionSource; import jalview.structure.StructureSelectionManager; import jalview.structure.VamsasSource; import jalview.util.MessageManager; import jalview.viewmodel.AlignmentViewport; import jalview.ws.params.AutoCalcSetting; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.Rectangle; import java.io.File; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.Hashtable; import java.util.Set; import java.util.Vector; import javax.swing.JInternalFrame; import javax.swing.JOptionPane; /** * DOCUMENT ME! * * @author $author$ * @version $Revision: 1.141 $ */ public class AlignViewport extends AlignmentViewport implements SelectionSource, VamsasSource, AlignViewportI, CommandListener { int startRes; int endRes; int startSeq; int endSeq; SequenceAnnotationOrder sortAnnotationsBy = null; Font font; NJTree currentTree = null; boolean cursorMode = false; boolean antiAlias = false; Rectangle explodedPosition; String viewName; boolean gatherViewsHere = false; private Deque historyList = new ArrayDeque(); private Deque redoList = new ArrayDeque(); private AnnotationColumnChooser annotationColumnSelectionState; /** * Creates a new AlignViewport object. * * @param al * alignment to view */ public AlignViewport(AlignmentI al) { setAlignment(al); init(); } /** * Create a new AlignViewport object with a specific sequence set ID * * @param al * @param seqsetid * (may be null - but potential for ambiguous constructor exception) */ public AlignViewport(AlignmentI al, String seqsetid) { this(al, seqsetid, null); } public AlignViewport(AlignmentI al, String seqsetid, String viewid) { sequenceSetID = seqsetid; viewId = viewid; // TODO remove these once 2.4.VAMSAS release finished if (Cache.log != null && Cache.log.isDebugEnabled() && seqsetid != null) { Cache.log.debug("Setting viewport's sequence set id : " + sequenceSetID); } if (Cache.log != null && Cache.log.isDebugEnabled() && viewId != null) { Cache.log.debug("Setting viewport's view id : " + viewId); } setAlignment(al); init(); } /** * Create a new AlignViewport with hidden regions * * @param al * AlignmentI * @param hiddenColumns * ColumnSelection */ public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns) { setAlignment(al); if (hiddenColumns != null) { colSel = hiddenColumns; } init(); } /** * New viewport with hidden columns and an existing sequence set id * * @param al * @param hiddenColumns * @param seqsetid * (may be null) */ public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns, String seqsetid) { this(al, hiddenColumns, seqsetid, null); } /** * New viewport with hidden columns and an existing sequence set id and viewid * * @param al * @param hiddenColumns * @param seqsetid * (may be null) * @param viewid * (may be null) */ public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns, String seqsetid, String viewid) { sequenceSetID = seqsetid; viewId = viewid; // TODO remove these once 2.4.VAMSAS release finished if (Cache.log != null && Cache.log.isDebugEnabled() && seqsetid != null) { Cache.log.debug("Setting viewport's sequence set id : " + sequenceSetID); } if (Cache.log != null && Cache.log.isDebugEnabled() && viewId != null) { Cache.log.debug("Setting viewport's view id : " + viewId); } setAlignment(al); if (hiddenColumns != null) { colSel = hiddenColumns; } init(); } private void applyViewProperties() { antiAlias = Cache.getDefault("ANTI_ALIAS", false); viewStyle.setShowJVSuffix(Cache.getDefault("SHOW_JVSUFFIX", true)); setShowAnnotation(Cache.getDefault("SHOW_ANNOTATIONS", true)); setRightAlignIds(Cache.getDefault("RIGHT_ALIGN_IDS", false)); setCentreColumnLabels(Cache.getDefault("CENTRE_COLUMN_LABELS", false)); autoCalculateConsensus = Cache.getDefault("AUTO_CALC_CONSENSUS", true); setPadGaps(Cache.getDefault("PAD_GAPS", true)); setShowNPFeats(Cache.getDefault("SHOW_NPFEATS_TOOLTIP", true)); setShowDBRefs(Cache.getDefault("SHOW_DBREFS_TOOLTIP", true)); viewStyle.setSeqNameItalics(Cache.getDefault("ID_ITALICS", true)); viewStyle.setWrapAlignment(Cache.getDefault("WRAP_ALIGNMENT", false)); viewStyle.setShowUnconserved(Cache .getDefault("SHOW_UNCONSERVED", false)); sortByTree = Cache.getDefault("SORT_BY_TREE", false); followSelection = Cache.getDefault("FOLLOW_SELECTIONS", true); sortAnnotationsBy = SequenceAnnotationOrder.valueOf(Cache.getDefault( Preferences.SORT_ANNOTATIONS, SequenceAnnotationOrder.NONE.name())); showAutocalculatedAbove = Cache.getDefault( Preferences.SHOW_AUTOCALC_ABOVE, false); } void init() { this.startRes = 0; this.endRes = alignment.getWidth() - 1; this.startSeq = 0; this.endSeq = alignment.getHeight() - 1; applyViewProperties(); String fontName = Cache.getDefault("FONT_NAME", "SansSerif"); String fontStyle = Cache.getDefault("FONT_STYLE", Font.PLAIN + ""); String fontSize = Cache.getDefault("FONT_SIZE", "10"); int style = 0; if (fontStyle.equals("bold")) { style = 1; } else if (fontStyle.equals("italic")) { style = 2; } setFont(new Font(fontName, style, Integer.parseInt(fontSize))); alignment .setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0)); // We must set conservation and consensus before setting colour, // as Blosum and Clustal require this to be done if (hconsensus == null && !isDataset) { if (!alignment.isNucleotide()) { showConservation = Cache.getDefault("SHOW_CONSERVATION", true); showQuality = Cache.getDefault("SHOW_QUALITY", true); showGroupConservation = Cache.getDefault("SHOW_GROUP_CONSERVATION", false); } showConsensusHistogram = Cache.getDefault("SHOW_CONSENSUS_HISTOGRAM", true); showSequenceLogo = Cache.getDefault("SHOW_CONSENSUS_LOGO", false); normaliseSequenceLogo = Cache.getDefault("NORMALISE_CONSENSUS_LOGO", false); showGroupConsensus = Cache.getDefault("SHOW_GROUP_CONSENSUS", false); showConsensus = Cache.getDefault("SHOW_IDENTITY", true); } initAutoAnnotation(); if (jalview.bin.Cache.getProperty("DEFAULT_COLOUR") != null) { globalColourScheme = ColourSchemeProperty.getColour(alignment, jalview.bin.Cache.getProperty("DEFAULT_COLOUR")); if (globalColourScheme instanceof UserColourScheme) { globalColourScheme = UserDefinedColours.loadDefaultColours(); ((UserColourScheme) globalColourScheme).setThreshold(0, isIgnoreGapsConsensus()); } if (globalColourScheme != null) { globalColourScheme.setConsensus(hconsensus); } } } /** * get the consensus sequence as displayed under the PID consensus annotation * row. * * @return consensus sequence as a new sequence object */ public SequenceI getConsensusSeq() { if (consensus == null) { updateConsensus(null); } if (consensus == null) { return null; } StringBuffer seqs = new StringBuffer(); for (int i = 0; i < consensus.annotations.length; i++) { if (consensus.annotations[i] != null) { if (consensus.annotations[i].description.charAt(0) == '[') { seqs.append(consensus.annotations[i].description.charAt(1)); } else { seqs.append(consensus.annotations[i].displayCharacter); } } } SequenceI sq = new Sequence("Consensus", seqs.toString()); sq.setDescription("Percentage Identity Consensus " + ((ignoreGapsInConsensusCalculation) ? " without gaps" : "")); return sq; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public int getStartRes() { return startRes; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public int getEndRes() { return endRes; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public int getStartSeq() { return startSeq; } /** * DOCUMENT ME! * * @param res * DOCUMENT ME! */ public void setStartRes(int res) { this.startRes = res; } /** * DOCUMENT ME! * * @param seq * DOCUMENT ME! */ public void setStartSeq(int seq) { this.startSeq = seq; } /** * DOCUMENT ME! * * @param res * DOCUMENT ME! */ public void setEndRes(int res) { if (res > (alignment.getWidth() - 1)) { // log.System.out.println(" Corrected res from " + res + " to maximum " + // (alignment.getWidth()-1)); res = alignment.getWidth() - 1; } if (res < 0) { res = 0; } this.endRes = res; } /** * DOCUMENT ME! * * @param seq * DOCUMENT ME! */ public void setEndSeq(int seq) { if (seq > alignment.getHeight()) { seq = alignment.getHeight(); } if (seq < 0) { seq = 0; } this.endSeq = seq; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public int getEndSeq() { return endSeq; } boolean validCharWidth; /** * update view settings with the given font. You may need to call * alignPanel.fontChanged to update the layout geometry */ public void setFont(Font f) { font = f; Container c = new Container(); java.awt.FontMetrics fm = c.getFontMetrics(font); int w = viewStyle.getCharWidth(), ww = fm.charWidth('M'), h = viewStyle .getCharHeight(); setCharHeight(fm.getHeight()); setCharWidth(ww); viewStyle.setFontName(font.getName()); viewStyle.setFontStyle(font.getStyle()); viewStyle.setFontSize(font.getSize()); validCharWidth = true; } @Override public void setViewStyle(ViewStyleI settingsForView) { super.setViewStyle(settingsForView); setFont(new Font(viewStyle.getFontName(), viewStyle.getFontStyle(), viewStyle.getFontSize())); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public Font getFont() { return font; } /** * DOCUMENT ME! * * @param align * DOCUMENT ME! */ public void setAlignment(AlignmentI align) { if (alignment != null && alignment.getCodonFrames() != null) { StructureSelectionManager.getStructureSelectionManager( Desktop.instance).removeMappings(alignment.getCodonFrames()); } this.alignment = align; if (alignment != null && alignment.getCodonFrames() != null) { StructureSelectionManager.getStructureSelectionManager( Desktop.instance).addMappings(alignment.getCodonFrames()); } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public char getGapCharacter() { return getAlignment().getGapCharacter(); } /** * DOCUMENT ME! * * @param gap * DOCUMENT ME! */ public void setGapCharacter(char gap) { if (getAlignment() != null) { getAlignment().setGapCharacter(gap); } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public ColumnSelection getColumnSelection() { return colSel; } /** * DOCUMENT ME! * * @param tree * DOCUMENT ME! */ public void setCurrentTree(NJTree tree) { currentTree = tree; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public NJTree getCurrentTree() { return currentTree; } /** * returns the visible column regions of the alignment * * @param selectedRegionOnly * true to just return the contigs intersecting with the selected * area * @return */ public int[] getViewAsVisibleContigs(boolean selectedRegionOnly) { int[] viscontigs = null; int start = 0, end = 0; if (selectedRegionOnly && selectionGroup != null) { start = selectionGroup.getStartRes(); end = selectionGroup.getEndRes() + 1; } else { end = alignment.getWidth(); } viscontigs = colSel.getVisibleContigs(start, end); return viscontigs; } /** * get hash of undo and redo list for the alignment * * @return long[] { historyList.hashCode, redoList.hashCode }; */ public long[] getUndoRedoHash() { // TODO: JAL-1126 if (historyList == null || redoList == null) { return new long[] { -1, -1 }; } return new long[] { historyList.hashCode(), this.redoList.hashCode() }; } /** * test if a particular set of hashcodes are different to the hashcodes for * the undo and redo list. * * @param undoredo * the stored set of hashcodes as returned by getUndoRedoHash * @return true if the hashcodes differ (ie the alignment has been edited) or * the stored hashcode array differs in size */ public boolean isUndoRedoHashModified(long[] undoredo) { if (undoredo == null) { return true; } long[] cstate = getUndoRedoHash(); if (cstate.length != undoredo.length) { return true; } for (int i = 0; i < cstate.length; i++) { if (cstate[i] != undoredo[i]) { return true; } } return false; } /** * when set, view will scroll to show the highlighted position */ public boolean followHighlight = true; /** * @return true if view should scroll to show the highlighted region of a * sequence * @return */ public boolean getFollowHighlight() { return followHighlight; } public boolean followSelection = true; /** * @return true if view selection should always follow the selections * broadcast by other selection sources */ public boolean getFollowSelection() { return followSelection; } /** * Send the current selection to be broadcast to any selection listeners. */ public void sendSelection() { jalview.structure.StructureSelectionManager .getStructureSelectionManager(Desktop.instance).sendSelection( new SequenceGroup(getSelectionGroup()), new ColumnSelection(getColumnSelection()), this); } /** * return the alignPanel containing the given viewport. Use this to get the * components currently handling the given viewport. * * @param av * @return null or an alignPanel guaranteed to have non-null alignFrame * reference */ public AlignmentPanel getAlignPanel() { AlignmentPanel[] aps = PaintRefresher.getAssociatedPanels(this .getSequenceSetId()); for (int p = 0; aps != null && p < aps.length; p++) { if (aps[p].av == this) { return aps[p]; } } return null; } public boolean getSortByTree() { return sortByTree; } public void setSortByTree(boolean sort) { sortByTree = sort; } /** * synthesize a column selection if none exists so it covers the given * selection group. if wholewidth is false, no column selection is made if the * selection group covers the whole alignment width. * * @param sg * @param wholewidth */ public void expandColSelection(SequenceGroup sg, boolean wholewidth) { int sgs, sge; if (sg != null && (sgs = sg.getStartRes()) >= 0 && sg.getStartRes() <= (sge = sg.getEndRes()) && (colSel == null || colSel.getSelected() == null || colSel .getSelected().size() == 0)) { if (!wholewidth && alignment.getWidth() == (1 + sge - sgs)) { // do nothing return; } if (colSel == null) { colSel = new ColumnSelection(); } for (int cspos = sg.getStartRes(); cspos <= sg.getEndRes(); cspos++) { colSel.addElement(cspos); } } } public StructureSelectionManager getStructureSelectionManager() { return StructureSelectionManager .getStructureSelectionManager(Desktop.instance); } /** * * @param pdbEntries * @return a series of SequenceI arrays, one for each PDBEntry, listing which * sequence in the alignment holds a reference to it */ public SequenceI[][] collateForPDB(PDBEntry[] pdbEntries) { ArrayList seqvectors = new ArrayList(); for (PDBEntry pdb : pdbEntries) { ArrayList seqs = new ArrayList(); for (int i = 0; i < alignment.getHeight(); i++) { Vector pdbs = alignment.getSequenceAt(i).getDatasetSequence() .getPDBId(); if (pdbs == null) { continue; } SequenceI sq; for (int p = 0; p < pdbs.size(); p++) { PDBEntry p1 = (PDBEntry) pdbs.elementAt(p); if (p1.getId().equals(pdb.getId())) { if (!seqs.contains(sq = alignment.getSequenceAt(i))) { seqs.add(sq); } continue; } } } seqvectors.add(seqs.toArray(new SequenceI[seqs.size()])); } return seqvectors.toArray(new SequenceI[seqvectors.size()][]); } public boolean isNormaliseSequenceLogo() { return normaliseSequenceLogo; } public void setNormaliseSequenceLogo(boolean state) { normaliseSequenceLogo = state; } /** * * @return true if alignment characters should be displayed */ public boolean isValidCharWidth() { return validCharWidth; } private Hashtable calcIdParams = new Hashtable(); private boolean showAutocalculatedAbove; public AutoCalcSetting getCalcIdSettingsFor(String calcId) { return calcIdParams.get(calcId); } public void setCalcIdSettingsFor(String calcId, AutoCalcSetting settings, boolean needsUpdate) { calcIdParams.put(calcId, settings); // TODO: create a restart list to trigger any calculations that need to be // restarted after load // calculator.getRegisteredWorkersOfClass(settings.getWorkerClass()) if (needsUpdate) { Cache.log.debug("trigger update for " + calcId); } } protected SequenceAnnotationOrder getSortAnnotationsBy() { return sortAnnotationsBy; } protected void setSortAnnotationsBy(SequenceAnnotationOrder sortAnnotationsBy) { this.sortAnnotationsBy = sortAnnotationsBy; } protected boolean isShowAutocalculatedAbove() { return showAutocalculatedAbove; } protected void setShowAutocalculatedAbove(boolean showAutocalculatedAbove) { this.showAutocalculatedAbove = showAutocalculatedAbove; } /** * Method called when another alignment's edit (or possibly other) command is * broadcast to here. * * To allow for sequence mappings (e.g. protein to cDNA), we have to first * 'unwind' the command on the source sequences (in simulation, not in fact), * and then for each edit in turn: *
    *
  • compute the equivalent edit on the mapped sequences
  • *
  • apply the mapped edit
  • *
  • 'apply' the source edit to the working copy of the source sequences
  • *
* * @param command * @param undo * @param ssm */ @Override public void mirrorCommand(CommandI command, boolean undo, StructureSelectionManager ssm, VamsasSource source) { /* * ...work in progress... do nothing unless we are a 'complement' of the * source May replace this with direct calls not via SSM. */ if (source instanceof AlignViewportI && ((AlignViewportI) source).getCodingComplement() == this) { // ok to continue; } else { return; } CommandI mappedCommand = ssm.mapCommand(command, undo, getAlignment(), getGapCharacter()); if (mappedCommand != null) { AlignmentI[] views = getAlignPanel().alignFrame.getViewAlignments(); mappedCommand.doCommand(views); getAlignPanel().alignmentChanged(); } } @Override public VamsasSource getVamsasSource() { return this; } /** * Add one command to the command history list. * * @param command */ public void addToHistoryList(CommandI command) { if (this.historyList != null) { this.historyList.push(command); broadcastCommand(command, false); } } protected void broadcastCommand(CommandI command, boolean undo) { getStructureSelectionManager().commandPerformed(command, undo, getVamsasSource()); } /** * Add one command to the command redo list. * * @param command */ public void addToRedoList(CommandI command) { if (this.redoList != null) { this.redoList.push(command); } broadcastCommand(command, true); } /** * Clear the command redo list. */ public void clearRedoList() { if (this.redoList != null) { this.redoList.clear(); } } public void setHistoryList(Deque list) { this.historyList = list; } public Deque getHistoryList() { return this.historyList; } public void setRedoList(Deque list) { this.redoList = list; } public Deque getRedoList() { return this.redoList; } /** * Add the sequences from the given alignment to this viewport. Optionally, * may give the user the option to open a new frame, or split panel, with cDNA * and protein linked. * * @param al * @param title */ public void addAlignment(AlignmentI al, String title) { // TODO: promote to AlignViewportI? applet CutAndPasteTransfer is different // JBPComment: title is a largely redundant parameter at the moment // JBPComment: this really should be an 'insert/pre/append' controller // JBPComment: but the DNA/Protein check makes it a bit more complex // refactored from FileLoader / CutAndPasteTransfer / SequenceFetcher with // this comment: // TODO: create undo object for this JAL-1101 /* * If one alignment is protein and one nucleotide, with at least one * sequence name in common, offer to open a linked alignment. */ if (getAlignment().isNucleotide() != al.isNucleotide()) { // TODO: JAL-845 try a bit harder to link up imported sequences final Set sequenceNames = getAlignment().getSequenceNames(); sequenceNames.retainAll(al.getSequenceNames()); if (!sequenceNames.isEmpty()) // at least one sequence name in both { if (openLinkedAlignment(al, title)) { return; } } } // TODO: JAL-407 regardless of above - identical sequences (based on ID and // provenance) should share the same dataset sequence for (int i = 0; i < al.getHeight(); i++) { getAlignment().addSequence(al.getSequenceAt(i)); } // TODO this call was done by SequenceFetcher but not FileLoader or // CutAndPasteTransfer. Is it needed? // JBPComment: this repositions the view to show the new sequences // JBPComment: so it is needed for UX setEndSeq(getAlignment().getHeight()); firePropertyChange("alignment", null, getAlignment().getSequences()); } /** * Show a dialog with the option to open and link (cDNA <-> protein) as a new * alignment. Returns true if the new alignment was opened, false if not, * because the user declined the offer. * * @param title */ protected boolean openLinkedAlignment(AlignmentI al, String title) { String[] options = new String[] { MessageManager.getString("action.no"), MessageManager.getString("label.split_window"), MessageManager.getString("label.new_window"), }; final String question = JvSwingUtils.wrapTooltip(true, MessageManager.getString("label.open_linked_alignment?")); int response = JOptionPane.showOptionDialog(Desktop.desktop, question, MessageManager.getString("label.open_linked_alignment"), JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]); if (response != 1 && response != 2) { return false; } final boolean openSplitPane = (response == 1); final boolean openInNewWindow = (response == 2); /* * Create the AlignFrame first (which creates the new alignment's datasets), * before attempting sequence mapping. */ AlignFrame newAlignFrame = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); newAlignFrame.setTitle(title); /* * Identify protein and dna alignments. Make a copy of this one if opening * in a new split pane. */ AlignmentI thisAlignment = openSplitPane ? new Alignment(getAlignment()) : getAlignment(); AlignmentI protein = al.isNucleotide() ? thisAlignment : al; final AlignmentI cdna = al.isNucleotide() ? al : thisAlignment; newAlignFrame.statusBar.setText(MessageManager.formatMessage( "label.successfully_loaded_file", new Object[] { title })); // TODO if we want this (e.g. to enable reload of the alignment from file), // we will need to add parameters to the stack. // if (!protocol.equals(AppletFormatAdapter.PASTE)) // { // alignFrame.setFileName(file, format); // } if (openInNewWindow) { Desktop.addInternalFrame(newAlignFrame, title, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); } /* * Try to find mappings for at least one sequence. Any mappings made will be * added to the protein alignment. */ MappingResult mapped = AlignmentUtils.mapProteinToCdna(protein, cdna); final StructureSelectionManager ssm = StructureSelectionManager .getStructureSelectionManager(Desktop.instance); if (mapped != MappingResult.Mapped) { /* * No mapping possible - warn the user, but leave window open. */ final String msg = JvSwingUtils.wrapTooltip(true, MessageManager.getString("label.mapping_failed")); JOptionPane.showInternalMessageDialog(Desktop.desktop, msg, MessageManager.getString("label.no_mappings"), JOptionPane.WARNING_MESSAGE); } try { newAlignFrame.setMaximum(jalview.bin.Cache.getDefault( "SHOW_FULLSCREEN", false)); } catch (java.beans.PropertyVetoException ex) { } if (openSplitPane) { // TODO: move this kind of constructor stuff to a factory/controller // method ? /* * Open in split pane. DNA sequence above, protein below. */ AlignFrame copyMe = new AlignFrame(thisAlignment, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); copyMe.setTitle(getAlignPanel().alignFrame.getTitle()); final AlignFrame proteinFrame = al.isNucleotide() ? copyMe : newAlignFrame; final AlignFrame cdnaFrame = al.isNucleotide() ? newAlignFrame : copyMe; protein = proteinFrame.viewport.getAlignment(); cdnaFrame.setVisible(true); proteinFrame.setVisible(true); String sep = String.valueOf(File.separatorChar); String proteinShortName = proteinFrame.getTitle().substring( proteinFrame.getTitle().lastIndexOf(sep) + 1); String dnaShortName = cdnaFrame.getTitle().substring( cdnaFrame.getTitle().lastIndexOf(sep) + 1); String linkedTitle = MessageManager.formatMessage( "label.linked_view_title", dnaShortName, proteinShortName); JInternalFrame splitFrame = new SplitFrame(cdnaFrame, proteinFrame); Desktop.addInternalFrame(splitFrame, linkedTitle, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); /* * Set the frames to listen for each other's edit and sort commands. */ ssm.addCommandListener(cdnaFrame.getViewport()); ssm.addCommandListener(proteinFrame.getViewport()); /* * 'Coding complement' (dna/protein) views will mirror each others' edits, * selections, sorting etc as decided from time to time by the relevant * authorities. */ proteinFrame.getViewport().setCodingComplement(cdnaFrame.getViewport()); } /* * Register the mappings (held on the protein alignment) with the * StructureSelectionManager (for mouseover linking). */ ssm.addMappings(protein.getCodonFrames()); return true; } public AnnotationColumnChooser getAnnotationColumnSelectionState() { return annotationColumnSelectionState; } public void setAnnotationColumnSelectionState( AnnotationColumnChooser currentAnnotationColumnSelectionState) { this.annotationColumnSelectionState = currentAnnotationColumnSelectionState; } @Override public void setIdWidth(int i) { super.setIdWidth(i); AlignmentPanel ap = getAlignPanel(); if (ap != null) { // modify GUI elements to reflect geometry change Dimension idw = getAlignPanel().getIdPanel().getIdCanvas() .getPreferredSize(); idw.width = i; getAlignPanel().getIdPanel().getIdCanvas().setPreferredSize(idw); } } }