X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FAppVarna.java;h=3a647169a8eb2ead5c32b31e7536cee61c0703d2;hb=e1aa3fdd1ca82abf5acc0cd3c2b86a5ca1083941;hp=9316b05890f589c9c0d7302434c67804083ec488;hpb=7aef14d879f7bfb8af464a6b7700a99413eab0c6;p=jalview.git diff --git a/src/jalview/gui/AppVarna.java b/src/jalview/gui/AppVarna.java index 9316b05..3a64716 100644 --- a/src/jalview/gui/AppVarna.java +++ b/src/jalview/gui/AppVarna.java @@ -20,6 +20,23 @@ */ package jalview.gui; +import jalview.analysis.AlignSeq; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.RnaViewerModel; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; +import jalview.ext.varna.RnaModel; +import jalview.structure.SecondaryStructureListener; +import jalview.structure.SelectionListener; +import jalview.structure.SelectionSource; +import jalview.structure.StructureSelectionManager; +import jalview.structure.VamsasSource; +import jalview.util.Comparison; +import jalview.util.MessageManager; +import jalview.util.ShiftList; + import java.awt.BorderLayout; import java.awt.Color; import java.util.Collection; @@ -27,8 +44,6 @@ import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.swing.JInternalFrame; import javax.swing.JSplitPane; @@ -46,28 +61,12 @@ import fr.orsay.lri.varna.models.annotations.HighlightRegionAnnotation; import fr.orsay.lri.varna.models.rna.ModeleBase; import fr.orsay.lri.varna.models.rna.RNA; -import jalview.analysis.AlignSeq; -import jalview.datamodel.AlignmentAnnotation; -import jalview.datamodel.ColumnSelection; -import jalview.datamodel.RnaViewerModel; -import jalview.datamodel.SequenceGroup; -import jalview.datamodel.SequenceI; -import jalview.ext.varna.RnaModel; -import jalview.structure.SecondaryStructureListener; -import jalview.structure.SelectionListener; -import jalview.structure.SelectionSource; -import jalview.structure.StructureSelectionManager; -import jalview.structure.VamsasSource; -import jalview.util.Comparison; -import jalview.util.MessageManager; -import jalview.util.ShiftList; - -public class AppVarna extends JInternalFrame implements SelectionListener, - SecondaryStructureListener, InterfaceVARNASelectionListener, - VamsasSource +public class AppVarna extends JInternalFrame + implements SelectionListener, SecondaryStructureListener, + InterfaceVARNASelectionListener, VamsasSource { - private static final Pattern PAIRS_PATTERN = Pattern - .compile("[^([{<>}])]"); + private static final byte[] PAIRS = new byte[] { '(', ')', '[', ']', '{', + '}', '<', '>' }; private AppVarnaBinding vab; @@ -121,6 +120,15 @@ public class AppVarna extends JInternalFrame implements SelectionListener, } } + /** + * highlight a region from start to end (inclusive) on rna + * + * @param rna + * @param start + * - first base pair index (from 0) + * @param end + * - last base pair index (from 0) + */ public void highlightRegion(RNA rna, int start, int end) { clearLastSelection(); @@ -167,8 +175,6 @@ public class AppVarna extends JInternalFrame implements SelectionListener, /** * Constructor * - * @param sname - * a descriptive name * @param seq * the RNA sequence * @param aa @@ -176,50 +182,28 @@ public class AppVarna extends JInternalFrame implements SelectionListener, * @param ap * the AlignmentPanel creating this object */ - public AppVarna(String sname, SequenceI seq, AlignmentAnnotation aa, - AlignmentPanel ap) + public AppVarna(SequenceI seq, AlignmentAnnotation aa, AlignmentPanel ap) { this(ap); - String name = sname + " trimmed to " + seq.getName(); - String fullName = MessageManager.formatMessage("label.varna_params", + String sname = aa.sequenceRef == null + ? "secondary structure (alignment)" + : seq.getName() + " structure"; + String theTitle = sname + + (aa.sequenceRef == null ? " trimmed to " + seq.getName() + : ""); + theTitle = MessageManager.formatMessage("label.varna_params", new String[] - { name }); - setTitle(fullName); - - /* - * if (!aa.isValidStruc()) { throw new - * IllegalArgumentException("Invalid RNA structure annotation"); } final - * String struc = aa.getRNAStruc(); - * - * String strucseq = seq.getSequenceAsString(); - * - * String gappedTitle = sname + " (with gaps)"; String rnaTitle = - * gappedTitle; RNA gapped = new RNA(rnaTitle); try { - * gapped.setRNA(strucseq, replaceOddGaps(struc)); } catch - * (ExceptionUnmatchedClosingParentheses e2) { e2.printStackTrace(); } catch - * (ExceptionFileFormatOrSyntax e3) { e3.printStackTrace(); } - * models.put(gapped, new RnaModel(rnaTitle, aa, seq, gapped, true, null)); - * - * String trimmedTitle = "trimmed " + sname; rnaTitle = trimmedTitle; RNA - * trimmed = trimRNA(gapped, rnaTitle); models.put(trimmed, new - * RnaModel(rnaTitle, aa, seq, trimmed, false, null)); - */ - // vab = new AppVarnaBinding(Arrays.asList(new RNA[] - // { trimmed, gapped })); - // vab = new AppVarnaBinding(); - // // String seqName = seq.getName(); - // // String name = sname + " trimmed to " + seqName; - // initVarna(name); + { theTitle }); + setTitle(theTitle); String gappedTitle = sname + " (with gaps)"; - RnaModel gappedModel = new RnaModel(gappedTitle, aa, seq, null, true, - null); + RnaModel gappedModel = new RnaModel(gappedTitle, aa, seq, null, true); addModel(gappedModel, gappedTitle); String trimmedTitle = "trimmed " + sname; RnaModel trimmedModel = new RnaModel(trimmedTitle, aa, seq, null, - false, null); + false); addModel(trimmedModel, trimmedTitle); vab.setSelectedIndex(0); } @@ -286,13 +270,6 @@ public class AppVarna extends JInternalFrame implements SelectionListener, showPanel(true); } - public String replaceOddGaps(String oldStr) - { - Matcher matcher = PAIRS_PATTERN.matcher(oldStr); - String newStr = matcher.replaceAll("."); - return newStr; - } - /** * Constructs a new RNA model from the given one, without gaps. Also * calculates and saves a 'shift list' @@ -308,7 +285,8 @@ public class AppVarna extends JInternalFrame implements SelectionListener, RNA rnaTrim = new RNA(name); try { - rnaTrim.setRNA(rna.getSeq(), replaceOddGaps(rna.getStructDBN())); + String structDBN = rna.getStructDBN(true); + rnaTrim.setRNA(rna.getSeq(), replaceOddGaps(structDBN)); } catch (ExceptionUnmatchedClosingParentheses e2) { e2.printStackTrace(); @@ -319,7 +297,7 @@ public class AppVarna extends JInternalFrame implements SelectionListener, String seq = rnaTrim.getSeq(); StringBuilder struc = new StringBuilder(256); - struc.append(rnaTrim.getStructDBN()); + struc.append(rnaTrim.getStructDBN(true)); int ofstart = -1; int sleng = seq.length(); @@ -332,7 +310,7 @@ public class AppVarna extends JInternalFrame implements SelectionListener, ofstart = i; } /* - * mark base or base pair in the structure with * + * mark base or base & pair in the structure with * */ if (!rnaTrim.findPair(i).isEmpty()) { @@ -409,32 +387,35 @@ public class AppVarna extends JInternalFrame implements SelectionListener, * selected RNA in the VARNA window is highlighted at the specific position. * To be able to remove it before the next highlight it is saved in * _lastHighlight + * + * @param sequence + * @param index + * the aligned sequence position (base 0) + * @param position + * the dataset sequence position (base 1) */ @Override - public void mouseOverSequence(SequenceI sequence, int index) + public void mouseOverSequence(SequenceI sequence, final int index, + final int position) { RNA rna = vab.getSelectedRNA(); if (rna == null) { return; } - if (models.get(rna).seq == sequence) + RnaModel rnaModel = models.get(rna); + if (rnaModel.seq == sequence) { - ShiftList shift = offsets.get(rna); - if (shift != null) - { - // System.err.print("Orig pos:"+index); - index = shift.shift(index); - // System.err.println("\nFinal pos:"+index); - } - mouseOverHighlighter.highlightRegion(rna, index, index); + int highlightPos = rnaModel.gapped ? index + : position - sequence.getStart(); + mouseOverHighlighter.highlightRegion(rna, highlightPos, highlightPos); vab.updateSelectedRNA(rna); } } @Override public void selection(SequenceGroup seqsel, ColumnSelection colsel, - SelectionSource source) + HiddenColumns hidden, SelectionSource source) { if (source != ap.av) { @@ -447,18 +428,31 @@ public class AppVarna extends JInternalFrame implements SelectionListener, { return; } - if (seqsel != null && seqsel.getSize() > 0) + + RnaModel rnaModel = models.get(rna); + + if (seqsel != null && seqsel.getSize() > 0 + && seqsel.contains(rnaModel.seq)) { int start = seqsel.getStartRes(), end = seqsel.getEndRes(); - ShiftList shift = offsets.get(rna); - if (shift != null) + if (rnaModel.gapped) + { + ShiftList shift = offsets.get(rna); + if (shift != null) + { + start = shift.shift(start); + end = shift.shift(end); + } + } + else { - start = shift.shift(start); - end = shift.shift(end); + start = rnaModel.seq.findPosition(start) - rnaModel.seq.getStart(); + end = rnaModel.seq.findPosition(end) - rnaModel.seq.getStart(); } + selectionHighlighter.highlightRegion(rna, start, end); - selectionHighlighter.getLastHighlight().setOutlineColor( - seqsel.getOutlineColour()); + selectionHighlighter.getLastHighlight() + .setOutlineColor(seqsel.getOutlineColour()); // TODO - translate column markings to positions on structure if present. vab.updateSelectedRNA(rna); } @@ -493,7 +487,8 @@ public class AppVarna extends JInternalFrame implements SelectionListener, } @Override - public void onSelectionChanged(BaseList arg0, BaseList arg1, BaseList arg2) + public void onSelectionChanged(BaseList arg0, BaseList arg1, + BaseList arg2) { // TODO translate selected regions in VARNA to a selection on the // alignpanel. @@ -610,36 +605,8 @@ public class AppVarna extends JInternalFrame implements SelectionListener, { if (!model.ann.isValidStruc()) { - throw new IllegalArgumentException("Invalid RNA structure annotation"); - } - - /* - * loaded from project file with Varna session data - */ - if (model.varnaSession != null) - { - try - { - FullBackup fromSession = vab.vp.loadSession(model.varnaSession); - vab.addStructure(fromSession.rna, fromSession.config); - RNA rna = fromSession.rna; - // copy the model, but now including the RNA object - RnaModel newModel = new RnaModel(model.title, model.ann, model.seq, - rna, model.gapped, model.varnaSession); - if (!model.gapped) - { - registerOffset(rna, buildOffset(model.seq)); - } - // TODO and add mapping (offsets) - models.put(rna, newModel); - // capture rna selection state when saved - selectionHighlighter = new VarnaHighlighter(rna); - return fromSession.rna; - } catch (ExceptionLoadingFailed e) - { - e.printStackTrace(); - return null; - } + throw new IllegalArgumentException( + "Invalid RNA structure annotation"); } /* @@ -666,7 +633,7 @@ public class AppVarna extends JInternalFrame implements SelectionListener, rna = trimRNA(rna, modelName); } models.put(rna, new RnaModel(modelName, model.ann, model.seq, rna, - model.gapped, null)); + model.gapped)); vab.addStructure(rna); return rna; } @@ -680,14 +647,14 @@ public class AppVarna extends JInternalFrame implements SelectionListener, protected ShiftList buildOffset(SequenceI seq) { // TODO refactor to avoid duplication with trimRNA() + // TODO JAL-1789 bugs in use of ShiftList here ShiftList offset = new ShiftList(); int ofstart = -1; int sleng = seq.getLength(); - char[] seqChars = seq.getSequence(); for (int i = 0; i < sleng; i++) { - if (Comparison.isGap(seqChars[i])) + if (Comparison.isGap(seq.getCharAt(i))) { if (ofstart == -1) { @@ -715,10 +682,101 @@ public class AppVarna extends JInternalFrame implements SelectionListener, /** * Set the selected index in the model selection list * - * @param selectedRna + * @param selectedIndex + */ + public void setInitialSelection(final int selectedIndex) + { + /* + * empirically it needs a second for Varna/AWT to finish loading/drawing + * models for this to work; SwingUtilities.invokeLater _not_ a solution; + * explanation and/or better solution welcome! + */ + synchronized (this) + { + try + { + wait(1000); + } catch (InterruptedException e) + { + // meh + } + } + vab.setSelectedIndex(selectedIndex); + } + + /** + * Add a model with associated Varna session file + * + * @param rna + * @param modelName + */ + public RNA addModelSession(RnaModel model, String modelName, + String sessionFile) + { + if (!model.ann.isValidStruc()) + { + throw new IllegalArgumentException( + "Invalid RNA structure annotation"); + } + + try + { + FullBackup fromSession = vab.vp.loadSession(sessionFile); + vab.addStructure(fromSession.rna, fromSession.config); + RNA rna = fromSession.rna; + // copy the model, but now including the RNA object + RnaModel newModel = new RnaModel(model.title, model.ann, model.seq, + rna, model.gapped); + if (!model.gapped) + { + registerOffset(rna, buildOffset(model.seq)); + } + models.put(rna, newModel); + // capture rna selection state when saved + selectionHighlighter = new VarnaHighlighter(rna); + return fromSession.rna; + } catch (ExceptionLoadingFailed e) + { + System.err + .println("Error restoring Varna session: " + e.getMessage()); + return null; + } + } + + /** + * Replace everything except RNA secondary structure characters with a period + * + * @param s + * @return */ - public void setSelectedIndex(int selectedRna) + public static String replaceOddGaps(String s) { - vab.setSelectedIndex(selectedRna); + if (s == null) + { + return null; + } + + // this is measured to be 10 times faster than a regex replace + boolean changed = false; + byte[] bytes = s.getBytes(); + for (int i = 0; i < bytes.length; i++) + { + boolean ok = false; + // todo check for ((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z')) if + // wanted also + for (int j = 0; !ok && (j < PAIRS.length); j++) + { + if (bytes[i] == PAIRS[j]) + { + ok = true; + } + } + if (!ok) + { + bytes[i] = '.'; + changed = true; + } + } + return changed ? new String(bytes) : s; } }