*/
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;
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;
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;
}
}
+ /**
+ * 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();
/**
* Constructor
*
- * @param sname
- * a descriptive name
* @param seq
* the RNA sequence
* @param aa
* @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);
}
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'
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();
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();
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())
{
* 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)
{
{
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);
}
}
@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.
{
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");
}
/*
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;
}
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)
{
/**
* 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;
}
}